Notifications
Clear all

[Closed] alternative to intersectRayEx

Hi guys,

I would like create an function pretty similar to intersectRayEx but with somes differences:

  • first this function does works with polys
  • the value returned would be of 4 different types:
    0 : no intersection
    1: vertex intersection
    2: edge intersection
    3: face intersection
  • an index value : face, edge or vertex index

Thanks to jman I have already an fonction to known the intersection between a plane and a ray.
Nevertheless, I currently stopped because if the poly face have more than 3 vertices, this face would not be inevitably planar. Then I should know the triangulation used internally… And I do not know how to currently recover it.

Somebody have an idea ?
What is the best means to do that ?

17 Replies
1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

A while back I wrote an (unpublished) prototype that would let you switch vertex, edge and face modes by simply hovering the mouse over the respective elements. It also highlighted the current element (face, edge or vertex) and displayed its index etc. as the mouse got close to it.
The method I used involved the RayMeshGridIntersect interface methods and some rather simple code to perform testing against the TriMesh version of the object and then figuring out the corresponding MNMesh element (vertex, edge or poly).
Generally, if you intersect against TriMesh, the face you get gives you 3 vertices. Since vertex indexing in TriMesh and MNMesh is identical, you can easily figure out what Poly Edge you are close to or what polygon the 3 vertices belong to. It is enough to get all polys used by the 3 vertices and find the common polygon that they all share…

Hope this gives you some ideas…

Bobo,

I think LFShade did something similar in CleanCut script, because it highlights edges and vertices as the mouse passes over. Although no raymeshgridinterface was used there. I little while back I posted a code snippet to cipher the nmesh polygon based on the mesh triangle exactly as you have described, and based again on LFShade’s algorithm (but streamlined), but it had a fundamental flaw in at least one case. Imagine the nmesh looks something like this (sorry for the ascii drawing, no chance to make a proper pic atm):

<code>a__________e
| \ |
| \ |
| \ |
| c |
| / |
| / |
| / |
b————d</code>

Now, if you are given the vertices a, b, c they are shared by both polygon abc and polygon acbde. How could you definitively tell which polygon the mouse was over using such a method as you have described? I had thought to find out which polygon the intersection point falls inside of, but with one (or worse, possibly two) concave polygons in the equation, it is a very difficult thing to determine. What is your solution?

<allonym>

