Skip to content

Instantly share code, notes, and snippets.

@Ravenstine
Last active December 16, 2015 22:41
Show Gist options
  • Save Ravenstine/6239234134bdfdc8d0b8 to your computer and use it in GitHub Desktop.
Save Ravenstine/6239234134bdfdc8d0b8 to your computer and use it in GitHub Desktop.
class PolyFence(list):
def __init__(self, obj_name, tolerance=0):
self.obj_name = obj_name
self.compute_convex_hull(tolerance)
def select(self):
for vertex in self:
cmds.select(vertex.obj_name, add=True)
def draw(self):
cmds.polyCreateFacet(p=[(v.x(), 0.0, v.z()) for v in self])
def vertices(self):
cmds.select(self.obj_name)
vertex_names = cmds.ls('%s.vtx[:]' % self.obj_name, fl=True)
return [Vertex(vertex_name) for vertex_name in vertex_names]
def intersects(self, polygon):
for coordinate in self:
if coordinate.within(polygon):
return True
return False
def compute_convex_hull(self, tolerance=0):
def cross(o, a, b):
return (a.x() - o.x()) * (b.z() - o.z()) - (a.z() - o.z()) * (b.x() - o.x())
def build_hull(sorted_points):
hull = []
for p in sorted_points:
while len(hull) >= 2 and cross(hull[-2], hull[-1], p) <= 0:
hull.pop()
hull.append(p)
return hull
# Sort the points lexicographically (tuples are compared lexicographically).
# Remove duplicates to detect the case we have just one unique point.
sorted_points = sorted(set(self.vertices()), key=lambda v: (v.x(), v.z()))
lower_hull = build_hull(sorted_points)
upper_hull = build_hull(reversed(sorted_points))
# Last point of each list is omitted because it is repeated at the beginning of the other list.
self += self.simplify_line(lower_hull[:-1] + upper_hull[:-1], tolerance)
def simplify_line(self, points, tolerance=0):
# square distance between 2 points
def getSqDist(p1, p2):
dx = p1.x() - p2.x()
dz = p1.z() - p2.z()
return dx * dx + dz * dz
# basic distance-based simplification
def simplifyRadialDist(points, sqTolerance):
prevPoint = points[0]
newPoints = [prevPoint]
for point in points:
if getSqDist(point, prevPoint) > sqTolerance:
newPoints.append(point)
prevPoint = point
if prevPoint != point:
newPoints.append(point)
return newPoints
if len(points) <= 2:
return points
if tolerance != None:
sqTolerance = tolerance * tolerance
else:
1
return simplifyRadialDist(points, sqTolerance)
class Vertex:
def __init__(self, obj_name):
self.obj_name = obj_name
def select(self):
cmds.select(self.obj_name)
def x(self):
return self.position()[0]
def y(self):
return self.position()[1]
def z(self):
return self.position()[2]
def position(self):
return cmds.pointPosition(self.obj_name)
def within(self, points):
x, z = (self.x(), self.z())
n = len(points)
inside = False
p1x, p1z = (points[0].x(), points[0].z())
for i in range(1, n + 1):
p2x, p2z = (points[i % n].x(), points[i % n].z())
if z > min(p1z, p2z) and z <= max(p1z, p2z) and x <= max(p1x, p2x):
if p1z != p2z:
xinters = (z - p1z) * (p2x - p1x) / (p2z - p1z) + p1x
if p1x == p2x or x <= xinters:
inside = not inside
p1x, p1z = p2x, p2z
return inside
def __getitem__(self, idx):
if idx == 0:
return self.x()
if idx == 1:
return self.z()
return None
def __repr__(self):
return "Vtx(%s, %s)" % (self.x(), self.z())
def __hash__(self):
return hash(self.__repr__())
torus_1 = cmds.polyTorus()[0]
torus_2 = cmds.polyTorus()[0]
cmds.move(0.5,0,0)
fence_1 = PolyFence(torus_1, 0.5)
fence_2 = PolyFence(torus_2)
assert(fence_1.intersects(fence_2))
cmds.move(1,0,0)
assert(fence_1.intersects(fence_2))
cmds.move(4,0,0)
assert(not fence_1.intersects(fence_2))
fence_1.draw()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment