Closet Point/Edges to locator


#1

I have a locator close to a geo. How do I make the locator snap to the closet CV on the Geo?


#2

one way might be to use the polySelectConstraint command to filter those components within a certain distance, then loop through each remaining component, finding the closest.
I imagine it’d be fairly slow though.


#3

If you meant the closest vertex on a mesh…
Create a closestPointOnMesh node.
Connect your poly.outMesh to the closestPointOnMesh.inputMesh
Connect your locator.translate to the closestPointOnMesh.inPosition
Query the position of closestPointOnMesh.closestVertexIndex.
Move your locator to this point.


string $mesh[] = `polySphere -r 1 -sx 20 -sy 20 -ax 0 1 0 -cuv 2 -ch 1`; 
string $null[] = `spaceLocator -p 0 0 0`;
// Move the locator somewhere
 move -r -0.433105 0.314959 0.946469 ;
 string $cpom = `createNode closestPointOnMesh`;
 connectAttr -f ($mesh[0] + ".outMesh") ($cpom + ".inMesh");
 connectAttr -f ($null[0] + ".translate") ($cpom + ".inPosition");
 int $closestVert = `getAttr ($cpom + ".closestVertexIndex")`;
 float $vtxPos[] = `xform -q -ws -t ($mesh[0] + ".vtx[" + $closestVert + "]")`;
 xform -ws -t $vtxPos[0] $vtxPos[1] $vtxPos[2] $null[0];
  
 I'm sure there's a better way to do that.

 If you want the closest CV on a NURBS surface, you could use the closestPointOnSurface node. This gives you a surface point, which I'm guessing is what you want to snap to. But if you do want to snap to the closest CV that is a little trickier. 

 Anybody?

#4

Are talking mel or python, and is that about NURBS or polys? Guessing from the “CV” int the question i think you are talking for NURBS. The closestPointOnSurface is a fine way for a mel approach, but as far as I know it requres the bonus tools pack, which meens an additional plug-in t be loaded. If you are familiar with python and need to snap exactly to a cv/vtx - few simple calls to the API can make it fast and easy.


#5

Sorry about the title. I need mean a vertex on a poly, but would curious to know how to do on a Nurbs also.

I write my scripts in Python, so I would love it if you get let me know how to do via a API.

For now, I would try 3d monkey method.
What is the bonus tool pack? Is that part of Maya or a additional plugin?


#6

Does it really needs to be vertices/cvs ? If so, then use python OpenMaya module. It would look somewhat like this:


 import maya.OpenMaya as om
 
 #your MFnMesh object 
 targetFn = om.MFnMesh(targetDag)
 
 #your locator position
 locPos = om.MPoint(1.2,0.4,0.2)
 
 #returned closest point
 closestPoint = om.MPoint()
 
 #returned int ptr to closest face
 mutil = om.MScriptUtil()
 intPtr = mutil.asIntPtr()
 
 
 
 #find the closest point and id
 targetFn.getClosestPoint(locPos,closestPoint,om.MSpace.kWorld,intPtr)
 
 #get the closest face		
 closestPolygonId = om.MScriptUtil(intPtr).asInt()
 
 
 #setIndex requires a ptr to previous index
 dummyPtr = mutil.asIntPtr()
 
 polyIter = om.MItMeshPolygon(targetDag)
 polyIter.setIndex(closestPolygonId,dummyPtr)
 
 #get vertices from this face
 pArray = om.MPointArray()
 vArray = om.MIntArray()
 polyIter.getPoints(pArray,om.MSpace.kWorld)
 polyIter.getVertices(vArray)
 
 #===then just compare which vertex is the closest to the locator.
 

otherwise, just use geometry constraint to get the closest point on mesh.


#7