well, that drawing didn’t come out so well:( but here is a link to the other thread with an example image in it: http://forums.cgsociety.org/showpost.php?p=2569516&postcount=12

Hi
Thanks for the ideas

bobo:
I am thinking of the problem…

allonym:
Here is an illustration of the problem with your current routine

if we search the polyFace of the meshFace in dark grey,
your current routine can’t choose between the two faces.
I do not have an good idea to solve that atm…

One step more:

fn meshFaceToPoly3 poly meshFace =
	(
	local mpolyface=meshop.getPolysUsingFace poly.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
	local mpolyfaceVerts=meshop.getVertsUsingFace poly.mesh mpolyface
	local polyfaces=polyOp.getFacesUsingVert poly mpolyfaceVerts
	local retFace
	for face in polyfaces do (
		local polyfaceVerts=polyOp.getVertsUsingFace poly face
		if ((polyfaceVerts*mpolyfaceVerts).numberset == mpolyfaceVerts.numberset) do retFace=face
		)
	retFace
	)

I have a question about objects “myPoly.mesh”

Each time I write “myPoly.mesh”, that creates a copy of the poly object in memory ?
Or this .mesh object already exists in any event ?

The myPoly.mesh seems to have all edges separated from the others.
Each face has 3 independent edges without links with the others faces.
Is that right ?

Hey here is an alternative you could build further on. This function gets vertices under the mouse. It compares the distance from the mouse to each vertex in screenspace and if the distance to the closest vertex is less than 12 pixels it returns the vertex index. It also disregards any backfacing or hidden vertices.

 fn Getmouseverts = 
(
allvc = polyop.getNumVerts $.baseobject ; if allvc != 0 then
(
backv = polyop.getVertsUsedOnlyByFaces $.baseobject (polyop.getFacesByFlag $.baseobject 8)
okv = (#{1..allvc} - backv - (polyop.getHiddenVerts $.baseobject)) as array
gw.setTransform(Matrix3 1)
mp = mouse.pos
clove = for i in okv collect 
(
m = gw.wTranspoint (polyop.getVert $.baseobject i node:$)
distance mp [m.x,m.y]
)
minitem = finditem clove (amin clove)
if clove[minitem] < 12 then okv[minitem] else undefined
)
)
Getmouseverts()

Using this you could pehaps get a few of the closest vertices, get the faces or edges of those vertices and check if the mouse is close to a certain face or edge, or if the mouse is within the shape of a polygon or lies between the two vertices of an edge.

CML

Thanx Rivendale
Interesting alternative.
In fact I don’t use the mouse with my script lol
But thanks anyway

You like mouses isn’t ?
a pic for you:

Here is my first try by using intersectRayEx on a Poly.
The main problem in this version is that intersectRayEx don’t work with myPoly.mesh… then I create a snapshot of the poly and delete it after.
I don’t know how to avoid this .
Maybe with the RayMeshGridIntersect interface ? I never used it.
Maybe that is better ? but I am off, to bed…

fn pointLineDist2 pA pB pC = (
	local vAB=pB-pA
	local vAC=pC-pA
	(length (cross vAB vAC))/(length vAB)
	)

fn getPolyfaceUsingMeshface obj meshFace = (
	local mpolyface=meshop.getPolysUsingFace obj.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
	local mpolyfaceVerts=meshop.getVertsUsingFace obj.mesh mpolyface
	local polyfaces=polyOp.getFacesUsingVert obj mpolyfaceVerts
	local retFace
	for face in polyfaces do (
		local polyfaceVerts=polyOp.getVertsUsingFace obj face
		if ((polyfaceVerts*mpolyfaceVerts).numberset==mpolyfaceVerts.numberset) do retFace=face
		)
	retFace
	)

fn isEdgeVert obj pos theEdge tol = (
	local currentVerts=polyOp.getEdgeVerts obj theEdge
	local pA=polyOp.getVert obj currentVerts[1]
	local pB=polyOp.getVert obj currentVerts[2]
	local d=pointLineDist2 pA pB pos
	if d<=tol
		then (
			local L1=distance pA pB
			local L2=distance pA pos
			local L3=distance pB pos
			if not ( L2>L1 or L3>L1 )
				then (
					if not (L2<=tol or L3<=tol)
						then return #(2,theEdge,pos)
						else (
							if L2<=tol do return #(1,currentVerts[1],pos)
							if L3<=tol do return #(1,currentVerts[2],pos)
							)
					)
				else false
			)
		else false
	)

fn findEdgeVert obj pos theEdges tol = (
	local retValue
	for thisEdge in theEdges do (
		retValue=isEdgeVert obj pos thisEdge tol
		if retValue!=false do return retValue
		)
	retValue
	)

fn intersectRayExPoly obj theRay tol = (
	local objMesh=snapshot obj
	local retArray=intersectRayEx objMesh theRay
	delete objMesh
	if retArray!=undefined
		then (
			local theFace=(getPolyfaceUsingMeshface obj retArray[2])
			local theIntersection=retArray[1].pos
			local theFaceEdges=polyOp.getEdgesUsingFace obj #{theFace}
			local retValue=findEdgeVert obj theIntersection theFaceEdges tol
			if retValue!=false then retValue else #(3,theFace,theIntersection)
			)
		else #(0,0,[0,0,0])
	)

obj=selection[1]
if classof obj==Editable_Poly do (
	theRay=ray [0,0,100] [0,0,-1]
	theInterSection=intersectRayExPoly obj theRay 0.25
	format "theInterSection=% 
" theInterSection
	)

Currently the values returned are in an array:
#( type of intersection , index , position )

type of intersection :
0 : no intersection
1: vertex intersection
2: edge intersection
3: face intersection

index: the index of the vertex, edge or face

position: the position of the ray intersection

Haha, funny image, thanks. I certainly enjoy a mouse who can entertain like that!

Here is another script: This one uses neither intersectRayEx nor RayMeshGridIntersect.
It does not convert the object either. The intersection is calculated directly in the script.

There is probably a means to optimize that. In particular we could add a test to know if the ray crosses the bounding box of the object. Currently if the ray not intersect the object the routine test all faces (and only a little number if the ray intersects the object)

struct intersectionStruct ( type=0, meshFace=0, polyFace=0, edge=0, vertex=0, point=0 )

fn isFacePoint pA pB pC pD = (
	local vAB=normalize (pB-pA)
	local vAC=normalize (pC-pA)
	local vAD=normalize (pD-pA)
	local angleBC=dot vAB vAC
	local angleBD=dot vAB vAD
	if angleBD<angleBC do return false
	local angleCD=dot vAC vAD
	if angleCD<angleBC do return false
	local vBA=-vAB
	local vBC=normalize (pC-pB)
	local vBD=normalize (pD-pB)
	local angleAC=dot vBA vBC
	local angleAD=dot vBA vBD
	if angleAD<angleAC do return false
	local angleCD=dot vBC vBD
	if angleCD<angleAC do return false
	true
	)

fn planelineintersect planePoint planeNormal vectorPoint vectorDir =		
	(
	local planeNormal=normalize planeNormal
	local vectorDir=normalize vectorDir
	local tol=.0000000754
	local vectorPoint2=vectorPoint+vectorDir
	local d1=dot (planePoint-vectorPoint) planeNormal
	local d2=dot vectorDir planeNormal
	local absd1=abs(d1), absd2=abs(d2)
	if absd2<tol and absd1>tol do return 0
	if absd1<tol and absd2<tol do return -1
	(vectorPoint+d1/d2*(vectorPoint2-vectorPoint))
	)

fn findFirstSmaller theArray theValue = (
	local theArrayCount=theArray.count
	for idx=1 to theArrayCount do (if theArray[idx]<theValue do return idx)
	0
	)--fn

fn getIntersection obj theFaces vRay vRayPos = (
	for f in theFaces do (
		local faceVerts=(meshop.getVertsUsingFace obj.mesh #{f})as array
		pA=polyOp.getVert obj faceVerts[1]
		pB=polyOp.getVert obj faceVerts[2]
		pC=polyOp.getVert obj faceVerts[3]
		local planeNormal=cross (pB-pA) (pC-pA)
		local pD=planelineintersect pA planeNormal vRayPos vRay
		if (isFacePoint pA pB pC pD) do return (intersectionStruct point:pD meshFace:f)
		)
	(intersectionStruct())
	)--fn

fn getPolyfaceUsingMeshface obj meshFace = (
	local mpolyface=meshop.getPolysUsingFace obj.mesh #{meshFace} ignoreVisEdges:false threshhold:360.0
	local mpolyfaceVerts=meshop.getVertsUsingFace obj.mesh mpolyface
	local polyfaces=polyOp.getFacesUsingVert obj mpolyfaceVerts
	local retFace
	for face in polyfaces do (
		local polyfaceVerts=polyOp.getVertsUsingFace obj face
		if ((polyfaceVerts*mpolyfaceVerts).numberset == mpolyfaceVerts.numberset) do retFace=face
		)
	retFace
	)

fn pointLineDist2 pA pB pC = (
	local vAB=pB-pA
	local vAC=pC-pA
	(length (cross vAB vAC))/(length vAB)
	)

fn isEdgeVert obj theIntersection theEdge tol = (
	local pos=theIntersection.point
	local currentVerts=polyOp.getEdgeVerts obj theEdge
	local pA=polyOp.getVert obj currentVerts[1]
	local pB=polyOp.getVert obj currentVerts[2]
	local d=pointLineDist2 pA pB pos
	if d<=tol do (
			local L1=distance pA pB
			local L2=distance pA pos
			local L3=distance pB pos
			if not ( L2>L1 or L3>L1 ) do (
					if not (L2<=tol or L3<=tol)
						then ( theIntersection.type=2; theIntersection.edge=theEdge; return theIntersection )
						else (
							if L2<=tol do ( theIntersection.type=1; theIntersection.vertex=currentVerts[1]; return theIntersection )
							if L3<=tol do ( theIntersection.type=1; theIntersection.vertex=currentVerts[2]; return theIntersection )
							)
					)
			)
	theIntersection
	)

fn findEdgeVert obj theIntersection theEdges tol = (
	local pos=theIntersection.point
	for thisEdge in theEdges do (
		isEdgeVert obj theIntersection thisEdge tol
		if (theIntersection.type==1 or theIntersection.type==2) do return theIntersection
		)
	)
fn intersectPolyRay obj theRay tol:0.000001 = (
	local tolDot=0.000001
	local vRay=-(normalize theRay.dir)
	local vRayPos=theRay.pos
	local theFaces=#{1..polyOp.getNumFaces obj}
	local theVerts=#{}
	-- face visibility test
	for f in theFaces do (
		local d=dot vRay (polyOp.getFaceNormal obj f)
		if d>tolDot do (
			local currentVerts=polyOp.getVertsUsingFace obj #{f}
			for v in currentVerts do theVerts[v]=true
			)
		)
	-- proxy vertices array
	local vertsIdxArray=#()
	local vertsDotArray=#()
	for v in theVerts do (
		local d=dot vRay ( normalize (vRayPos-(polyOp.getVert obj v)) )
		local newIdx=findFirstSmaller vertsDotArray d
		if newIdx==0
			then (append vertsDotArray d ; append vertsIdxArray v)
			else (insertItem d vertsDotArray newIdx ; insertItem v vertsIdxArray newIdx)
		)
	-- test the ray on meshFaces
	local testedFaces=#{}
	local vertexCount=1
	local vertsIdxArrayCount=vertsIdxArray.count
	local theIntersection=intersectionStruct()
	while (theIntersection.type==0 and vertexCount<=vertsIdxArrayCount) do (
		local currentFaces=meshOp.getFacesUsingVert obj.mesh #{vertsIdxArray[vertexCount]}
		currentFaces-=testedFaces
		theIntersection=getIntersection obj currentFaces vRay vRayPos
		if theIntersection.meshFace!=0 do (
			theIntersection.type=3
			theIntersection.polyFace=getPolyfaceUsingMeshface obj theIntersection.meshFace
			local theFaceEdges=polyOp.getEdgesUsingFace obj #{theIntersection.polyFace}
			findEdgeVert obj theIntersection theFaceEdges tol
			)
		testedFaces+=currentFaces
		vertexCount+=1
		)
	theIntersection
	)--fn

if (isValidNode $Plane01 and isValidNode $Point01)
	then (
		obj=$Plane01
		if classof obj==Editable_Poly then (
				r=ray $Point01.pos [0,0,-1]
				local theIntersection=intersectPolyRay obj r tol:0.25
				format "theIntersection=% 
" theIntersection
				case theIntersection.type of
					(
					1: (select obj; subobjectlevel=1; polyOp.setVertSelection obj #{theIntersection.vertex})
					2: (select obj; subobjectlevel=2; polyOp.setEdgeSelection obj #{theIntersection.edge})
					3: (select obj; subobjectlevel=4; polyOp.setFaceSelection obj #{theIntersection.polyFace})
					)
				)
			else messageBox("not an editable poly")
		)
	else messageBox("rename yours objects")
Page 1 / 2