From e76333f3006d7f881be3e067de2b24f802cb4e78 Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Thu, 12 Jan 2017 17:39:23 -0800 Subject: [PATCH] Fixed segmentation of xy-plane arcs, made # segments factor a property. --- .../PathScripts/PathDressupHoldingTags.py | 27 ++++++++++++------- src/Mod/Path/PathScripts/PathGeom.py | 14 +++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py index 34908fe57..7bb01d6ca 100644 --- a/src/Mod/Path/PathScripts/PathDressupHoldingTags.py +++ b/src/Mod/Path/PathScripts/PathDressupHoldingTags.py @@ -287,21 +287,22 @@ class Tag: class MapWireToTag: - def __init__(self, edge, tag, i): + def __init__(self, edge, tag, i, segm): debugEdge(edge, 'MapWireToTag(%.2f, %.2f, %.2f)' % (i.x, i.y, i.z)) self.tag = tag + self.segm = segm if PathGeom.pointsCoincide(edge.valueAt(edge.FirstParameter), i): tail = edge self.commands = [] debugEdge(tail, '.........=') elif PathGeom.pointsCoincide(edge.valueAt(edge.LastParameter), i): debugEdge(edge, '++++++++ .') - self.commands = PathGeom.cmdsForEdge(edge) + self.commands = PathGeom.cmdsForEdge(edge, segm=segm) tail = None else: e, tail = PathGeom.splitEdgeAt(edge, i) debugEdge(e, '++++++++ .') - self.commands = PathGeom.cmdsForEdge(e) + self.commands = PathGeom.cmdsForEdge(e, segm=segm) debugEdge(tail, '.........-') self.initialEdge = edge self.tail = tail @@ -485,7 +486,7 @@ class MapWireToTag: commands = [] for e,flip in self.orderAndFlipEdges(self.cleanupEdges(shape.Edges)): debugEdge(e, '++++++++ %s' % ('<' if flip else '>'), False) - commands.extend(PathGeom.cmdsForEdge(e, flip, False)) + commands.extend(PathGeom.cmdsForEdge(e, flip, False, self.segm)) return commands return [] @@ -705,9 +706,10 @@ class ObjectDressup: obj.addProperty("App::PropertyLength", "Width", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Width of tags.")) obj.addProperty("App::PropertyLength", "Height", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Height of tags.")) obj.addProperty("App::PropertyAngle", "Angle", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Angle of tag plunge and ascent.")) - obj.addProperty("App::PropertyLength", "Radius", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Radius of the fillet on the top the tag.")) + obj.addProperty("App::PropertyLength", "Radius", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Radius of the fillet for the tag.")) obj.addProperty("App::PropertyVectorList", "Positions", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Locations of insterted holding tags")) obj.addProperty("App::PropertyIntegerList", "Disabled", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Ids of disabled holding tags")) + obj.addProperty("App::PropertyInteger", "SegmentationFactor", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Factor determining the # segments used to approximate rounded tags.")) obj.Proxy = self def __getstate__(self): @@ -738,7 +740,7 @@ class ObjectDressup: return False return True - def createPath(self, edges, tags, rapid): + def createPath(self, obj, edges, tags, rapid): #print("createPath") commands = [] lastEdge = 0 @@ -748,6 +750,13 @@ class ObjectDressup: inters = None edge = None + segm = 50 + if hasattr(obj, 'SegmentationFactor'): + segm = obj.SegmentationFactor + if segm <= 0: + segm = 50 + obj.SegmentationFactor = 50 + self.mappers = [] mapper = None @@ -773,7 +782,7 @@ class ObjectDressup: t += 1 i = tags[tIndex].intersects(edge, edge.FirstParameter) if i and self.isValidTagStartIntersection(edge, i): - mapper = MapWireToTag(edge, tags[tIndex], i) + mapper = MapWireToTag(edge, tags[tIndex], i, segm) self.mappers.append(mapper) edge = mapper.tail @@ -786,7 +795,7 @@ class ObjectDressup: v = edge.Vertexes[1] commands.append(Path.Command('G0', {'X': v.X, 'Y': v.Y, 'Z': v.Z})) else: - commands.extend(PathGeom.cmdsForEdge(edge)) + commands.extend(PathGeom.cmdsForEdge(edge, segm=segm)) edge = None t = 0 @@ -881,7 +890,7 @@ class ObjectDressup: #else: # debugCylinder(tag.originAt(self.pathData.minZ), tag.fullWidth()/2, tag.actualHeight, "tag-%02d" % tagID) - obj.Path = self.createPath(self.pathData.edges, self.tags, self.pathData.rapid) + obj.Path = self.createPath(obj, self.pathData.edges, self.tags, self.pathData.rapid) #print("execute - done") def setup(self, obj, generate=False): diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index ed8539873..b78bd7f45 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -145,15 +145,15 @@ class PathGeom: return Vector(point.x, point.y, 0) @classmethod - def cmdsForEdge(cls, edge, flip = False, useHelixForBSpline = True): - """(edge, flip = False, useHelixForBSpline = True) -> List(Path.Command) + def cmdsForEdge(cls, edge, flip = False, useHelixForBSpline = True, segm = 50): + """(edge, flip=False, useHelixForBSpline=True, segm=50) -> List(Path.Command) Returns a list of Path.Command representing the given edge. If flip is True the edge is considered to be backwards. If useHelixForBSpline is True an Edge based on a BSplineCurve is considered to represent a helix and results in G2 or G3 command. Otherwise edge has no direct Path.Command mapping and will be approximated by straight segments. - Approximation is also the approach for edges that are neither straight lines - nor arcs (nor helixes).""" + segm is a factor for the segmentation of arbitrary curves not mapped to G1/2/3 + commands. The higher the value the more segments will be used.""" pt = edge.valueAt(edge.LastParameter) if not flip else edge.valueAt(edge.FirstParameter) params = {'X': pt.x, 'Y': pt.y, 'Z': pt.z} if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment: @@ -166,12 +166,12 @@ class PathGeom: p1 = pt p3 = edge.valueAt(edge.LastParameter) p2 = edge.valueAt((edge.FirstParameter + edge.LastParameter)/2) - if (type(edge.Curve) == Part.Circle and cls.pointsCoincide(edge.Curve.Axis, Vector(0, 0, 1))) or (useHelixForBSpline and type(edge.Curve) == Part.BSplineCurve): + if (type(edge.Curve) == Part.Circle and cls.isRoughly(edge.Curve.Axis.x, 0) and cls.isRoughly(edge.Curve.Axis.y, 0)) or (useHelixForBSpline and type(edge.Curve) == Part.BSplineCurve): if Side.Left == Side.of(p2 - p1, p3 - p2): cmd = 'G3' else: cmd = 'G2' - print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z)) + #print("**** (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)" % (p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z)) pd = Part.Circle(PathGeom.xy(p1), PathGeom.xy(p2), PathGeom.xy(p3)).Center pa = PathGeom.xy(p1) @@ -191,7 +191,7 @@ class PathGeom: return [ Path.Command('G1', {'X': p3.x, 'Y': p3.y, 'Z': p3.z}) ] # at this point pixellation is all we can do commands = [] - segments = int(math.ceil((deviation / eStraight.Length) * 1000)) + segments = int(math.ceil((deviation / eStraight.Length) * segm)) #print("**** pixellation with %d segments" % segments) dParameter = (edge.LastParameter - edge.FirstParameter) / segments for i in range(0, segments):