diff --git a/src/Mod/Path/PathScripts/PathFeatureExtensions.py b/src/Mod/Path/PathScripts/PathFeatureExtensions.py index 6036efc5f8..9a734de260 100644 --- a/src/Mod/Path/PathScripts/PathFeatureExtensions.py +++ b/src/Mod/Path/PathScripts/PathFeatureExtensions.py @@ -174,6 +174,44 @@ def setExtensions(obj, extensions): obj.ExtensionFeature = [(ext.obj, ext.getSubLink()) for ext in extensions] +def getStandardAngle(x, y): + """getStandardAngle(x, y)... + Return standard degree angle given x and y values of vector.""" + angle = math.degrees(math.atan2(y, x)) + if angle < 0.0: + return angle + 360.0 + return angle + + +def arcAdjustmentAngle(arc1, arc2): + """arcAdjustmentAngle(arc1, arc2)... + Return adjustment angle to apply to arc2 in order to align it with arc1. + Arcs must have same center point.""" + center = arc1.Curve.Center + cntr2 = arc2.Curve.Center + + # Verify centers of arcs are same + if center.sub(cntr2).Length > 0.0000001: + return None + + # Calculate midpoint of arc1, and standard angle from center to that midpoint + midPntArc1 = arc1.valueAt( + arc1.FirstParameter + (arc1.LastParameter - arc1.FirstParameter) / 2.0 + ) + midPntVect1 = midPntArc1.sub(center) + ang1 = getStandardAngle(midPntVect1.x, midPntVect1.y) + + # Calculate midpoint of arc2, and standard angle from center to that midpoint + midPntArc2 = arc2.valueAt( + arc2.FirstParameter + (arc2.LastParameter - arc2.FirstParameter) / 2.0 + ) + midPntVect2 = midPntArc2.sub(center) + ang2 = getStandardAngle(midPntVect2.x, midPntVect2.y) + + # Return adjustment angle to apply to arc2 in order to align with arc1 + return ang1 - ang2 + + class Extension(object): DirectionNormal = 0 DirectionX = 1 @@ -300,6 +338,7 @@ class Extension(object): PathLog.debug("Extending single edge wire") edge = edges[0] if Part.Circle == type(edge.Curve): + PathLog.debug("is Part.Circle") circle = edge.Curve # for a circle we have to figure out if it's a hole or a cylinder p0 = edge.valueAt(edge.FirstParameter) @@ -315,6 +354,7 @@ class Extension(object): # assuming the offset produces a valid circle - go for it if r > 0: + PathLog.debug("radius > 0 - extend outward") e3 = Part.makeCircle( r, circle.Center, @@ -322,7 +362,18 @@ class Extension(object): edge.FirstParameter * 180 / math.pi, edge.LastParameter * 180 / math.pi, ) + + # Determine if rotational alignment is necessary for new arc + rotationAdjustment = arcAdjustmentAngle(edge, e3) + if not PathGeom.isRoughly(rotationAdjustment, 0.0): + e3.rotate( + edge.Curve.Center, + FreeCAD.Vector(0.0, 0.0, 1.0), + rotationAdjustment, + ) + if endPoints(edge): + PathLog.debug("Make section of donut") # need to construct the arc slice e0 = Part.makeLine( edge.valueAt(edge.FirstParameter), @@ -332,12 +383,21 @@ class Extension(object): edge.valueAt(edge.LastParameter), e3.valueAt(e3.LastParameter), ) - return Part.Wire([e0, edge, e2, e3]) + + wire = Part.Wire([e0, edge, e2, e3]) + + # Determine if calculated extension collides with model (wrong direction) + face = Part.Face(wire) + if face.common(feature).Area < face.Area * 0.10: + return wire # Calculated extension is correct + else: + return None # Extension collides with model extWire = Part.Wire([e3]) self.extFaces = [self._makeCircularExtFace(edge, extWire)] return extWire + PathLog.debug("radius < 0 - extend inward") # the extension is bigger than the hole - so let's just cover the whole hole if endPoints(edge): # if the resulting arc is smaller than the radius, create a pie slice @@ -351,13 +411,14 @@ class Extension(object): return Part.Wire([edge]) else: + PathLog.debug("else is NOT Part.Circle") PathLog.track(self.feature, self.sub, type(edge.Curve), endPoints(edge)) direction = self._getDirection(sub) if direction is None: return None - # return self._extendEdge(feature, edge, direction) return self._extendEdge(feature, edges[0], direction) + elif sub.isClosed(): PathLog.debug("Extending multi-edge closed wire") subFace = Part.Face(sub) @@ -380,7 +441,14 @@ class Extension(object): return off2D PathLog.debug("Extending multi-edge open wire") - return extendWire(feature, sub, length) + extendedWire = extendWire(feature, sub, length) + if extendedWire is None: + return extendedWire + + # Trim wire face using model + extFace = Part.Face(extendedWire) + trimmedWire = extFace.cut(self.obj.Shape).Wires[0] + return trimmedWire.copy() def _makeCircularExtFace(self, edge, extWire): """_makeCircularExtensionFace(edge, extWire)...