Here it is if you want snapping just to vertices, not to closestPoint:


  import maya.OpenMaya as om
  import maya.cmds as mc
  
  def snapToClosest():
      selObj = om.MSelectionList()
      # Store active selection
      om.MGlobal.getActiveSelectionList(selObj)
      if selObj.length() < 2:
          mc.warning("Select geo and then locator")
          return
      locDag = om.MDagPath()
      meshDag = om.MDagPath()
      # extract dag paths, assuming the first selected is the mesh
      # and the second is the locator
      selObj.getDagPath(0, meshDag)
      selObj.getDagPath(1, locDag)
      locName = locDag.fullPathName()
      # get the locator position
      locT = om.MFnTransform( locDag.transform() )
      locPt = om.MPoint( locT.getTranslation(om.MSpace.kPostTransform) )
      
      # find the closest vertex
      vtxIt = om.MItMeshVertex(meshDag)
      mindist = 10000
      closestPt = om.MPoint()
      vtxId = -1
      while not vtxIt.isDone():
          vtxPt = vtxIt.position( om.MSpace.kWorld)
          dist = vtxPt.distanceTo(locPt)
          if dist < mindist:
              mindist = dist
              closestPt = vtxPt
              vtxId = vtxIt.index()
          vtxIt.next()
      print "Closest vtx: %d at %f" % (vtxId, mindist)
      mc.xform(locName, t=[closestPt.x, closestPt.y, closestPt.z], ws=1, a=1)
    
  snapToClosest()  
 

You will need to extract a dag path for your objects in order to attach an iterator to them. If you need to pass the objects by name, not as selection you can use the following routine:


selObj = om.MSelectionList()
  # Add objects by name
  selObj.add("pCube1")
  selObj.add("locator1")
  locDag = om.MDagPath()
  meshDag = om.MDagPath()
  # extract dag paths for the objects
  selObj.getDagPath(0, meshDag)
  selObj.getDagPath(1, locDag)
  # check them if you like
  meshName = meshDag.fullPathName()
  locName = locDag.fullPathName()
  # .. proceed as before
 

It’s exactly the same for NURBS surfaces ot curves, just you have to use the proper iterator class also with MItMeshEdge for example you can snap to edge centers, start/end points and so on.


#8

Thanks r4inm4ker for your help. Really appreciate it

Azrail, the script works fantastically on meshes, however when I try to use it on Nurbs surface, the locator seems to snap to the CV on the seam/isoparm

Here is the modified code


import maya.OpenMaya as om
import maya.cmds as mc

def snapToClosest():
	selObj = om.MSelectionList()
	# Store active selection
	om.MGlobal.getActiveSelectionList(selObj)
	if selObj.length() < 2:
	  mc.warning("Select geo and then locator")
	  return
	locDag = om.MDagPath()
	meshDag = om.MDagPath()
	# extract dag paths, assuming the first selected is the mesh
	# and the second is the locator
	selObj.getDagPath(0, meshDag)
	selObj.getDagPath(1, locDag)
	locName = locDag.fullPathName()
	# get the locator position
	locT = om.MFnTransform( locDag.transform() )
	locPt = om.MPoint( locT.getTranslation(om.MSpace.kPostTransform) )
	
	# find the closest vertex
	vtxIt = om.MItSurfaceCV(meshDag)	
	mindist = 10000000
	closestPt = om.MPoint()
	vtxId = -1
	while not vtxIt.isDone():
	  vtxPt = vtxIt.position( om.MSpace.kWorld)
	  dist = vtxPt.distanceTo(locPt)
	  if dist < mindist:
		  mindist = dist
		  closestPt = vtxPt
		  vtxId = vtxIt.index()
	  vtxIt.next()
	print "Closest vtx: %d at %f" % (vtxId, mindist)
	mc.xform(locName, t=[closestPt.x, closestPt.y, closestPt.z], ws=1, a=1)

snapToClosest()  


This OpenMaya module is completely new to me. Are there any good tutorial/books apart from the documentation which elaborates a bit more.


#9

The openMaya module is the python implementation of maya’s API, so the docs in maya’s help describe all of it, but you have to translate it from C++ syntax. There are few tutorials online which can help you start understanding what exactly is going on:

http://www.rtrowbridge.com/blog/2009/02/maya-api-docs-demystified-for-python-users/

As for the snapping - nurbs requre a little more specific approach, since the iteration is processed in rows:


    while not vtxIt.isDone():
            while not vtxIt.isRowDone():
                vtxPt = vtxIt.position( om.MSpace.kWorld)
                dist = vtxPt.distanceTo(locPt)
                if dist < mindist:
                    mindist = dist
                    closestPt = vtxPt
                    vtxId = vtxIt.index()
                vtxIt.next()
            vtxIt.nextRow()
   

btw it still snaps somewhere close to the surface…


#10

Please ignore question. Should have googled it

I was looking for this

http://www.vfxcreator.com/blog/2009/05/closest-point-on-curve-script.html


#11

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.