Skip to content

Instantly share code, notes, and snippets.

@WebberHuang
Last active May 11, 2016 20:35
Show Gist options
  • Save WebberHuang/66bae81e12af97187745 to your computer and use it in GitHub Desktop.
Save WebberHuang/66bae81e12af97187745 to your computer and use it in GitHub Desktop.
find the closest edge on mesh from any position
#!/usr/bin/env python
# Author: Webber Huang
# E-mail: xracz.fx@gmail.com
# Website: http://riggingtd.com
# Purpose: Find the closest edge on mesh from any position
# Created: 2014/6/17
#========================================================================
import heapq
import maya.cmds as cmds
import maya.OpenMaya as om
########################################################################
class DistBaseVertex(object):
#----------------------------------------------------------------------
def __init__(self, idx, dist):
self._dist = dist
self._idx = idx
self._edges = set()
#----------------------------------------------------------------------
def index(self):
return self._idx
#----------------------------------------------------------------------
def addConnectedEdges(self, idx):
self._edges.add(idx)
#----------------------------------------------------------------------
def getConnectedEdges(self):
return self._edges
#----------------------------------------------------------------------
def __repr__(self):
return ("Index: %d\tDistance: %f\tConnected Edges: %s"
% (self._idx, self._dist, str(self._edges)[5:-2]))
#----------------------------------------------------------------------
def __cmp__(self, other):
""""""
assert isinstance(other, DistBaseVertex)
return cmp(self._dist, other._dist)
########################################################################
class PriorityQueue(object):
#----------------------------------------------------------------------
def __init__(self):
self._queue = []
self._count = 0
#----------------------------------------------------------------------
def push(self, item):
heapq.heappush(self._queue, item)
self._count += 1
#----------------------------------------------------------------------
def pop(self):
result = heapq.heappop(self._queue)
self._count -= 1
return result
#----------------------------------------------------------------------
def count(self):
return self._count
#----------------------------------------------------------------------
def __repr__(self):
temp = list(self._queue)
result = ""
while temp: result += "%s\n" % heapq.heappop(temp)
return result
#----------------------------------------------------------------------
def toDagPathObj(name):
sels = om.MSelectionList()
sels.add (name)
dagPath = om.MDagPath()
sels.getDagPath(0, dagPath)
return dagPath
#----------------------------------------------------------------------
def closestFaceVerticesOnMesh(mesh, position):
meshObj = toDagPathObj(mesh)
meshFn = om.MFnMesh(meshObj)
srcPt = om.MPoint(position[0], position[1], position[2])
tgtPt = om.MPoint()
util = om.MScriptUtil()
idPtr = util.asIntPtr()
meshFn.getClosestPoint(srcPt, tgtPt, om.MSpace.kWorld, idPtr)
idx = om.MScriptUtil.getInt(idPtr)
vertices = om.MIntArray()
meshFn.getPolygonVertices(idx, vertices)
return vertices
#----------------------------------------------------------------------
def closestEdgeOnMesh(mesh, position, returnId=False):
meshObj = toDagPathObj(mesh)
vtxIt = om.MItMeshVertex(meshObj)
util = om.MScriptUtil()
prevIdx = util.asIntPtr()
srcPt = om.MPoint(position[0], position[1], position[2])
pq = PriorityQueue()
# Get closest face vertices
vertices = closestFaceVerticesOnMesh(mesh, position)
# Iterate vertices, create DistBaseVertex object, push into pq
for v in vertices:
vtxIt.reset()
vtxIt.setIndex(v, prevIdx)
# Measure distance from source point to current vertex
dist = vtxIt.position(om.MSpace.kWorld).distanceTo(srcPt)
dbv = DistBaseVertex(v, dist)
# Add connected edges
edges = om.MIntArray()
vtxIt.getConnectedEdges(edges)
for e in edges: dbv.addConnectedEdges(e)
pq.push(dbv)
# Obtain closest edge by calculate the intersection of two edge sets
vtx1, vtx2= pq.pop(), pq.pop()
idx = (vtx1.getConnectedEdges() & vtx2.getConnectedEdges()).pop()
if returnId: return idx
return "%s.e[%d]" % (mesh, idx)
if __name__ == "__main__":
src, mesh = cmds.ls(sl=1)
pos = cmds.xform(src, q=1, ws=1, t=1)
e = closestEdgeOnMesh(mesh, pos, False)
cmds.select(e)
om.MGlobal.displayInfo(e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment