[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 ?
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")