Last active
December 16, 2015 22:41
-
-
Save Ravenstine/6239234134bdfdc8d0b8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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