add_library('hemesh')
verts = [PVector(144, 315), PVector(125, 273), PVector(134, 262), PVector(140, 276), PVector(176, 281), #05
PVector(193, 269), PVector(193, 195), PVector(203, 236), PVector(225, 236), PVector(254, 203), #10
PVector(301, 212), PVector(377, 139), PVector(417, 144), PVector(429, 200), PVector(402, 237), #15
PVector(416, 250), PVector(442, 241), PVector(434, 267), PVector(337, 368), PVector(186, 401), #20
PVector(162, 387)]
def setup():
size(600, 500)
background('#FFFFFF')
#### COMPUTE STRAIGHT SKELETON ####
#Convert vertices to WB_Points (must be in clockwise order)
polyverts = [WB_Point(p.x, p.y) for p in verts]
#Set a very large offset for each vertex (similar to a wavefront so far projected it will output the whole skeleton)
offsets = [1000] * len(verts)
#Some HE_Mesh magic trick
pyr = WB_PyramidFactory().setPoints(polyverts)
mesh = HE_Mesh(pyr.createOffset(0, offsets))
#Store Skeleton edges (just for rendering)
edges = set()
for i1, i2 in mesh.getEdgesAsInt():
v1 = mesh.getVertex(i1).getPosition()
v2 = mesh.getVertex(i2).getPosition()
#make sure to cull edges belonging to the polygonal shape (select skeleton only)
if v1 in polyverts and v2 in polyverts:
continue
edges.add((v1, v2))
#### COMPUTE MITERED OFFSETS ####
contours = []
#Retrieve inner faces of the skeleton
for i, face_id in enumerate(mesh.getFacesAsInt()):
start_index = None
face_verts = []
#Get each vertex of visited face & store them
for idx, n in enumerate(face_id):
v = mesh.getVertex(n).getPosition()
v = PVector(v.x, v.y) # convert to PVector
face_verts.append(v)
if v == verts[i]:
start_index = idx
#Re-order vertices & edges so they all start from the original polygon edges
face_verts = face_verts[start_index:] + face_verts[:start_index]
face_edges = zip(face_verts, face_verts[1:] + face_verts[:1])
#Start-point & end-point of the 1st edge
spt, ept = face_edges[0]
#Convert 1st edge to ray & offset multiple times
for gap in xrange(0, 100, 5):
dir = PVector.sub(ept, spt).normalize()
theta = dir.heading() + HALF_PI #angle perpendicular to the edge
#Offset ray parallely
vec = PVector.fromAngle(theta).setMag(gap)
p1 = spt.copy().add(dir.mult(10000.0)).add(vec) #end-pt of ray
p2 = spt.copy().add(dir.mult(-1.0)).add(vec) #start-pt of ray
#Look for intersections with the boundaries of current "inner" face
intersections = []
for p3, p4 in face_edges[1:]:
X = intersect(p1, p2, p3, p4)
if X:
intersections.append(X)
#If any, store them grouped by 2
if intersections:
it = iter(intersections)
contours.extend(zip(it, it))
#### RENDER ####
#Polygonal shape
pushStyle()
strokeWeight(3)
for v1, v2 in zip(verts, verts[1:] + verts[0:]):
line(v1.x, v1.y, v2.x, v2.y)
popStyle()
#Straight-Skeleton
for v1, v2 in edges:
line(v1.x, v1.y, v2.x, v2.y)
#Offsets
for v1, v2 in contours:
line(v1.x, v1.y, v2.x, v2.y)
noLoop()
def intersect(p1, p2, p3, p4):
'''Returns a PVector.
Checks if 2 lines are intersecting. If so, returns location of intersection point'''
uA = ((p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x)) / (((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y)) + .01)
uB = ((p2.x-p1.x)*(p1.y-p3.y) - (p2.y-p1.y)*(p1.x-p3.x)) / (((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y)) + .01)
if uA >= 0 and uA <= 1 and uB >= 0 and uB <= 1:
secX = p1.x + (uA * (p2.x-p1.x))
secY = p1.y + (uA * (p2.y-p1.y))
return PVector(secX, secY)
It works fine but I'm wondering if there's a more appropriate way (a "Hemesh" way) of finding these offsets. Is there a class or function dedicated to this task somewhere ?
Dear @wblut,
Is there a simple way to output the mitered offsets of a polygon with Hemesh ?
For the moment I'm using the following routine:
Exemple:
It works fine but I'm wondering if there's a more appropriate way (a "Hemesh" way) of finding these offsets. Is there a class or function dedicated to this task somewhere ?