From bb18dd9a914e94dcaa409f9b86d14124ebc6aa4b Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 00:33:25 +0100 Subject: [PATCH 1/8] [PATH] Added basic support for arcs in deburr op --- src/Mod/Path/PathScripts/PathDeburr.py | 56 ++++++++++++++++++++--- src/Mod/Path/PathScripts/PathDeburrGui.py | 14 +++--- src/Mod/Path/PathScripts/PathOpTools.py | 22 +++++++++ src/Mod/Path/PathScripts/PathSelection.py | 3 +- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index ba530dc366..c540811765 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2018 sliptonic * -# * Copyright (c) 2020 Schildkroet * +# * Copyright (c) 2020-2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -93,7 +93,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): '''Proxy class for Deburr operation.''' def opFeatures(self, obj): - return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant + return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant | PathOp.FeatureBaseGeometry def initOperation(self, obj): PathLog.track(obj.Label) @@ -139,14 +139,59 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): for base, subs in obj.Base: edges = [] basewires = [] + max_h = -99999 + for f in subs: sub = base.Shape.getElement(f) - if type(sub) == Part.Edge: + + if type(sub) == Part.Edge: # Edge edges.append(sub) + + elif type(sub) == Part.Face and sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): # Angled face + # Find z value of upper edge + for edge in sub.Edges: + for p0 in edge.Vertexes: + if p0.Point.z > max_h: + max_h = p0.Point.z + + # Search for lower edge and raise it to height of upper edge + for edge in sub.Edges: + if Part.Circle == type(edge.Curve): # Edge is a circle + if edge.Vertexes[0].Point.z < max_h: + + if edge.Closed: # Circle + v = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + new_edge = Part.makeCircle(edge.Curve.Radius, v, FreeCAD.Vector(0, 0, 1)) + edges.append(new_edge) + break + else: # Arc + if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z: + l1 = math.sqrt((edge.Vertexes[0].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[0].Point.y - edge.Curve.Center.y)**2) + l2 = math.sqrt((edge.Vertexes[1].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[1].Point.y - edge.Curve.Center.y)**2) + + start_angle = math.acos((edge.Vertexes[0].Point.x - edge.Curve.Center.x) / l1) + end_angle = math.acos((edge.Vertexes[1].Point.x - edge.Curve.Center.x) / l2) + + if edge.Vertexes[0].Point.y < edge.Curve.Center.y: + start_angle *= -1 + if edge.Vertexes[1].Point.y < edge.Curve.Center.y: + end_angle *= -1 + + edge = Part.ArcOfCircle(Part.Circle(edge.Curve.Center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + break + + else: # Line + if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z and edge.Vertexes[0].Point.z < max_h: + new_edge = Part.Edge(Part.LineSegment(FreeCAD.Vector(edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, max_h), FreeCAD.Vector(edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y, max_h))) + edges.append(new_edge) + + elif sub.Wires: basewires.extend(sub.Wires) - else: + + else: # Flat face basewires.append(Part.Wire(sub.Edges)) + self.edges = edges # pylint: disable=attribute-defined-outside-init for edgelist in Part.sortEdges(edges): basewires.append(Part.Wire(edgelist)) @@ -160,9 +205,6 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if wire: wires.append(wire) - # # Save Outside or Inside - # obj.Side = side[0] - # Set direction of op forward = (obj.Direction == 'CW') diff --git a/src/Mod/Path/PathScripts/PathDeburrGui.py b/src/Mod/Path/PathScripts/PathDeburrGui.py index d98642f4dd..1d4e0d8bf3 100644 --- a/src/Mod/Path/PathScripts/PathDeburrGui.py +++ b/src/Mod/Path/PathScripts/PathDeburrGui.py @@ -55,14 +55,14 @@ class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage): return super(TaskPanelBaseGeometryPage, self) def addBaseGeometry(self, selection): - for sel in selection: - if sel.HasSubObjects: + #for sel in selection: + #if sel.HasSubObjects: # selectively add some elements of the drawing to the Base - for sub in sel.SubObjects: - if isinstance(sub, Part.Face): - if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): - PathLog.info(translate("Path", "Ignoring non-horizontal Face")) - return + #for sub in sel.SubObjects: + # if isinstance(sub, Part.Face): + # if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): + # PathLog.info(translate("Path", "Ignoring non-horizontal Face")) + # return self.super().addBaseGeometry(selection) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 5bdb3a9ba4..862710bca5 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -166,6 +166,28 @@ def offsetWire(wire, base, offset, forward):#, Side = None): edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) w = Part.Wire([edge]) return w + + if Part.Circle == type(curve) and not wire.isClosed(): + # Process arc segment + z = -1 if forward else 1 + l1 = math.sqrt((edge.Vertexes[0].Point.x - curve.Center.x)**2 + (edge.Vertexes[0].Point.y - curve.Center.y)**2) + l2 = math.sqrt((edge.Vertexes[1].Point.x - curve.Center.x)**2 + (edge.Vertexes[1].Point.y - curve.Center.y)**2) + + start_angle = math.acos((edge.Vertexes[0].Point.x - curve.Center.x) / l1) + end_angle = math.acos((edge.Vertexes[1].Point.x - curve.Center.x) / l2) + + if edge.Vertexes[0].Point.y < curve.Center.y: + start_angle *= -1 + if edge.Vertexes[1].Point.y < curve.Center.y: + end_angle *= -1 + + if base.isInside(edge.Vertexes[0].Point, offset/2, True): + offset *= -1 + + edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() + + return Part.Wire([edge]) + if Part.Line == type(curve) or Part.LineSegment == type(curve): # offsetting a single edge doesn't work because there is an infinite # possible planes into which the edge could be offset diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index 055bfb1757..8f0725407b 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2015 Dan Falck * +# * Copyright (c) 2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -115,7 +116,7 @@ class CHAMFERGate(PathBaseGate): subShape = shape.getElement(sub) if subShape.ShapeType == 'Edge': return True - elif (subShape.ShapeType == 'Face' and subShape.normalAt(0, 0) == FreeCAD.Vector(0, 0, 1)): + elif (subShape.ShapeType == 'Face'): return True return False From d1d1478063dd0a7d29141e4601d04eca76898f8a Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 15:41:37 +0100 Subject: [PATCH 2/8] [PATH] Improved deburr --- src/Mod/Path/PathScripts/PathDeburr.py | 50 ++++++++++++++++++++--- src/Mod/Path/PathScripts/PathDeburrGui.py | 9 ---- src/Mod/Path/PathScripts/PathOpTools.py | 16 +++++--- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index c540811765..2dac9b36e3 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -86,7 +86,7 @@ def toolDepthAndOffset(width, extraDepth, tool, printInfo): extraOffset = -width if angle == 180 else (extraDepth / tan) offset = toolOffset + extraOffset - return (depth, offset, suppressInfo) + return (depth, offset, extraOffset, suppressInfo) class ObjectDeburr(PathEngraveBase.ObjectOp): @@ -123,7 +123,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if not hasattr(self, 'printInfo'): self.printInfo = True try: - (depth, offset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo) + (depth, offset, extraOffset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo) self.printInfo = not suppressInfo except ValueError as e: msg = "{} \n No path will be generated".format(e) @@ -136,10 +136,13 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): self.basewires = [] # pylint: disable=attribute-defined-outside-init self.adjusted_basewires = [] # pylint: disable=attribute-defined-outside-init wires = [] + for base, subs in obj.Base: edges = [] basewires = [] max_h = -99999 + radius_top = 0 + radius_bottom = 0 for f in subs: sub = base.Shape.getElement(f) @@ -148,11 +151,24 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): edges.append(sub) elif type(sub) == Part.Face and sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): # Angled face + # If an angled face is selected, the lower edge is projected to the height of the upper edge, + # to simulate an edge + # Find z value of upper edge for edge in sub.Edges: for p0 in edge.Vertexes: if p0.Point.z > max_h: max_h = p0.Point.z + + # Find biggest radius for top/bottom + for edge in sub.Edges: + if Part.Circle == type(edge.Curve): + if edge.Vertexes[0].Point.z == max_h: + if edge.Curve.Radius > radius_top: + radius_top = edge.Curve.Radius + else: + if edge.Curve.Radius > radius_bottom: + radius_bottom = edge.Curve.Radius # Search for lower edge and raise it to height of upper edge for edge in sub.Edges: @@ -160,24 +176,44 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if edge.Vertexes[0].Point.z < max_h: if edge.Closed: # Circle - v = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) - new_edge = Part.makeCircle(edge.Curve.Radius, v, FreeCAD.Vector(0, 0, 1)) + # New center + center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + new_edge = Part.makeCircle(edge.Curve.Radius, center, FreeCAD.Vector(0, 0, 1)) edges.append(new_edge) + + # Modify offset for inner angled faces + if radius_bottom < radius_top: + offset -= 2 * extraOffset + break + else: # Arc if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z: + # Arc vertexes are on same layer l1 = math.sqrt((edge.Vertexes[0].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[0].Point.y - edge.Curve.Center.y)**2) l2 = math.sqrt((edge.Vertexes[1].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[1].Point.y - edge.Curve.Center.y)**2) + # New center + center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + + # Calculate angles based on x-axis (0 - PI/2) start_angle = math.acos((edge.Vertexes[0].Point.x - edge.Curve.Center.x) / l1) end_angle = math.acos((edge.Vertexes[1].Point.x - edge.Curve.Center.x) / l2) + # Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle if edge.Vertexes[0].Point.y < edge.Curve.Center.y: start_angle *= -1 if edge.Vertexes[1].Point.y < edge.Curve.Center.y: end_angle *= -1 - edge = Part.ArcOfCircle(Part.Circle(edge.Curve.Center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + # Create new arc + new_edge = Part.ArcOfCircle(Part.Circle(center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + edges.append(new_edge) + + # Modify offset for inner angled faces + if radius_bottom < radius_top: + offset -= 2 * extraOffset + break else: # Line @@ -201,7 +237,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): for w in basewires: self.adjusted_basewires.append(w) - wire = PathOpTools.offsetWire(w, base.Shape, offset, True) #, obj.Side) + wire = PathOpTools.offsetWire(w, base.Shape, offset, True) if wire: wires.append(wire) @@ -214,6 +250,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): while z + obj.StepDown.Value < depth: z = z + obj.StepDown.Value zValues.append(z) + zValues.append(depth) PathLog.track(obj.Label, depth, zValues) @@ -250,5 +287,6 @@ def Create(name, obj=None): '''Create(name) ... Creates and returns a Deburr operation.''' if obj is None: obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + obj.Proxy = ObjectDeburr(obj, name) return obj diff --git a/src/Mod/Path/PathScripts/PathDeburrGui.py b/src/Mod/Path/PathScripts/PathDeburrGui.py index 1d4e0d8bf3..76e5f405e6 100644 --- a/src/Mod/Path/PathScripts/PathDeburrGui.py +++ b/src/Mod/Path/PathScripts/PathDeburrGui.py @@ -55,15 +55,6 @@ class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage): return super(TaskPanelBaseGeometryPage, self) def addBaseGeometry(self, selection): - #for sel in selection: - #if sel.HasSubObjects: - # selectively add some elements of the drawing to the Base - #for sub in sel.SubObjects: - # if isinstance(sub, Part.Face): - # if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): - # PathLog.info(translate("Path", "Ignoring non-horizontal Face")) - # return - self.super().addBaseGeometry(selection) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 862710bca5..de7c2e19fb 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -143,7 +143,7 @@ def orientWire(w, forward=True): PathLog.track('orientWire - ok') return wire -def offsetWire(wire, base, offset, forward):#, Side = None): +def offsetWire(wire, base, offset, forward): '''offsetWire(wire, base, offset, forward) ... offsets the wire away from base and orients the wire accordingly. The function tries to avoid most of the pitfalls of Part.makeOffset2D which is possible because all offsetting happens in the XY plane. @@ -158,14 +158,14 @@ def offsetWire(wire, base, offset, forward):#, Side = None): # https://www.freecadweb.org/wiki/Part%20Offset2D # it's easy to construct them manually though z = -1 if forward else 1 - edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z)) - if base.isInside(edge.Vertexes[0].Point, offset/2, True): + new_edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z)) + if base.isInside(new_edge.Vertexes[0].Point, offset/2, True): if offset > curve.Radius or PathGeom.isRoughly(offset, curve.Radius): # offsetting a hole by its own radius (or more) makes the hole vanish return None - edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) - w = Part.Wire([edge]) - return w + new_edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) + + return Part.Wire([new_edge]) if Part.Circle == type(curve) and not wire.isClosed(): # Process arc segment @@ -173,17 +173,21 @@ def offsetWire(wire, base, offset, forward):#, Side = None): l1 = math.sqrt((edge.Vertexes[0].Point.x - curve.Center.x)**2 + (edge.Vertexes[0].Point.y - curve.Center.y)**2) l2 = math.sqrt((edge.Vertexes[1].Point.x - curve.Center.x)**2 + (edge.Vertexes[1].Point.y - curve.Center.y)**2) + # Calculate angles based on x-axis (0 - PI/2) start_angle = math.acos((edge.Vertexes[0].Point.x - curve.Center.x) / l1) end_angle = math.acos((edge.Vertexes[1].Point.x - curve.Center.x) / l2) + # Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle if edge.Vertexes[0].Point.y < curve.Center.y: start_angle *= -1 if edge.Vertexes[1].Point.y < curve.Center.y: end_angle *= -1 + # Inside / Outside if base.isInside(edge.Vertexes[0].Point, offset/2, True): offset *= -1 + # Create new arc edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() return Part.Wire([edge]) From 9266d0a1c2f5f8f8d351c4c285092beda059c30d Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 00:33:25 +0100 Subject: [PATCH 3/8] [PATH] Added basic support for arcs in deburr op --- src/Mod/Path/PathScripts/PathDeburr.py | 56 ++++++++++++++++++++--- src/Mod/Path/PathScripts/PathDeburrGui.py | 14 +++--- src/Mod/Path/PathScripts/PathOpTools.py | 22 +++++++++ src/Mod/Path/PathScripts/PathSelection.py | 3 +- 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index ba530dc366..c540811765 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2018 sliptonic * -# * Copyright (c) 2020 Schildkroet * +# * Copyright (c) 2020-2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -93,7 +93,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): '''Proxy class for Deburr operation.''' def opFeatures(self, obj): - return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant + return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant | PathOp.FeatureBaseGeometry def initOperation(self, obj): PathLog.track(obj.Label) @@ -139,14 +139,59 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): for base, subs in obj.Base: edges = [] basewires = [] + max_h = -99999 + for f in subs: sub = base.Shape.getElement(f) - if type(sub) == Part.Edge: + + if type(sub) == Part.Edge: # Edge edges.append(sub) + + elif type(sub) == Part.Face and sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): # Angled face + # Find z value of upper edge + for edge in sub.Edges: + for p0 in edge.Vertexes: + if p0.Point.z > max_h: + max_h = p0.Point.z + + # Search for lower edge and raise it to height of upper edge + for edge in sub.Edges: + if Part.Circle == type(edge.Curve): # Edge is a circle + if edge.Vertexes[0].Point.z < max_h: + + if edge.Closed: # Circle + v = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + new_edge = Part.makeCircle(edge.Curve.Radius, v, FreeCAD.Vector(0, 0, 1)) + edges.append(new_edge) + break + else: # Arc + if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z: + l1 = math.sqrt((edge.Vertexes[0].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[0].Point.y - edge.Curve.Center.y)**2) + l2 = math.sqrt((edge.Vertexes[1].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[1].Point.y - edge.Curve.Center.y)**2) + + start_angle = math.acos((edge.Vertexes[0].Point.x - edge.Curve.Center.x) / l1) + end_angle = math.acos((edge.Vertexes[1].Point.x - edge.Curve.Center.x) / l2) + + if edge.Vertexes[0].Point.y < edge.Curve.Center.y: + start_angle *= -1 + if edge.Vertexes[1].Point.y < edge.Curve.Center.y: + end_angle *= -1 + + edge = Part.ArcOfCircle(Part.Circle(edge.Curve.Center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + break + + else: # Line + if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z and edge.Vertexes[0].Point.z < max_h: + new_edge = Part.Edge(Part.LineSegment(FreeCAD.Vector(edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, max_h), FreeCAD.Vector(edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y, max_h))) + edges.append(new_edge) + + elif sub.Wires: basewires.extend(sub.Wires) - else: + + else: # Flat face basewires.append(Part.Wire(sub.Edges)) + self.edges = edges # pylint: disable=attribute-defined-outside-init for edgelist in Part.sortEdges(edges): basewires.append(Part.Wire(edgelist)) @@ -160,9 +205,6 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if wire: wires.append(wire) - # # Save Outside or Inside - # obj.Side = side[0] - # Set direction of op forward = (obj.Direction == 'CW') diff --git a/src/Mod/Path/PathScripts/PathDeburrGui.py b/src/Mod/Path/PathScripts/PathDeburrGui.py index d98642f4dd..1d4e0d8bf3 100644 --- a/src/Mod/Path/PathScripts/PathDeburrGui.py +++ b/src/Mod/Path/PathScripts/PathDeburrGui.py @@ -55,14 +55,14 @@ class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage): return super(TaskPanelBaseGeometryPage, self) def addBaseGeometry(self, selection): - for sel in selection: - if sel.HasSubObjects: + #for sel in selection: + #if sel.HasSubObjects: # selectively add some elements of the drawing to the Base - for sub in sel.SubObjects: - if isinstance(sub, Part.Face): - if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): - PathLog.info(translate("Path", "Ignoring non-horizontal Face")) - return + #for sub in sel.SubObjects: + # if isinstance(sub, Part.Face): + # if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): + # PathLog.info(translate("Path", "Ignoring non-horizontal Face")) + # return self.super().addBaseGeometry(selection) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 5bdb3a9ba4..862710bca5 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -166,6 +166,28 @@ def offsetWire(wire, base, offset, forward):#, Side = None): edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) w = Part.Wire([edge]) return w + + if Part.Circle == type(curve) and not wire.isClosed(): + # Process arc segment + z = -1 if forward else 1 + l1 = math.sqrt((edge.Vertexes[0].Point.x - curve.Center.x)**2 + (edge.Vertexes[0].Point.y - curve.Center.y)**2) + l2 = math.sqrt((edge.Vertexes[1].Point.x - curve.Center.x)**2 + (edge.Vertexes[1].Point.y - curve.Center.y)**2) + + start_angle = math.acos((edge.Vertexes[0].Point.x - curve.Center.x) / l1) + end_angle = math.acos((edge.Vertexes[1].Point.x - curve.Center.x) / l2) + + if edge.Vertexes[0].Point.y < curve.Center.y: + start_angle *= -1 + if edge.Vertexes[1].Point.y < curve.Center.y: + end_angle *= -1 + + if base.isInside(edge.Vertexes[0].Point, offset/2, True): + offset *= -1 + + edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() + + return Part.Wire([edge]) + if Part.Line == type(curve) or Part.LineSegment == type(curve): # offsetting a single edge doesn't work because there is an infinite # possible planes into which the edge could be offset diff --git a/src/Mod/Path/PathScripts/PathSelection.py b/src/Mod/Path/PathScripts/PathSelection.py index 055bfb1757..8f0725407b 100644 --- a/src/Mod/Path/PathScripts/PathSelection.py +++ b/src/Mod/Path/PathScripts/PathSelection.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2015 Dan Falck * +# * Copyright (c) 2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -115,7 +116,7 @@ class CHAMFERGate(PathBaseGate): subShape = shape.getElement(sub) if subShape.ShapeType == 'Edge': return True - elif (subShape.ShapeType == 'Face' and subShape.normalAt(0, 0) == FreeCAD.Vector(0, 0, 1)): + elif (subShape.ShapeType == 'Face'): return True return False From d6a82ec73132aac55ba9e5aef448506745d92ca0 Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 15:41:37 +0100 Subject: [PATCH 4/8] [PATH] Improved deburr --- src/Mod/Path/PathScripts/PathDeburr.py | 50 ++++++++++++++++++++--- src/Mod/Path/PathScripts/PathDeburrGui.py | 9 ---- src/Mod/Path/PathScripts/PathOpTools.py | 16 +++++--- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index c540811765..2dac9b36e3 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -86,7 +86,7 @@ def toolDepthAndOffset(width, extraDepth, tool, printInfo): extraOffset = -width if angle == 180 else (extraDepth / tan) offset = toolOffset + extraOffset - return (depth, offset, suppressInfo) + return (depth, offset, extraOffset, suppressInfo) class ObjectDeburr(PathEngraveBase.ObjectOp): @@ -123,7 +123,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if not hasattr(self, 'printInfo'): self.printInfo = True try: - (depth, offset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo) + (depth, offset, extraOffset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo) self.printInfo = not suppressInfo except ValueError as e: msg = "{} \n No path will be generated".format(e) @@ -136,10 +136,13 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): self.basewires = [] # pylint: disable=attribute-defined-outside-init self.adjusted_basewires = [] # pylint: disable=attribute-defined-outside-init wires = [] + for base, subs in obj.Base: edges = [] basewires = [] max_h = -99999 + radius_top = 0 + radius_bottom = 0 for f in subs: sub = base.Shape.getElement(f) @@ -148,11 +151,24 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): edges.append(sub) elif type(sub) == Part.Face and sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): # Angled face + # If an angled face is selected, the lower edge is projected to the height of the upper edge, + # to simulate an edge + # Find z value of upper edge for edge in sub.Edges: for p0 in edge.Vertexes: if p0.Point.z > max_h: max_h = p0.Point.z + + # Find biggest radius for top/bottom + for edge in sub.Edges: + if Part.Circle == type(edge.Curve): + if edge.Vertexes[0].Point.z == max_h: + if edge.Curve.Radius > radius_top: + radius_top = edge.Curve.Radius + else: + if edge.Curve.Radius > radius_bottom: + radius_bottom = edge.Curve.Radius # Search for lower edge and raise it to height of upper edge for edge in sub.Edges: @@ -160,24 +176,44 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): if edge.Vertexes[0].Point.z < max_h: if edge.Closed: # Circle - v = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) - new_edge = Part.makeCircle(edge.Curve.Radius, v, FreeCAD.Vector(0, 0, 1)) + # New center + center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + new_edge = Part.makeCircle(edge.Curve.Radius, center, FreeCAD.Vector(0, 0, 1)) edges.append(new_edge) + + # Modify offset for inner angled faces + if radius_bottom < radius_top: + offset -= 2 * extraOffset + break + else: # Arc if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z: + # Arc vertexes are on same layer l1 = math.sqrt((edge.Vertexes[0].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[0].Point.y - edge.Curve.Center.y)**2) l2 = math.sqrt((edge.Vertexes[1].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[1].Point.y - edge.Curve.Center.y)**2) + # New center + center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h) + + # Calculate angles based on x-axis (0 - PI/2) start_angle = math.acos((edge.Vertexes[0].Point.x - edge.Curve.Center.x) / l1) end_angle = math.acos((edge.Vertexes[1].Point.x - edge.Curve.Center.x) / l2) + # Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle if edge.Vertexes[0].Point.y < edge.Curve.Center.y: start_angle *= -1 if edge.Vertexes[1].Point.y < edge.Curve.Center.y: end_angle *= -1 - edge = Part.ArcOfCircle(Part.Circle(edge.Curve.Center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + # Create new arc + new_edge = Part.ArcOfCircle(Part.Circle(center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape() + edges.append(new_edge) + + # Modify offset for inner angled faces + if radius_bottom < radius_top: + offset -= 2 * extraOffset + break else: # Line @@ -201,7 +237,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): for w in basewires: self.adjusted_basewires.append(w) - wire = PathOpTools.offsetWire(w, base.Shape, offset, True) #, obj.Side) + wire = PathOpTools.offsetWire(w, base.Shape, offset, True) if wire: wires.append(wire) @@ -214,6 +250,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): while z + obj.StepDown.Value < depth: z = z + obj.StepDown.Value zValues.append(z) + zValues.append(depth) PathLog.track(obj.Label, depth, zValues) @@ -250,5 +287,6 @@ def Create(name, obj=None): '''Create(name) ... Creates and returns a Deburr operation.''' if obj is None: obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name) + obj.Proxy = ObjectDeburr(obj, name) return obj diff --git a/src/Mod/Path/PathScripts/PathDeburrGui.py b/src/Mod/Path/PathScripts/PathDeburrGui.py index 1d4e0d8bf3..76e5f405e6 100644 --- a/src/Mod/Path/PathScripts/PathDeburrGui.py +++ b/src/Mod/Path/PathScripts/PathDeburrGui.py @@ -55,15 +55,6 @@ class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage): return super(TaskPanelBaseGeometryPage, self) def addBaseGeometry(self, selection): - #for sel in selection: - #if sel.HasSubObjects: - # selectively add some elements of the drawing to the Base - #for sub in sel.SubObjects: - # if isinstance(sub, Part.Face): - # if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): - # PathLog.info(translate("Path", "Ignoring non-horizontal Face")) - # return - self.super().addBaseGeometry(selection) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 862710bca5..de7c2e19fb 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -143,7 +143,7 @@ def orientWire(w, forward=True): PathLog.track('orientWire - ok') return wire -def offsetWire(wire, base, offset, forward):#, Side = None): +def offsetWire(wire, base, offset, forward): '''offsetWire(wire, base, offset, forward) ... offsets the wire away from base and orients the wire accordingly. The function tries to avoid most of the pitfalls of Part.makeOffset2D which is possible because all offsetting happens in the XY plane. @@ -158,14 +158,14 @@ def offsetWire(wire, base, offset, forward):#, Side = None): # https://www.freecadweb.org/wiki/Part%20Offset2D # it's easy to construct them manually though z = -1 if forward else 1 - edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z)) - if base.isInside(edge.Vertexes[0].Point, offset/2, True): + new_edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z)) + if base.isInside(new_edge.Vertexes[0].Point, offset/2, True): if offset > curve.Radius or PathGeom.isRoughly(offset, curve.Radius): # offsetting a hole by its own radius (or more) makes the hole vanish return None - edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) - w = Part.Wire([edge]) - return w + new_edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) + + return Part.Wire([new_edge]) if Part.Circle == type(curve) and not wire.isClosed(): # Process arc segment @@ -173,17 +173,21 @@ def offsetWire(wire, base, offset, forward):#, Side = None): l1 = math.sqrt((edge.Vertexes[0].Point.x - curve.Center.x)**2 + (edge.Vertexes[0].Point.y - curve.Center.y)**2) l2 = math.sqrt((edge.Vertexes[1].Point.x - curve.Center.x)**2 + (edge.Vertexes[1].Point.y - curve.Center.y)**2) + # Calculate angles based on x-axis (0 - PI/2) start_angle = math.acos((edge.Vertexes[0].Point.x - curve.Center.x) / l1) end_angle = math.acos((edge.Vertexes[1].Point.x - curve.Center.x) / l2) + # Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle if edge.Vertexes[0].Point.y < curve.Center.y: start_angle *= -1 if edge.Vertexes[1].Point.y < curve.Center.y: end_angle *= -1 + # Inside / Outside if base.isInside(edge.Vertexes[0].Point, offset/2, True): offset *= -1 + # Create new arc edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() return Part.Wire([edge]) From cdcd83c060944e0a4be2feacad2901bd6e77f213 Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 17:32:54 +0100 Subject: [PATCH 5/8] [PATH] Fixed leadinout problems with full circles and side detection --- src/Mod/Path/PathScripts/PathDeburr.py | 10 +++++++++- src/Mod/Path/PathScripts/PathDressupLeadInOut.py | 5 +++++ src/Mod/Path/PathScripts/PathGeom.py | 7 +++++-- src/Mod/Path/PathScripts/PathOpTools.py | 16 +++++++++++----- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDeburr.py b/src/Mod/Path/PathScripts/PathDeburr.py index 2dac9b36e3..fb5e969155 100644 --- a/src/Mod/Path/PathScripts/PathDeburr.py +++ b/src/Mod/Path/PathScripts/PathDeburr.py @@ -234,16 +234,24 @@ class ObjectDeburr(PathEngraveBase.ObjectOp): self.basewires.extend(basewires) + # Set default side + side = ["Outside"] for w in basewires: self.adjusted_basewires.append(w) - wire = PathOpTools.offsetWire(w, base.Shape, offset, True) + wire = PathOpTools.offsetWire(w, base.Shape, offset, True, side) if wire: wires.append(wire) # Set direction of op forward = (obj.Direction == 'CW') + # Set value of side + obj.Side = side[0] + # Check side extra for angled faces + if radius_top > radius_bottom: + obj.Side = "Inside" + zValues = [] z = 0 if obj.StepDown.Value != 0: diff --git a/src/Mod/Path/PathScripts/PathDressupLeadInOut.py b/src/Mod/Path/PathScripts/PathDressupLeadInOut.py index 64fc18e1ac..137cf71ee7 100644 --- a/src/Mod/Path/PathScripts/PathDressupLeadInOut.py +++ b/src/Mod/Path/PathScripts/PathDressupLeadInOut.py @@ -113,6 +113,7 @@ class ObjectDressup: def getDirectionOfPath(self, obj): op = PathDressup.baseOp(obj.Base) + if hasattr(op, 'Side') and op.Side == 'Outside': if hasattr(op, 'Direction') and op.Direction == 'CW': return 'left' @@ -131,12 +132,16 @@ class ObjectDressup: return '' def normalize(self, Vector): + vx = 0 + vy = 0 + x = Vector.x y = Vector.y length = math.sqrt(x*x + y*y) if((math.fabs(length)) > 0.0000000000001): vx = round(x / length, 3) vy = round(y / length, 3) + return FreeCAD.Vector(vx, vy, 0) def invert(self, Vector): diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index 5c70b63701..21585435d3 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -350,8 +350,11 @@ def edgeForCmd(cmd, startPoint): PathLog.debug("StartPoint:{}".format(startPoint)) PathLog.debug("MidPoint:{}".format(midPoint)) PathLog.debug("EndPoint:{}".format(endPoint)) - - return Part.Edge(Part.Arc(startPoint, midPoint, endPoint)) + + if pointsCoincide(startPoint, endPoint, 0.001): + return Part.makeCircle(R, center, FreeCAD.Vector(0, 0, 1)) + else: + return Part.Edge(Part.Arc(startPoint, midPoint, endPoint)) # It's a Helix #print('angle: A=%.2f B=%.2f' % (getAngle(A)/math.pi, getAngle(B)/math.pi)) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index de7c2e19fb..83cdb5c3e8 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -143,7 +143,7 @@ def orientWire(w, forward=True): PathLog.track('orientWire - ok') return wire -def offsetWire(wire, base, offset, forward): +def offsetWire(wire, base, offset, forward, Side = None): '''offsetWire(wire, base, offset, forward) ... offsets the wire away from base and orients the wire accordingly. The function tries to avoid most of the pitfalls of Part.makeOffset2D which is possible because all offsetting happens in the XY plane. @@ -163,6 +163,9 @@ def offsetWire(wire, base, offset, forward): if offset > curve.Radius or PathGeom.isRoughly(offset, curve.Radius): # offsetting a hole by its own radius (or more) makes the hole vanish return None + if Side: + Side[0] = "Inside" + print("inside") new_edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z)) return Part.Wire([new_edge]) @@ -186,6 +189,9 @@ def offsetWire(wire, base, offset, forward): # Inside / Outside if base.isInside(edge.Vertexes[0].Point, offset/2, True): offset *= -1 + if Side: + print("inside") + Side[0] = "Inside" # Create new arc edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() @@ -223,12 +229,12 @@ def offsetWire(wire, base, offset, forward): if wire.isClosed(): if not base.isInside(owire.Edges[0].Vertexes[0].Point, offset/2, True): PathLog.track('closed - outside') - # if Side: - # Side[0] = "Outside" + if Side: + Side[0] = "Outside" return orientWire(owire, forward) PathLog.track('closed - inside') - # if Side: - # Side[0] = "Inside" + if Side: + Side[0] = "Inside" try: owire = wire.makeOffset2D(-offset) except Exception: # pylint: disable=broad-except From e545f32aef9edcff54a97d7e49aad7ed3285d182 Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 17:37:24 +0100 Subject: [PATCH 6/8] [PATH] Updated copyright --- src/Mod/Path/PathScripts/PathDressupLeadInOut.py | 4 ++-- src/Mod/Path/PathScripts/PathGeom.py | 1 + src/Mod/Path/PathScripts/PathOpTools.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathDressupLeadInOut.py b/src/Mod/Path/PathScripts/PathDressupLeadInOut.py index 137cf71ee7..03f24a277f 100644 --- a/src/Mod/Path/PathScripts/PathDressupLeadInOut.py +++ b/src/Mod/Path/PathScripts/PathDressupLeadInOut.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2017 LTS under LGPL * -# * Copyright (c) 2020 Schildkroet * +# * Copyright (c) 2020-2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * @@ -113,7 +113,7 @@ class ObjectDressup: def getDirectionOfPath(self, obj): op = PathDressup.baseOp(obj.Base) - + if hasattr(op, 'Side') and op.Side == 'Outside': if hasattr(op, 'Direction') and op.Direction == 'CW': return 'left' diff --git a/src/Mod/Path/PathScripts/PathGeom.py b/src/Mod/Path/PathScripts/PathGeom.py index 21585435d3..d4054f48a8 100644 --- a/src/Mod/Path/PathScripts/PathGeom.py +++ b/src/Mod/Path/PathScripts/PathGeom.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2016 sliptonic * +# * Copyright (c) 2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index 83cdb5c3e8..f9e885a1f2 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2018 sliptonic * +# * Copyright (c) 2021 Schildkroet * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * From 5c119906cf163dc3159b7521679d5cc01d77cda6 Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sat, 13 Feb 2021 22:02:10 +0100 Subject: [PATCH 7/8] [PATH] Fixed tests --- src/Mod/Path/PathTests/TestPathDeburr.py | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Mod/Path/PathTests/TestPathDeburr.py b/src/Mod/Path/PathTests/TestPathDeburr.py index 901851143b..2dcf446018 100644 --- a/src/Mod/Path/PathTests/TestPathDeburr.py +++ b/src/Mod/Path/PathTests/TestPathDeburr.py @@ -38,7 +38,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase): tool.FlatRadius = 0 tool.CuttingEdgeAngle = 180 - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True) self.assertRoughly(0.01, depth) self.assertRoughly(9, offset) self.assertFalse(info) @@ -46,7 +46,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase): # legacy tools - no problem, same result tool.CuttingEdgeAngle = 0 - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True) self.assertRoughly(0.01, depth) self.assertRoughly(9, offset) self.assertFalse(info) @@ -57,12 +57,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase): tool.FlatRadius = 0 tool.CuttingEdgeAngle = 90 - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) self.assertRoughly(1, depth) self.assertRoughly(0, offset) self.assertFalse(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.2, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.2, tool, True) self.assertRoughly(1.2, depth) self.assertRoughly(0.2, offset) self.assertFalse(info) @@ -73,12 +73,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase): tool.FlatRadius = 0.3 tool.CuttingEdgeAngle = 90 - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) self.assertRoughly(1, depth) self.assertRoughly(0.3, offset) self.assertFalse(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(2, 0.2, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(2, 0.2, tool, True) self.assertRoughly(2.2, depth) self.assertRoughly(0.5, offset) self.assertFalse(info) @@ -91,12 +91,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase): td = 1.73205 - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True) self.assertRoughly(td, depth) self.assertRoughly(10, offset) self.assertFalse(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(3, 1, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(3, 1, tool, True) self.assertRoughly(td * 3 + 1, depth) self.assertRoughly(10 + td, offset) self.assertFalse(info) @@ -109,15 +109,15 @@ class TestPathDeburr(PathTestUtils.PathTestBase): self.Diameter = dia tool = FakeEndmill(10) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True) self.assertRoughly(0.1, depth) self.assertRoughly(4, offset) self.assertTrue(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) self.assertRoughly(0.1, depth) self.assertRoughly(4, offset) self.assertTrue(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) self.assertRoughly(0.1, depth) self.assertRoughly(4, offset) self.assertTrue(info) @@ -131,15 +131,15 @@ class TestPathDeburr(PathTestUtils.PathTestBase): self.CuttingEdgeAngle = angle tool = FakePointyBit(10, 90) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True) self.assertRoughly(1.1, depth) self.assertRoughly(0.1, offset) self.assertTrue(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) self.assertRoughly(1.1, depth) self.assertRoughly(0.1, offset) self.assertTrue(info) - (depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) + (depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info) self.assertRoughly(1.1, depth) self.assertRoughly(0.1, offset) self.assertTrue(info) From 9e69594769e8c039565c7d0d2fd3d6c267a29820 Mon Sep 17 00:00:00 2001 From: Patrick F Date: Sun, 21 Feb 2021 02:56:14 +0100 Subject: [PATCH 8/8] [PATH] offsetWire bugfixes --- src/Mod/Path/PathScripts/PathOpTools.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Mod/Path/PathScripts/PathOpTools.py b/src/Mod/Path/PathScripts/PathOpTools.py index f9e885a1f2..4f66953b02 100644 --- a/src/Mod/Path/PathScripts/PathOpTools.py +++ b/src/Mod/Path/PathScripts/PathOpTools.py @@ -186,16 +186,23 @@ def offsetWire(wire, base, offset, forward, Side = None): start_angle *= -1 if edge.Vertexes[1].Point.y < curve.Center.y: end_angle *= -1 + + if (edge.Vertexes[0].Point.x > curve.Center.x or edge.Vertexes[1].Point.x > curve.Center.x) and curve.AngleXU < 0: + tmp = start_angle + start_angle = end_angle + end_angle = tmp # Inside / Outside if base.isInside(edge.Vertexes[0].Point, offset/2, True): offset *= -1 if Side: - print("inside") Side[0] = "Inside" # Create new arc - edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() + if curve.AngleXU > 0: + edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape() + else: + edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius-offset), start_angle, end_angle).toShape() return Part.Wire([edge])