def cleanupEdges(self, edges): # want to remove all edges from the wire itself, and all internal struts PathLog.track("+cleanupEdges") PathLog.debug(" edges:") if not edges: return edges for e in edges: debugEdge(e, ' ') PathLog.debug(":") self.edgesCleanup = [copy.copy(edges)] # remove any edge that has a point inside the tag solid # and collect all edges that are connected to the entry and/or exit self.entryEdges = [] self.exitEdges = [] self.edgePoints = [] for e in copy.copy(edges): p1 = e.valueAt(e.FirstParameter) p2 = e.valueAt(e.LastParameter) self.edgePoints.append(p1) self.edgePoints.append(p2) if self.tag.solid.isInside(p1, PathGeom.Tolerance, False) or self.tag.solid.isInside(p2, PathGeom.Tolerance, False): edges.remove(e) debugEdge(e, '......... X0', False) else: if PathGeom.pointsCoincide(p1, self.entry) or PathGeom.pointsCoincide(p2, self.entry): self.entryEdges.append(e) if PathGeom.pointsCoincide(p1, self.exit) or PathGeom.pointsCoincide(p2, self.exit): self.exitEdges.append(e) self.edgesCleanup.append(copy.copy(edges)) # if there are no edges connected to entry/exit, it means the plunge in/out is vertical # we need to add in the missing segment and collect the new entry/exit edges. if not self.entryEdges: print("fill entryEdges ...") self.realEntry = sorted(self.edgePoints, key=lambda p: (p - self.entry).Length)[0] self.entryEdges = list(filter(lambda e: PathGeom.edgeConnectsTo(e, self.realEntry), edges)) edges.append(Part.Edge(Part.LineSegment(self.entry, self.realEntry))) else: self.realEntry = None if not self.exitEdges: print("fill exitEdges ...") self.realExit = sorted(self.edgePoints, key=lambda p: (p - self.exit).Length)[0] self.exitEdges = list(filter(lambda e: PathGeom.edgeConnectsTo(e, self.realExit), edges)) edges.append(Part.Edge(Part.LineSegment(self.realExit, self.exit))) else: self.realExit = None self.edgesCleanup.append(copy.copy(edges)) # if there are 2 edges attached to entry/exit, throw away the one that is "lower" if len(self.entryEdges) > 1: debugEdge(self.entryEdges[0], ' entry[0]', False) debugEdge(self.entryEdges[1], ' entry[1]', False) if self.entryEdges[0].BoundBox.ZMax < self.entryEdges[1].BoundBox.ZMax: edges.remove(self.entryEdges[0]) debugEdge(e, '......... X1', False) else: edges.remove(self.entryEdges[1]) debugEdge(e, '......... X2', False) if len(self.exitEdges) > 1: debugEdge(self.exitEdges[0], ' exit[0]', False) debugEdge(self.exitEdges[1], ' exit[1]', False) if self.exitEdges[0].BoundBox.ZMax < self.exitEdges[1].BoundBox.ZMax: if self.exitEdges[0] in edges: edges.remove(self.exitEdges[0]) debugEdge(e, '......... X3', False) else: if self.exitEdges[1] in edges: edges.remove(self.exitEdges[1]) debugEdge(e, '......... X4', False) self.edgesCleanup.append(copy.copy(edges)) return edges
def execute(self, obj): if not obj.Base or not obj.Base.isDerivedFrom('Path::Feature') or not obj.Base.Path: return tc = PathDressup.toolController(obj.Base) if len(obj.Base.Path.Commands) > 0: self.safeHeight = float(PathUtil.opProperty(obj.Base, 'SafeHeight')) self.clearanceHeight = float(PathUtil.opProperty(obj.Base, 'ClearanceHeight')) boundary = obj.Stock.Shape cmd = obj.Base.Path.Commands[0] pos = cmd.Placement.Base commands = [cmd] lastExit = None for cmd in obj.Base.Path.Commands[1:]: if cmd.Name in PathGeom.CmdMoveAll: edge = PathGeom.edgeForCmd(cmd, pos) inside = edge.common(boundary).Edges outside = edge.cut(boundary).Edges if not obj.Inside: t = inside inside = outside outside = t # it's really a shame that one cannot trust the sequence and/or # orientation of edges if 1 == len(inside) and 0 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), ' + ', cmd) # cmd fully included by boundary if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value)) lastExit = None commands.append(cmd) pos = PathGeom.commandEndPoint(cmd, pos) elif 0 == len(inside) and 1 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), ' - ', cmd) # cmd fully excluded by boundary if not lastExit: lastExit = pos pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track(_vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd) # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(ie) if ie: e = ie[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = e.valueAt(e.FirstParameter) if flip else ptL # inside edges are taken at this point (see swap of inside/outside # above - so we can just connect the dots ... if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, pos, tc.VertFeed.Value)) lastExit = None PathLog.track(e, flip) commands.extend(PathGeom.cmdsForEdge(e, flip, False)) inside.remove(e) pos = newPos lastExit = newPos else: oe = [e for e in outside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(oe) if oe: e = oe[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = e.valueAt(e.FirstParameter) if flip else ptL # outside edges are never taken at this point (see swap of # inside/oustide above) - so just move along ... outside.remove(e) pos = newPos else: PathLog.error('huh?') import Part Part.show(Part.Vertex(pos), 'pos') for e in inside: Part.show(e, 'ei') for e in outside: Part.show(e, 'eo') raise Exception('This is not supposed to happen') #pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track('no-move', cmd) commands.append(cmd) if lastExit: commands.extend(self.boundaryCommands(obj, lastExit, None, tc.VertFeed.Value)) lastExit = None else: PathLog.warning("No Path Commands for %s" % obj.Base.Label) commands = [] PathLog.track(commands) obj.Path = Path.Path(commands)
def execute(self): if ( not self.baseOp or not self.baseOp.isDerivedFrom("Path::Feature") or not self.baseOp.Path ): return None if len(self.baseOp.Path.Commands) == 0: PathLog.warning("No Path Commands for %s" % self.baseOp.Label) return [] tc = PathDressup.toolController(self.baseOp) self.safeHeight = float(PathUtil.opProperty(self.baseOp, "SafeHeight")) self.clearanceHeight = float( PathUtil.opProperty(self.baseOp, "ClearanceHeight") ) self.strG0ZsafeHeight = Path.Command( # was a Feed rate with G1 "G0", {"Z": self.safeHeight, "F": tc.VertRapid.Value} ) self.strG0ZclearanceHeight = Path.Command("G0", {"Z": self.clearanceHeight}) cmd = self.baseOp.Path.Commands[0] pos = cmd.Placement.Base # bogus m/c position to create first edge bogusX = True bogusY = True commands = [cmd] lastExit = None for cmd in self.baseOp.Path.Commands[1:]: if cmd.Name in PathGeom.CmdMoveAll: if bogusX: bogusX = "X" not in cmd.Parameters if bogusY: bogusY = "Y" not in cmd.Parameters edge = PathGeom.edgeForCmd(cmd, pos) if edge: inside = edge.common(self.boundary).Edges outside = edge.cut(self.boundary).Edges if not self.inside: # UI "inside boundary" param tmp = inside inside = outside outside = tmp # it's really a shame that one cannot trust the sequence and/or # orientation of edges if 1 == len(inside) and 0 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), " + ", cmd) # cmd fully included by boundary if lastExit: if not ( bogusX or bogusY ): # don't insert false paths based on bogus m/c position commands.extend( self.boundaryCommands( lastExit, pos, tc.VertFeed.Value ) ) lastExit = None commands.append(cmd) pos = PathGeom.commandEndPoint(cmd, pos) elif 0 == len(inside) and 1 == len(outside): PathLog.track(_vstr(pos), _vstr(lastExit), " - ", cmd) # cmd fully excluded by boundary if not lastExit: lastExit = pos pos = PathGeom.commandEndPoint(cmd, pos) else: PathLog.track( _vstr(pos), _vstr(lastExit), len(inside), len(outside), cmd ) # cmd pierces boundary while inside or outside: ie = [e for e in inside if PathGeom.edgeConnectsTo(e, pos)] PathLog.track(ie) if ie: e = ie[0] LastPt = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, LastPt) newPos = e.valueAt(e.FirstParameter) if flip else LastPt # inside edges are taken at this point (see swap of inside/outside # above - so we can just connect the dots ... if lastExit: if not (bogusX or bogusY): commands.extend( self.boundaryCommands( lastExit, pos, tc.VertFeed.Value ) ) lastExit = None PathLog.track(e, flip) if not ( bogusX or bogusY ): # don't insert false paths based on bogus m/c position commands.extend( PathGeom.cmdsForEdge( e, flip, False, 50, tc.HorizFeed.Value, tc.VertFeed.Value, ) ) inside.remove(e) pos = newPos lastExit = newPos else: oe = [ e for e in outside if PathGeom.edgeConnectsTo(e, pos) ] PathLog.track(oe) if oe: e = oe[0] ptL = e.valueAt(e.LastParameter) flip = PathGeom.pointsCoincide(pos, ptL) newPos = ( e.valueAt(e.FirstParameter) if flip else ptL ) # outside edges are never taken at this point (see swap of # inside/outside above) - so just move along ... outside.remove(e) pos = newPos else: PathLog.error("huh?") import Part Part.show(Part.Vertex(pos), "pos") for e in inside: Part.show(e, "ei") for e in outside: Part.show(e, "eo") raise Exception("This is not supposed to happen") # Eif # Eif # Ewhile # Eif # pos = PathGeom.commandEndPoint(cmd, pos) # Eif else: PathLog.track("no-move", cmd) commands.append(cmd) if lastExit: commands.extend(self.boundaryCommands(lastExit, None, tc.VertFeed.Value)) lastExit = None PathLog.track(commands) return Path.Path(commands)
def cleanupEdges(self, edges): # want to remove all edges from the wire itself, and all internal struts PathLog.track("+cleanupEdges") PathLog.debug(" edges:") if not edges: return edges for e in edges: debugEdge(e, ' ') PathLog.debug(":") self.edgesCleanup = [copy.copy(edges)] # remove any edge that has a point inside the tag solid # and collect all edges that are connected to the entry and/or exit self.entryEdges = [] self.exitEdges = [] self.edgePoints = [] for e in copy.copy(edges): p1 = e.valueAt(e.FirstParameter) p2 = e.valueAt(e.LastParameter) self.edgePoints.append(p1) self.edgePoints.append(p2) if self.tag.solid.isInside(p1, PathGeom.Tolerance, False) or self.tag.solid.isInside(p2, PathGeom.Tolerance, False): edges.remove(e) debugEdge(e, '......... X0', False) else: if PathGeom.pointsCoincide(p1, self.entry) or PathGeom.pointsCoincide(p2, self.entry): self.entryEdges.append(e) if PathGeom.pointsCoincide(p1, self.exit) or PathGeom.pointsCoincide(p2, self.exit): self.exitEdges.append(e) self.edgesCleanup.append(copy.copy(edges)) # if there are no edges connected to entry/exit, it means the plunge in/out is vertical # we need to add in the missing segment and collect the new entry/exit edges. if not self.entryEdges: print("fill entryEdges ...") self.realEntry = sorted(self.edgePoints, key=lambda p: (p - self.entry).Length)[0] self.entryEdges = filter(lambda e: PathGeom.edgeConnectsTo(e, self.realEntry), edges) edges.append(Part.Edge(Part.LineSegment(self.entry, self.realEntry))) else: self.realEntry = None if not self.exitEdges: print("fill exitEdges ...") self.realExit = sorted(self.edgePoints, key=lambda p: (p - self.exit).Length)[0] self.exitEdges = filter(lambda e: PathGeom.edgeConnectsTo(e, self.realExit), edges) edges.append(Part.Edge(Part.LineSegment(self.realExit, self.exit))) else: self.realExit = None self.edgesCleanup.append(copy.copy(edges)) # if there are 2 edges attached to entry/exit, throw away the one that is "lower" if len(self.entryEdges) > 1: debugEdge(self.entryEdges[0], ' entry[0]', False) debugEdge(self.entryEdges[1], ' entry[1]', False) if self.entryEdges[0].BoundBox.ZMax < self.entryEdges[1].BoundBox.ZMax: edges.remove(self.entryEdges[0]) debugEdge(e, '......... X1', False) else: edges.remove(self.entryEdges[1]) debugEdge(e, '......... X2', False) if len(self.exitEdges) > 1: debugEdge(self.exitEdges[0], ' exit[0]', False) debugEdge(self.exitEdges[1], ' exit[1]', False) if self.exitEdges[0].BoundBox.ZMax < self.exitEdges[1].BoundBox.ZMax: if self.exitEdges[0] in edges: edges.remove(self.exitEdges[0]) debugEdge(e, '......... X3', False) else: if self.exitEdges[1] in edges: edges.remove(self.exitEdges[1]) debugEdge(e, '......... X4', False) self.edgesCleanup.append(copy.copy(edges)) return edges