def rotatePoly(poly, angle): """Rotate polygon by the given angle around the origin.""" unitX = (math.cos(angle), -math.sin(angle)) unitY = (math.sin(angle), math.cos(angle)) result = Polygon() for point in poly: result.append((numpy.dot(point, unitX), numpy.dot(point, unitY))) return result
def rotatePoly(poly, angle): """Rotate polygon by the given angle around the origin.""" unitX = (math.cos(angle), -math.sin(angle)) unitY = (math.sin(angle), math.cos(angle)) result = Polygon() for point in poly: result.append((numpy.dot(point, unitX), numpy.dot(point, unitY))) return result
def followEdge(crackConnectionImage, pos, direction): """Follow edge starting at `pos` in `direction` until crackConnectionImage[pos] has the CONN_NODE bit set, or until we arrive at `pos` again (self-loop). Any CONN_MAYBE_NODE bits along the way are cleared.""" pos = Point2D(pos[0], pos[1]) vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5) result = Polygon([vPos]) startPos = copy.copy(pos) while True: vPos += _dirVector[direction] result.append(vPos) pos += _dirOffset[direction] if pos == startPos: break connection = int(crackConnectionImage[pos]) if connection & CONN_DIAG: if connection & CONN_DIAG_UPLEFT: turnLeft = direction in (DIR_NORTH, DIR_SOUTH) else: turnLeft = direction in (DIR_EAST, DIR_WEST) connection &= ~connections[(direction + 2) % 4] if turnLeft: direction = _turnLeft[direction] else: direction = _turnRight[direction] connection &= ~connections[direction] if not connection & CONN_ALL4: connection &= ~CONN_MAYBE_NODE crackConnectionImage[pos] = connection continue elif connection & CONN_NODE: break if connection & CONN_MAYBE_NODE: # we simply pass over it, but we do not want to start a # new edge here during further down in the process: crackConnectionImage[pos] = connection & ~CONN_MAYBE_NODE direction = _turnRight[direction] while connection & connections[direction] == 0: direction = _turnLeft[direction] return result, pos, connections[(direction + 2) % 4]
def followEdge(crackConnectionImage, pos, direction): """Follow edge starting at `pos` in `direction` until crackConnectionImage[pos] has the CONN_NODE bit set, or until we arrive at `pos` again (self-loop). Any CONN_MAYBE_NODE bits along the way are cleared.""" pos = Point2D(pos[0], pos[1]) vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5) result = Polygon([vPos]) startPos = copy.copy(pos) while True: vPos += _dirVector[direction] result.append(vPos) pos += _dirOffset[direction] if pos == startPos: break connection = int(crackConnectionImage[pos]) if connection & CONN_DIAG: if connection & CONN_DIAG_UPLEFT: turnLeft = direction in (DIR_NORTH, DIR_SOUTH) else: turnLeft = direction in (DIR_EAST, DIR_WEST) connection &= ~connections[(direction+2)%4] if turnLeft: direction = _turnLeft[direction] else: direction = _turnRight[direction] connection &= ~connections[direction] if not connection & CONN_ALL4: connection &= ~CONN_MAYBE_NODE crackConnectionImage[pos] = connection continue elif connection & CONN_NODE: break if connection & CONN_MAYBE_NODE: # we simply pass over it, but we do not want to start a # new edge here during further down in the process: crackConnectionImage[pos] = connection & ~CONN_MAYBE_NODE direction = _turnRight[direction] while connection & connections[direction] == 0: direction = _turnLeft[direction] return result, pos, connections[(direction+2)%4]
def shrinkPoly(poly, offset): assert poly[0] == poly[-1], "polygon should be closed" lines = [seg.line() for seg in polyLineSegments(poly)] for line in lines: line.dist -= offset i = 1 while i < len(lines): if lines[i-1].isParallel(lines[i]): del lines[i] else: i += 1 if lines[-1].isParallel(lines[0]): del lines[-1] result = Polygon([lines[i].intersect(lines[(i+1)%len(lines)]) for i in range(len(lines))]) result.append(result[0]) return result
def shrinkPoly(poly, offset): assert poly[0] == poly[-1], "polygon should be closed" lines = [seg.line() for seg in polyLineSegments(poly)] for line in lines: line.dist -= offset i = 1 while i < len(lines): if lines[i - 1].isParallel(lines[i]): del lines[i] else: i += 1 if lines[-1].isParallel(lines[0]): del lines[-1] result = Polygon([ lines[i].intersect(lines[(i + 1) % len(lines)]) for i in range(len(lines)) ]) result.append(result[0]) return result
def _kochIteration(poly): result = Polygon() for i in range(len(poly)-1): segment = poly[i+1]-poly[i] smaller = segment/3 left = Vector2( smaller[0]*_kochCos - smaller[1]*_kochSin, smaller[0]*_kochSin + smaller[1]*_kochCos) right = Vector2( smaller[0]*_kochCos + smaller[1]*_kochSin, -smaller[0]*_kochSin + smaller[1]*_kochCos) p1 = poly[i] + smaller p2 = p1 + left p3 = p2 + right result.append(poly[i]) result.append(p1) result.append(p2) result.append(p3) result.append(result[0]) return result
def _kochIteration(poly): result = Polygon() for i in range(len(poly) - 1): segment = poly[i + 1] - poly[i] smaller = segment / 3 left = Vector2(smaller[0] * _kochCos - smaller[1] * _kochSin, smaller[0] * _kochSin + smaller[1] * _kochCos) right = Vector2(smaller[0] * _kochCos + smaller[1] * _kochSin, -smaller[0] * _kochSin + smaller[1] * _kochCos) p1 = poly[i] + smaller p2 = p1 + left p3 = p2 + right result.append(poly[i]) result.append(p1) result.append(p2) result.append(p3) result.append(result[0]) return result
def kochCurve(level = 5): result = Polygon() p0 = Vector2(-0.5, -math.sqrt(1./12)) result.append(p0) p1 = p0 + Vector2(_kochCos, _kochSin) result.append(p1) p2 = p1 + Vector2(_kochCos, -_kochSin) result.append(p2) result.append(p0) for i in range(level): result = _kochIteration(result) return result
def kochCurve(level=5): result = Polygon() p0 = Vector2(-0.5, -math.sqrt(1. / 12)) result.append(p0) p1 = p0 + Vector2(_kochCos, _kochSin) result.append(p1) p2 = p1 + Vector2(_kochCos, -_kochSin) result.append(p2) result.append(p0) for i in range(level): result = _kochIteration(result) return result
def outputMarkedShapes(delaunayMap, fe, skipInnerEdges = True, regionDepth = 50, edgeDepth = 49, capStyle = fig.CapStyle.Round, **kwargs): """IIRC, this assumes that delaunayMap contains only triangles. Contiguous thick parts of the alpha shape will be exported as single regions (as if removeInterior[Edges] had been used for alphaBetaMap or removeUnmarkedEdges, but without modifying `delaunayMap`). You may set `edgeDepth` to None to disable the output of edges. If lineWidth is not set explicitly, it then defaults to zero for faces.""" # output all cells only once: edgeOutput = [False] * delaunayMap.maxEdgeLabel() faceOutput = [False] * delaunayMap.maxFaceLabel() faceAttr = dict(kwargs) if edgeDepth is None and not "lineWidth" in kwargs: faceAttr["lineWidth"] = 0 faceAttr["depth"] = regionDepth faceAttr["fillStyle"] = fig.FillStyle.Solid faceAttr["capStyle"] = capStyle print "- exporting marked regions as filled polygons..." for triangle in delaunayMap.faceIter(skipInfinite = True): if not triangle.flag(ALPHA_MARK) or faceOutput[triangle.label()]: continue faceOutput[triangle.label()] = True contour = list(triangle.contour().phiOrbit()) i = 0 while i < len(contour): edgeOutput[contour[i].edgeLabel()] = skipInnerEdges neighbor = contour[i].rightFace() if neighbor.flag(ALPHA_MARK) and not faceOutput[neighbor.label()]: _ = contour[i].nextAlpha().nextPhi() contour.insert(i+1, contour[i].clone().nextPhi()) faceOutput[neighbor.label()] = True else: i += 1 contour = Polygon([dart[0] for dart in contour]) contour.append(contour[0]) # close poly (for filling) i = 2 while i < len(contour): if contour[i] == contour[i-2]: del contour[i-2] del contour[i-2] if i > 2: i -= 1 else: i += 1 #print " * %d points (area %s)" % (len(contour), contour.partialArea()) fe.addClippedPoly(contour, **faceAttr) if "fillColor" in kwargs: del kwargs["fillColor"] if edgeDepth != None: print "- exporting remaining marked edges (depth %d)..." % edgeDepth for edge in delaunayMap.edgeIter(): if not edge.flag(ALPHA_MARK) or edgeOutput[edge.label()]: continue dart = edge.dart() poly = Polygon(list(dart)) edgeOutput[edge.label()] = True drawing = True while drawing: drawing = False dart.nextAlpha() for next in dart.sigmaOrbit(): outputEdge = next.edge() if not outputEdge.flag(ALPHA_MARK) or edgeOutput[outputEdge.label()]: continue drawing = True assert poly[-1] == next[0] if len(outputEdge) == 2: poly.append(next[1]) else: poly.extend(Polygon(list(next)[1:])) edgeOutput[outputEdge.label()] = True dart = next break # continue in the other direction: poly.reverse() dart = edge.dart().nextAlpha() drawing = True while drawing: drawing = False dart.nextAlpha() next = dart.clone() while next.nextSigma() != dart: outputEdge = next.edge() if not outputEdge.flag(ALPHA_MARK) or edgeOutput[outputEdge.label()]: continue drawing = True assert poly[-1] == next[0] poly.append(next[1]) edgeOutput[outputEdge.label()] = True dart = next break fe.addClippedPoly( poly, depth = edgeDepth, capStyle = capStyle, **kwargs)
def outputMarkedShapes(delaunayMap, fe, skipInnerEdges=True, regionDepth=50, edgeDepth=49, capStyle=fig.CapStyle.Round, **kwargs): """IIRC, this assumes that delaunayMap contains only triangles. Contiguous thick parts of the alpha shape will be exported as single regions (as if removeInterior[Edges] had been used for alphaBetaMap or removeUnmarkedEdges, but without modifying `delaunayMap`). You may set `edgeDepth` to None to disable the output of edges. If lineWidth is not set explicitly, it then defaults to zero for faces.""" # output all cells only once: edgeOutput = [False] * delaunayMap.maxEdgeLabel() faceOutput = [False] * delaunayMap.maxFaceLabel() faceAttr = dict(kwargs) if edgeDepth is None and not "lineWidth" in kwargs: faceAttr["lineWidth"] = 0 faceAttr["depth"] = regionDepth faceAttr["fillStyle"] = fig.FillStyle.Solid faceAttr["capStyle"] = capStyle print "- exporting marked regions as filled polygons..." for triangle in delaunayMap.faceIter(skipInfinite=True): if not triangle.flag(ALPHA_MARK) or faceOutput[triangle.label()]: continue faceOutput[triangle.label()] = True contour = list(triangle.contour().phiOrbit()) i = 0 while i < len(contour): edgeOutput[contour[i].edgeLabel()] = skipInnerEdges neighbor = contour[i].rightFace() if neighbor.flag(ALPHA_MARK) and not faceOutput[neighbor.label()]: _ = contour[i].nextAlpha().nextPhi() contour.insert(i + 1, contour[i].clone().nextPhi()) faceOutput[neighbor.label()] = True else: i += 1 contour = Polygon([dart[0] for dart in contour]) contour.append(contour[0]) # close poly (for filling) i = 2 while i < len(contour): if contour[i] == contour[i - 2]: del contour[i - 2] del contour[i - 2] if i > 2: i -= 1 else: i += 1 #print " * %d points (area %s)" % (len(contour), contour.partialArea()) fe.addClippedPoly(contour, **faceAttr) if "fillColor" in kwargs: del kwargs["fillColor"] if edgeDepth != None: print "- exporting remaining marked edges (depth %d)..." % edgeDepth for edge in delaunayMap.edgeIter(): if not edge.flag(ALPHA_MARK) or edgeOutput[edge.label()]: continue dart = edge.dart() poly = Polygon(list(dart)) edgeOutput[edge.label()] = True drawing = True while drawing: drawing = False dart.nextAlpha() for next in dart.sigmaOrbit(): outputEdge = next.edge() if not outputEdge.flag(ALPHA_MARK) or edgeOutput[ outputEdge.label()]: continue drawing = True assert poly[-1] == next[0] if len(outputEdge) == 2: poly.append(next[1]) else: poly.extend(Polygon(list(next)[1:])) edgeOutput[outputEdge.label()] = True dart = next break # continue in the other direction: poly.reverse() dart = edge.dart().nextAlpha() drawing = True while drawing: drawing = False dart.nextAlpha() next = dart.clone() while next.nextSigma() != dart: outputEdge = next.edge() if not outputEdge.flag(ALPHA_MARK) or edgeOutput[ outputEdge.label()]: continue drawing = True assert poly[-1] == next[0] poly.append(next[1]) edgeOutput[outputEdge.label()] = True dart = next break fe.addClippedPoly(poly, depth=edgeDepth, capStyle=capStyle, **kwargs)
def clipPoly(polygon, clipRect, closeAtBorder = None): """clipPoly(polygon, clipRect) Clips away those parts of polygon which are not in clipRect. Returns a list of polygons (since the polygon may leave clipRect, enter again, leave, ...). Polygon segments crossing clipRect's borders are cut, such that the resulting polyons get new endpoints exactly on the border.""" result = [] # print "clipPoly(%s..%s)" % (clipRect.begin(), clipRect.end()) # print list(polygon) if closeAtBorder is None: closeAtBorder = (polygon[0] == polygon[-1]) x1, y1 = clipRect.begin() x2, y2 = clipRect.end() part = None startBorder = None parts = [] relPos = None for i, p in enumerate(polygon): prevRP = relPos relPos = 0 if p[0] < x1: relPos |= LEFT elif p[0] > x2: relPos |= RIGHT if p[1] < y1: relPos |= TOP elif p[1] > y2: relPos |= BOTTOM if relPos: # outside if not i: # incomplete first segment continue if prevRP & relPos: # complete segment outside continue # calculate leaving intersection diff = polygon[i-1] - p l = -1.0 if relPos & LEFT: l = max(l, (x1 - p[0]) / diff[0]) endBorder = LEFT if relPos & RIGHT: l = max(l, (x2 - p[0]) / diff[0]) endBorder = RIGHT if relPos & TOP: nl = (y1 - p[1]) / diff[1] if nl > l: l = nl endBorder = TOP if relPos & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl > l: l = nl endBorder = BOTTOM ip = p + l * diff if prevRP: # segment may cross cliprect, calc. start intersection pl = 2.0 if prevRP & LEFT: pl = min(pl, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: pl = min(pl, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: npl = (y1 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = TOP if prevRP & BOTTOM: npl = (y2 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = BOTTOM if pl <= l: # we never crossed the clipRect continue pip = p + pl * diff part = Polygon([pip, ip]) else: part.append(ip) if part.length(): parts.append((startBorder, part, endBorder)) part = None continue if not part: part = Polygon() if i: # calculate entering intersection: diff = polygon[i-1] - p l = 2.0 if prevRP & LEFT: l = min(l, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: l = min(l, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: nl = (y1 - p[1]) / diff[1] if nl < l: l = nl startBorder = TOP if prevRP & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl < l: l = nl startBorder = BOTTOM ip = p + l * diff part.append(ip) part.append(p) if part and part.length(): parts.append((startBorder, part, None)) if not parts: return [] if not polygon.closed(): return [p[1] for p in parts] # if polygon[0] (== polygon[-1]) is inside clipRect, we may # need to join the first and last part here: if parts[0][1][0] == parts[-1][1][-1]: assert parts[0][0] is None and parts[-1][-1] is None # polygon is entirely within clipRect: if len(parts) == 1: return [parts[0][1]] parts[-1][1].extend(parts[0][1]) parts[0] = (parts[-1][0], parts[-1][1], parts[0][2]) del parts[-1] if not closeAtBorder: return [p[1] for p in parts] # compose counterclockwise list of intersection points at clip border: sides = ( ([(-p[1][-1][0], p[1], True ) for p in parts if p[2] == TOP] + [(-p[1][ 0][0], p[1], False) for p in parts if p[0] == TOP]), ([( p[1][-1][1], p[1], True ) for p in parts if p[2] == LEFT] + [( p[1][ 0][1], p[1], False) for p in parts if p[0] == LEFT]), ([( p[1][-1][0], p[1], True ) for p in parts if p[2] == BOTTOM] + [( p[1][ 0][0], p[1], False) for p in parts if p[0] == BOTTOM]), ([(-p[1][-1][1], p[1], True ) for p in parts if p[2] == RIGHT] + [(-p[1][ 0][1], p[1], False) for p in parts if p[0] == RIGHT])) # counterclockwise list of corner positions: corners = (clipRect.begin(), clipRect.begin()+(0, clipRect.size()[1]), clipRect.end(), clipRect.begin()+(clipRect.size()[0], 0)) isCCW = polygon.partialArea() > 0 # bookkeeping about mergings (always use the most current polygon) merged = {} def mergeRoot(poly): while True: result = merged.get(poly, poly) if result is poly: break poly = result return result lastPoly = None prevPoly = None prevOutside = None for side, end in zip(sides, corners): for _, poly, outside in sorted(side): # assert outside != prevOutside; prevOutside = outside if outside == isCCW: prevPoly = poly else: if prevPoly == None: lastPoly = poly continue prevPoly = mergeRoot(prevPoly) if prevPoly == poly: poly.append(poly[0]) result.append(poly) else: prevPoly.extend(poly) merged[poly] = prevPoly prevPoly = None if prevPoly: mergeRoot(prevPoly).append(end) if lastPoly: lastPoly.append(lastPoly[0]) if lastPoly.length(): result.append(lastPoly) return result
p1 = l1 * line.dir() + l3 * line.norm p2 = l1 * line.dir() + l4 * line.norm p3 = l2 * line.dir() + l4 * line.norm p4 = l2 * line.dir() + l3 * line.norm return Polygon([p1, p2, p3, p4, p1]) # -------------------------------------------------------------------- if __name__ == "__main__": import fig f = fig.File("cliptest.fig") cr = geomap.BoundingBox((0, 0), (4500, 4500)) f.layer(1).remove() for o in f.findObjects(type = fig.PolylineBase, depth = 42): p = Polygon(o.points) if o.closed(): p.append(p[0]) pp = clipPoly(p, cr) for p in pp: no = fig.Polygon(p, p[0] == p[-1]) no.depth = 1 no.lineWidth = 3 if no.closed(): no.fillStyle = fig.FillStyle.Solid no.fillColor = f.getColor(0.5) else: no.forwardArrow = fig.Arrow() f.append(no) f.save(fig2dev = "eps")
def clipPoly(polygon, clipRect, closeAtBorder=None): """clipPoly(polygon, clipRect) Clips away those parts of polygon which are not in clipRect. Returns a list of polygons (since the polygon may leave clipRect, enter again, leave, ...). Polygon segments crossing clipRect's borders are cut, such that the resulting polyons get new endpoints exactly on the border.""" result = [] # print "clipPoly(%s..%s)" % (clipRect.begin(), clipRect.end()) # print list(polygon) if closeAtBorder is None: closeAtBorder = (polygon[0] == polygon[-1]) x1, y1 = clipRect.begin() x2, y2 = clipRect.end() part = None startBorder = None parts = [] relPos = None for i, p in enumerate(polygon): prevRP = relPos relPos = 0 if p[0] < x1: relPos |= LEFT elif p[0] > x2: relPos |= RIGHT if p[1] < y1: relPos |= TOP elif p[1] > y2: relPos |= BOTTOM if relPos: # outside if not i: # incomplete first segment continue if prevRP & relPos: # complete segment outside continue # calculate leaving intersection diff = polygon[i - 1] - p l = -1.0 if relPos & LEFT: l = max(l, (x1 - p[0]) / diff[0]) endBorder = LEFT if relPos & RIGHT: l = max(l, (x2 - p[0]) / diff[0]) endBorder = RIGHT if relPos & TOP: nl = (y1 - p[1]) / diff[1] if nl > l: l = nl endBorder = TOP if relPos & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl > l: l = nl endBorder = BOTTOM ip = p + l * diff if prevRP: # segment may cross cliprect, calc. start intersection pl = 2.0 if prevRP & LEFT: pl = min(pl, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: pl = min(pl, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: npl = (y1 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = TOP if prevRP & BOTTOM: npl = (y2 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = BOTTOM if pl <= l: # we never crossed the clipRect continue pip = p + pl * diff part = Polygon([pip, ip]) else: part.append(ip) if part.length(): parts.append((startBorder, part, endBorder)) part = None continue if not part: part = Polygon() if i: # calculate entering intersection: diff = polygon[i - 1] - p l = 2.0 if prevRP & LEFT: l = min(l, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: l = min(l, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: nl = (y1 - p[1]) / diff[1] if nl < l: l = nl startBorder = TOP if prevRP & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl < l: l = nl startBorder = BOTTOM ip = p + l * diff part.append(ip) part.append(p) if part and part.length(): parts.append((startBorder, part, None)) if not parts: return [] if not polygon.closed(): return [p[1] for p in parts] # if polygon[0] (== polygon[-1]) is inside clipRect, we may # need to join the first and last part here: if parts[0][1][0] == parts[-1][1][-1]: assert parts[0][0] is None and parts[-1][-1] is None # polygon is entirely within clipRect: if len(parts) == 1: return [parts[0][1]] parts[-1][1].extend(parts[0][1]) parts[0] = (parts[-1][0], parts[-1][1], parts[0][2]) del parts[-1] if not closeAtBorder: return [p[1] for p in parts] # compose counterclockwise list of intersection points at clip border: sides = (([(-p[1][-1][0], p[1], True) for p in parts if p[2] == TOP] + [(-p[1][0][0], p[1], False) for p in parts if p[0] == TOP]), ([(p[1][-1][1], p[1], True) for p in parts if p[2] == LEFT] + [(p[1][0][1], p[1], False) for p in parts if p[0] == LEFT]), ([(p[1][-1][0], p[1], True) for p in parts if p[2] == BOTTOM] + [(p[1][0][0], p[1], False) for p in parts if p[0] == BOTTOM]), ([(-p[1][-1][1], p[1], True) for p in parts if p[2] == RIGHT] + [(-p[1][0][1], p[1], False) for p in parts if p[0] == RIGHT])) # counterclockwise list of corner positions: corners = (clipRect.begin(), clipRect.begin() + (0, clipRect.size()[1]), clipRect.end(), clipRect.begin() + (clipRect.size()[0], 0)) isCCW = polygon.partialArea() > 0 # bookkeeping about mergings (always use the most current polygon) merged = {} def mergeRoot(poly): while True: result = merged.get(poly, poly) if result is poly: break poly = result return result lastPoly = None prevPoly = None prevOutside = None for side, end in zip(sides, corners): for _, poly, outside in sorted(side): # assert outside != prevOutside; prevOutside = outside if outside == isCCW: prevPoly = poly else: if prevPoly == None: lastPoly = poly continue prevPoly = mergeRoot(prevPoly) if prevPoly == poly: poly.append(poly[0]) result.append(poly) else: prevPoly.extend(poly) merged[poly] = prevPoly prevPoly = None if prevPoly: mergeRoot(prevPoly).append(end) if lastPoly: lastPoly.append(lastPoly[0]) if lastPoly.length(): result.append(lastPoly) return result
p1 = l1 * line.dir() + l3 * line.norm p2 = l1 * line.dir() + l4 * line.norm p3 = l2 * line.dir() + l4 * line.norm p4 = l2 * line.dir() + l3 * line.norm return Polygon([p1, p2, p3, p4, p1]) # -------------------------------------------------------------------- if __name__ == "__main__": import fig f = fig.File("cliptest.fig") cr = geomap.BoundingBox((0, 0), (4500, 4500)) f.layer(1).remove() for o in f.findObjects(type=fig.PolylineBase, depth=42): p = Polygon(o.points) if o.closed(): p.append(p[0]) pp = clipPoly(p, cr) for p in pp: no = fig.Polygon(p, p[0] == p[-1]) no.depth = 1 no.lineWidth = 3 if no.closed(): no.fillStyle = fig.FillStyle.Solid no.fillColor = f.getColor(0.5) else: no.forwardArrow = fig.Arrow() f.append(no) f.save(fig2dev="eps")