From 851f6c02df29d2de2e3b21dbb3bdb42a01d76cce Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Fri, 22 May 2020 22:09:40 -0500 Subject: [PATCH] Draft: move functions to draftgeoutils.fillets --- src/Mod/Draft/CMakeLists.txt | 1 + src/Mod/Draft/DraftGeomUtils.py | 291 +----------------- src/Mod/Draft/draftgeoutils/fillets.py | 395 +++++++++++++++++++++++++ 3 files changed, 398 insertions(+), 289 deletions(-) create mode 100644 src/Mod/Draft/draftgeoutils/fillets.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 76fc7f2f3c..81bbafd913 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -38,6 +38,7 @@ SET (Draft_geoutils draftgeoutils/geometry.py draftgeoutils/wires.py draftgeoutils/arcs.py + draftgeoutils/fillets.py ) SET(Draft_tests diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index 818a426824..c42d6bfb25 100644 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -749,297 +749,10 @@ def arcFromSpline(edge): print("couldn't make a circle out of this edge") -def fillet(lEdges, r, chamfer=False): - """fillet(lEdges,r,chamfer=False): Take a list of two Edges & a float as argument, - Returns a list of sorted edges describing a round corner""" - # Fillet code graciously donated by Jacques-Antoine Gaudin - - def getCurveType(edge, existingCurveType=None): - """Builds or completes a dictionary containing edges with keys "Arc" and 'Line'""" - if not existingCurveType: - existingCurveType = { 'Line' : [], 'Arc' : [] } - if issubclass(type(edge.Curve),Part.LineSegment): - existingCurveType['Line'] += [edge] - elif issubclass(type(edge.Curve),Part.Line): - existingCurveType['Line'] += [edge] - elif issubclass(type(edge.Curve),Part.Circle): - existingCurveType['Arc'] += [edge] - else: - raise ValueError("Edge's curve must be either Line or Arc") - return existingCurveType - - rndEdges = lEdges[0:2] - rndEdges = Part.__sortEdges__(rndEdges) - - if len(rndEdges) < 2: - return rndEdges - - if r <= 0: - print("DraftGeomUtils.fillet : Error : radius is negative.") - return rndEdges - - curveType = getCurveType(rndEdges[0]) - curveType = getCurveType(rndEdges[1],curveType) - - lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]] - - if len(curveType['Line']) == 2: - # Deals with 2-line-edges lists -------------------------------------- - U1 = lVertexes[0].Point.sub(lVertexes[1].Point) ; U1.normalize() - U2 = lVertexes[2].Point.sub(lVertexes[1].Point) ; U2.normalize() - alpha = U1.getAngle(U2) - - if chamfer: - # correcting r value so the size of the chamfer = r - beta = math.pi - alpha/2 - r = (r/2)/math.cos(beta) - - if round(alpha,precision()) == 0 or round(alpha - math.pi,precision()) == 0: # Edges have same direction - print("DraftGeomUtils.fillet : Warning : edges have same direction. Did nothing") - return rndEdges - - dToCenter = r / math.sin(alpha/2.) - dToTangent = (dToCenter**2-r**2)**(0.5) - dirVect = Vector(U1) ; dirVect.scale(dToTangent,dToTangent,dToTangent) - arcPt1 = lVertexes[1].Point.add(dirVect) - - dirVect = U2.add(U1) ; dirVect.normalize() - dirVect.scale(dToCenter-r,dToCenter-r,dToCenter-r) - arcPt2 = lVertexes[1].Point.add(dirVect) - - dirVect = Vector(U2) ; dirVect.scale(dToTangent,dToTangent,dToTangent) - arcPt3 = lVertexes[1].Point.add(dirVect) - - if (dToTangent>lEdges[0].Length) or (dToTangent>lEdges[1].Length) : - print("DraftGeomUtils.fillet : Error : radius value ", r," is too high") - return rndEdges - if chamfer: - rndEdges[1] = Part.Edge(Part.LineSegment(arcPt1,arcPt3)) - else: - rndEdges[1] = Part.Edge(Part.Arc(arcPt1,arcPt2,arcPt3)) - - if lVertexes[0].Point == arcPt1: - # fillet consumes entire first edge - rndEdges.pop(0) - else: - rndEdges[0] = Part.Edge(Part.LineSegment(lVertexes[0].Point,arcPt1)) - - if lVertexes[2].Point != arcPt3: - # fillet does not consume entire second edge - rndEdges += [Part.Edge(Part.LineSegment(arcPt3,lVertexes[2].Point))] - - return rndEdges - - elif len(curveType['Arc']) == 1 : - # Deals with lists containing an arc and a line ---------------------- - if lEdges[0] in curveType['Arc']: - lineEnd = lVertexes[2] ; arcEnd = lVertexes[0] ; arcFirst = True - else: - lineEnd = lVertexes[0] ; arcEnd = lVertexes[2] ; arcFirst = False - arcCenter = curveType['Arc'][0].Curve.Center - arcRadius = curveType['Arc'][0].Curve.Radius - arcAxis = curveType['Arc'][0].Curve.Axis - arcLength = curveType['Arc'][0].Length - - U1 = lineEnd.Point.sub(lVertexes[1].Point) ; U1.normalize() - toCenter = arcCenter.sub(lVertexes[1].Point) - if arcFirst : # make sure the tangent points towards the arc - T = arcAxis.cross(toCenter) - else: - T = toCenter.cross(arcAxis) - - projCenter = toCenter.dot(U1) - if round(abs(projCenter),precision()) > 0: - normToLine = U1.cross(T).cross(U1) - else: - normToLine = Vector(toCenter) - normToLine.normalize() - - dCenterToLine = toCenter.dot(normToLine) - r - - if round(projCenter,precision()) > 0: - newRadius = arcRadius - r - elif round(projCenter,precision()) < 0 or (round(projCenter,precision()) == 0 and U1.dot(T) > 0): - newRadius = arcRadius + r - else: - print("DraftGeomUtils.fillet : Warning : edges are already tangent. Did nothing") - return rndEdges - - toNewCent = newRadius**2-dCenterToLine**2 - if toNewCent > 0 : - toNewCent = abs(abs(projCenter) - toNewCent**(0.5)) - else : - print("DraftGeomUtils.fillet : Error : radius value ", r," is too high") - return rndEdges - - U1.scale(toNewCent,toNewCent,toNewCent) - normToLine.scale(r,r,r) - newCent = lVertexes[1].Point.add(U1).add(normToLine) - - arcPt1= lVertexes[1].Point.add(U1) - arcPt2= lVertexes[1].Point.sub(newCent); arcPt2.normalize() - arcPt2.scale(r,r,r) ; arcPt2 = arcPt2.add(newCent) - if newRadius == arcRadius - r : - arcPt3= newCent.sub(arcCenter) - else : - arcPt3= arcCenter.sub(newCent) - arcPt3.normalize() - arcPt3.scale(r,r,r) ; arcPt3 = arcPt3.add(newCent) - arcPt = [arcPt1,arcPt2,arcPt3] +from draftgeoutils.fillets import fillet - # Warning : In the following I used a trick for calling the right element - # in arcPt or V : arcFirst is a boolean so - not arcFirst is -0 or -1 - # list[-1] is the last element of a list and list[0] the first - # this way I don't have to proceed tests to know the position of the arc - - myTrick = not arcFirst - - V = [arcPt3] - V += [arcEnd.Point] - - toCenter.scale(-1,-1,-1) - - delLength = arcRadius * V[0].sub(arcCenter).getAngle(toCenter) - if delLength > arcLength or toNewCent > curveType['Line'][0].Length: - print("DraftGeomUtils.fillet : Error : radius value ", r," is too high") - return rndEdges - - arcAsEdge = arcFrom2Pts(V[-arcFirst],V[-myTrick],arcCenter,arcAxis) - - V = [lineEnd.Point,arcPt1] - lineAsEdge = Part.Edge(Part.LineSegment(V[-arcFirst],V[myTrick])) - - rndEdges[not arcFirst] = arcAsEdge - rndEdges[arcFirst] = lineAsEdge - if chamfer: - rndEdges[1:1] = [Part.Edge(Part.LineSegment(arcPt[- arcFirst],arcPt[- myTrick]))] - else: - rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[- arcFirst],arcPt[1],arcPt[- myTrick]))] - - return rndEdges - - elif len(curveType['Arc']) == 2 : - # Deals with lists of 2 arc-edges ----------------------------------- - arcCenter, arcRadius, arcAxis, arcLength, toCenter, T, newRadius = [], [], [], [], [], [], [] - for i in range(2) : - arcCenter += [curveType['Arc'][i].Curve.Center] - arcRadius += [curveType['Arc'][i].Curve.Radius] - arcAxis += [curveType['Arc'][i].Curve.Axis] - arcLength += [curveType['Arc'][i].Length] - toCenter += [arcCenter[i].sub(lVertexes[1].Point)] - T += [arcAxis[0].cross(toCenter[0])] - T += [toCenter[1].cross(arcAxis[1])] - CentToCent = toCenter[1].sub(toCenter[0]) - dCentToCent = CentToCent.Length - - sameDirection = (arcAxis[0].dot(arcAxis[1]) > 0) - TcrossT = T[0].cross(T[1]) - if sameDirection : - if round(TcrossT.dot(arcAxis[0]),precision()) > 0 : - newRadius += [arcRadius[0]+r] - newRadius += [arcRadius[1]+r] - elif round(TcrossT.dot(arcAxis[0]),precision()) < 0 : - newRadius += [arcRadius[0]-r] - newRadius += [arcRadius[1]-r] - elif T[0].dot(T[1]) > 0 : - newRadius += [arcRadius[0]+r] - newRadius += [arcRadius[1]+r] - else: - print("DraftGeomUtils.fillet : Warning : edges are already tangent. Did nothing") - return rndEdges - elif not sameDirection: - if round(TcrossT.dot(arcAxis[0]),precision()) > 0 : - newRadius += [arcRadius[0]+r] - newRadius += [arcRadius[1]-r] - elif round(TcrossT.dot(arcAxis[0]),precision()) < 0 : - newRadius += [arcRadius[0]-r] - newRadius += [arcRadius[1]+r] - elif T[0].dot(T[1]) > 0 : - if arcRadius[0] > arcRadius[1] : - newRadius += [arcRadius[0]-r] - newRadius += [arcRadius[1]+r] - elif arcRadius[1] > arcRadius[0] : - newRadius += [arcRadius[0]+r] - newRadius += [arcRadius[1]-r] - else : - print("DraftGeomUtils.fillet : Warning : arcs are coincident. Did nothing") - return rndEdges - else : - print("DraftGeomUtils.fillet : Warning : edges are already tangent. Did nothing") - return rndEdges - - if newRadius[0]+newRadius[1] < dCentToCent or \ - newRadius[0]-newRadius[1] > dCentToCent or \ - newRadius[1]-newRadius[0] > dCentToCent : - print("DraftGeomUtils.fillet : Error : radius value ", r," is too high") - return rndEdges - - x = (dCentToCent**2+newRadius[0]**2-newRadius[1]**2)/(2*dCentToCent) - y = (newRadius[0]**2-x**2)**(0.5) - - CentToCent.normalize() ; toCenter[0].normalize() ; toCenter[1].normalize() - if abs(toCenter[0].dot(toCenter[1])) != 1 : - normVect = CentToCent.cross(CentToCent.cross(toCenter[0])) - else : - normVect = T[0] - normVect.normalize() - CentToCent.scale(x,x,x) ; normVect.scale(y,y,y) - newCent = arcCenter[0].add(CentToCent.add(normVect)) - CentToNewCent = [newCent.sub(arcCenter[0]),newCent.sub(arcCenter[1])] - for i in range(2) : - CentToNewCent[i].normalize() - if newRadius[i] == arcRadius[i]+r : - CentToNewCent[i].scale(-r,-r,-r) - else : - CentToNewCent[i].scale(r,r,r) - toThirdPt = lVertexes[1].Point.sub(newCent) ; toThirdPt.normalize() - toThirdPt.scale(r,r,r) - arcPt1 = newCent.add(CentToNewCent[0]) - arcPt2 = newCent.add(toThirdPt) - arcPt3 = newCent.add(CentToNewCent[1]) - arcPt = [arcPt1,arcPt2,arcPt3] - - arcAsEdge = [] - for i in range(2) : - toCenter[i].scale(-1,-1,-1) - delLength = arcRadius[i] * arcPt[-i].sub(arcCenter[i]).getAngle(toCenter[i]) - if delLength > arcLength[i] : - print("DraftGeomUtils.fillet : Error : radius value ", r," is too high") - return rndEdges - V = [arcPt[-i],lVertexes[-i].Point] - arcAsEdge += [arcFrom2Pts(V[i-1],V[-i],arcCenter[i],arcAxis[i])] - - rndEdges[0] = arcAsEdge[0] - rndEdges[1] = arcAsEdge[1] - if chamfer: - rndEdges[1:1] = [Part.Edge(Part.LineSegment(arcPt[0],arcPt[2]))] - else: - rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[0],arcPt[1],arcPt[2]))] - - return rndEdges - - -def filletWire(aWire, r, chamfer=False): - """Fillets each angle of a wire with r as radius value - if chamfer is true, a chamfer is made instead and r is the - size of the chamfer""" - - edges = aWire.Edges - edges = Part.__sortEdges__(edges) - filEdges = [edges[0]] - for i in range(len(edges)-1): - result = fillet([filEdges[-1],edges[i+1]],r,chamfer) - if len(result)>2: - filEdges[-1:] = result[0:3] - else : - filEdges[-1:] = result[0:2] - if isReallyClosed(aWire): - result = fillet([filEdges[-1],filEdges[0]],r,chamfer) - if len(result)>2: - filEdges[-1:] = result[0:2] - filEdges[0] = result[2] - return Part.Wire(filEdges) +from draftgeoutils.fillets import filletWire def getCircleFromSpline(edge): diff --git a/src/Mod/Draft/draftgeoutils/fillets.py b/src/Mod/Draft/draftgeoutils/fillets.py new file mode 100644 index 0000000000..94b5677d74 --- /dev/null +++ b/src/Mod/Draft/draftgeoutils/fillets.py @@ -0,0 +1,395 @@ +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides various functions for working with fillets.""" +## @package fillets +# \ingroup DRAFTGEOUTILS +# \brief Provides various functions for working with fillets. + +import lazy_loader.lazy_loader as lz +import math + +import FreeCAD + +from draftgeoutils.general import precision +from draftgeoutils.arcs import arcFrom2Pts +from draftgeoutils.wires import isReallyClosed + +# Delay import of module until first use because it is heavy +Part = lz.LazyLoader("Part", globals(), "Part") + + +def fillet(lEdges, r, chamfer=False): + """Return a list of sorted edges describing a round corner. + + Author: Jacques-Antoine Gaudin + """ + + def getCurveType(edge, existingCurveType=None): + """Build or complete a dictionary containing edges. + + The dictionary contains edges with keys 'Arc' and 'Line'. + """ + if not existingCurveType: + existingCurveType = {'Line': [], + 'Arc': []} + if issubclass(type(edge.Curve), Part.LineSegment): + existingCurveType['Line'] += [edge] + elif issubclass(type(edge.Curve), Part.Line): + existingCurveType['Line'] += [edge] + elif issubclass(type(edge.Curve), Part.Circle): + existingCurveType['Arc'] += [edge] + else: + raise ValueError("Edge's curve must be either Line or Arc") + return existingCurveType + + rndEdges = lEdges[0:2] + rndEdges = Part.__sortEdges__(rndEdges) + + if len(rndEdges) < 2: + return rndEdges + + if r <= 0: + print("DraftGeomUtils.fillet: Error: radius is negative.") + return rndEdges + + curveType = getCurveType(rndEdges[0]) + curveType = getCurveType(rndEdges[1], curveType) + + lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]] + + if len(curveType['Line']) == 2: + # Deals with 2-line-edges lists + U1 = lVertexes[0].Point.sub(lVertexes[1].Point) + U1.normalize() + + U2 = lVertexes[2].Point.sub(lVertexes[1].Point) + U2.normalize() + + alpha = U1.getAngle(U2) + + if chamfer: + # correcting r value so the size of the chamfer = r + beta = math.pi - alpha/2 + r = (r/2)/math.cos(beta) + + # Edges have same direction + if (round(alpha, precision()) == 0 + or round(alpha - math.pi, precision()) == 0): + print("DraftGeomUtils.fillet: Warning: " + "edges have same direction. Did nothing") + return rndEdges + + dToCenter = r / math.sin(alpha/2.0) + dToTangent = (dToCenter**2-r**2)**(0.5) + dirVect = FreeCAD.Vector(U1) + dirVect.scale(dToTangent, dToTangent, dToTangent) + arcPt1 = lVertexes[1].Point.add(dirVect) + + dirVect = U2.add(U1) + dirVect.normalize() + dirVect.scale(dToCenter - r, dToCenter - r, dToCenter - r) + arcPt2 = lVertexes[1].Point.add(dirVect) + + dirVect = FreeCAD.Vector(U2) + dirVect.scale(dToTangent, dToTangent, dToTangent) + arcPt3 = lVertexes[1].Point.add(dirVect) + + if (dToTangent > lEdges[0].Length) or (dToTangent > lEdges[1].Length): + print("DraftGeomUtils.fillet: Error: radius value ", r, + " is too high") + return rndEdges + + if chamfer: + rndEdges[1] = Part.Edge(Part.LineSegment(arcPt1, arcPt3)) + else: + rndEdges[1] = Part.Edge(Part.Arc(arcPt1, arcPt2, arcPt3)) + + if lVertexes[0].Point == arcPt1: + # fillet consumes entire first edge + rndEdges.pop(0) + else: + rndEdges[0] = Part.Edge(Part.LineSegment(lVertexes[0].Point, + arcPt1)) + + if lVertexes[2].Point != arcPt3: + # fillet does not consume entire second edge + rndEdges += [Part.Edge(Part.LineSegment(arcPt3, + lVertexes[2].Point))] + + return rndEdges + + elif len(curveType['Arc']) == 1: + # Deals with lists containing an arc and a line + if lEdges[0] in curveType['Arc']: + lineEnd = lVertexes[2] + arcEnd = lVertexes[0] + arcFirst = True + else: + lineEnd = lVertexes[0] + arcEnd = lVertexes[2] + arcFirst = False + arcCenter = curveType['Arc'][0].Curve.Center + arcRadius = curveType['Arc'][0].Curve.Radius + arcAxis = curveType['Arc'][0].Curve.Axis + arcLength = curveType['Arc'][0].Length + + U1 = lineEnd.Point.sub(lVertexes[1].Point) + U1.normalize() + toCenter = arcCenter.sub(lVertexes[1].Point) + if arcFirst: # make sure the tangent points towards the arc + T = arcAxis.cross(toCenter) + else: + T = toCenter.cross(arcAxis) + + projCenter = toCenter.dot(U1) + if round(abs(projCenter), precision()) > 0: + normToLine = U1.cross(T).cross(U1) + else: + normToLine = FreeCAD.Vector(toCenter) + normToLine.normalize() + + dCenterToLine = toCenter.dot(normToLine) - r + + if round(projCenter, precision()) > 0: + newRadius = arcRadius - r + elif (round(projCenter, precision()) < 0 + or (round(projCenter, precision()) == 0 and U1.dot(T) > 0)): + newRadius = arcRadius + r + else: + print("DraftGeomUtils.fillet: Warning: " + "edges are already tangent. Did nothing") + return rndEdges + + toNewCent = newRadius**2 - dCenterToLine**2 + if toNewCent > 0: + toNewCent = abs(abs(projCenter) - toNewCent**(0.5)) + else: + print("DraftGeomUtils.fillet: Error: radius value ", r, + " is too high") + return rndEdges + + U1.scale(toNewCent, toNewCent, toNewCent) + normToLine.scale(r, r, r) + newCent = lVertexes[1].Point.add(U1).add(normToLine) + + arcPt1 = lVertexes[1].Point.add(U1) + arcPt2 = lVertexes[1].Point.sub(newCent) + arcPt2.normalize() + arcPt2.scale(r, r, r) + arcPt2 = arcPt2.add(newCent) + + if newRadius == arcRadius - r: + arcPt3 = newCent.sub(arcCenter) + else: + arcPt3 = arcCenter.sub(newCent) + arcPt3.normalize() + arcPt3.scale(r, r, r) + arcPt3 = arcPt3.add(newCent) + arcPt = [arcPt1, arcPt2, arcPt3] + + # Warning: In the following I used a trick for calling + # the right element in arcPt or V: + # arcFirst is a boolean so - not arcFirst is -0 or -1 + # list[-1] is the last element of a list and list[0] the first + # this way I don't have to proceed tests to know the position + # of the arc + myTrick = not arcFirst + + V = [arcPt3] + V += [arcEnd.Point] + + toCenter.scale(-1, -1, -1) + + delLength = arcRadius * V[0].sub(arcCenter).getAngle(toCenter) + if delLength > arcLength or toNewCent > curveType['Line'][0].Length: + print("DraftGeomUtils.fillet: Error: radius value ", r, + " is too high") + return rndEdges + + arcAsEdge = arcFrom2Pts(V[-arcFirst], V[-myTrick], arcCenter, arcAxis) + + V = [lineEnd.Point, arcPt1] + lineAsEdge = Part.Edge(Part.LineSegment(V[-arcFirst], V[myTrick])) + + rndEdges[not arcFirst] = arcAsEdge + rndEdges[arcFirst] = lineAsEdge + if chamfer: + rndEdges[1:1] = [Part.Edge(Part.LineSegment(arcPt[- arcFirst], + arcPt[- myTrick]))] + else: + rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[- arcFirst], + arcPt[1], + arcPt[- myTrick]))] + + return rndEdges + + elif len(curveType['Arc']) == 2: + # Deals with lists of 2 arc-edges + (arcCenter, arcRadius, + arcAxis, arcLength, + toCenter, T, newRadius) = [], [], [], [], [], [], [] + + for i in range(2): + arcCenter += [curveType['Arc'][i].Curve.Center] + arcRadius += [curveType['Arc'][i].Curve.Radius] + arcAxis += [curveType['Arc'][i].Curve.Axis] + arcLength += [curveType['Arc'][i].Length] + toCenter += [arcCenter[i].sub(lVertexes[1].Point)] + + T += [arcAxis[0].cross(toCenter[0])] + T += [toCenter[1].cross(arcAxis[1])] + CentToCent = toCenter[1].sub(toCenter[0]) + dCentToCent = CentToCent.Length + + sameDirection = (arcAxis[0].dot(arcAxis[1]) > 0) + TcrossT = T[0].cross(T[1]) + + if sameDirection: + if round(TcrossT.dot(arcAxis[0]), precision()) > 0: + newRadius += [arcRadius[0] + r] + newRadius += [arcRadius[1] + r] + elif round(TcrossT.dot(arcAxis[0]), precision()) < 0: + newRadius += [arcRadius[0] - r] + newRadius += [arcRadius[1] - r] + elif T[0].dot(T[1]) > 0: + newRadius += [arcRadius[0] + r] + newRadius += [arcRadius[1] + r] + else: + print("DraftGeomUtils.fillet: Warning: " + "edges are already tangent. Did nothing") + return rndEdges + + elif not sameDirection: + if round(TcrossT.dot(arcAxis[0]), precision()) > 0: + newRadius += [arcRadius[0] + r] + newRadius += [arcRadius[1] - r] + elif round(TcrossT.dot(arcAxis[0]), precision()) < 0: + newRadius += [arcRadius[0] - r] + newRadius += [arcRadius[1] + r] + elif T[0].dot(T[1]) > 0: + if arcRadius[0] > arcRadius[1]: + newRadius += [arcRadius[0] - r] + newRadius += [arcRadius[1] + r] + elif arcRadius[1] > arcRadius[0]: + newRadius += [arcRadius[0] + r] + newRadius += [arcRadius[1] - r] + else: + print("DraftGeomUtils.fillet: Warning: " + "arcs are coincident. Did nothing") + return rndEdges + else: + print("DraftGeomUtils.fillet: Warning: " + "edges are already tangent. Did nothing") + return rndEdges + + if (newRadius[0] + newRadius[1] < dCentToCent + or newRadius[0] - newRadius[1] > dCentToCent + or newRadius[1] - newRadius[0] > dCentToCent): + print("DraftGeomUtils.fillet: Error: radius value ", r, + " is too high") + return rndEdges + + x = ((dCentToCent**2 + newRadius[0]**2 - newRadius[1]**2) + / (2*dCentToCent)) + y = (newRadius[0]**2 - x**2)**(0.5) + + CentToCent.normalize() + toCenter[0].normalize() + toCenter[1].normalize() + if abs(toCenter[0].dot(toCenter[1])) != 1: + normVect = CentToCent.cross(CentToCent.cross(toCenter[0])) + else: + normVect = T[0] + + normVect.normalize() + CentToCent.scale(x, x, x) + normVect.scale(y, y, y) + newCent = arcCenter[0].add(CentToCent.add(normVect)) + CentToNewCent = [newCent.sub(arcCenter[0]), + newCent.sub(arcCenter[1])] + + for i in range(2): + CentToNewCent[i].normalize() + if newRadius[i] == arcRadius[i] + r: + CentToNewCent[i].scale(-r, -r, -r) + else: + CentToNewCent[i].scale(r, r, r) + + toThirdPt = lVertexes[1].Point.sub(newCent) + toThirdPt.normalize() + toThirdPt.scale(r, r, r) + arcPt1 = newCent.add(CentToNewCent[0]) + arcPt2 = newCent.add(toThirdPt) + arcPt3 = newCent.add(CentToNewCent[1]) + arcPt = [arcPt1, arcPt2, arcPt3] + + arcAsEdge = [] + for i in range(2): + toCenter[i].scale(-1, -1, -1) + delLength = (arcRadius[i] + * arcPt[-i].sub(arcCenter[i]).getAngle(toCenter[i])) + if delLength > arcLength[i]: + print("DraftGeomUtils.fillet: Error: radius value ", r, + " is too high") + return rndEdges + V = [arcPt[-i], lVertexes[-i].Point] + arcAsEdge += [arcFrom2Pts(V[i-1], V[-i], + arcCenter[i], arcAxis[i])] + + rndEdges[0] = arcAsEdge[0] + rndEdges[1] = arcAsEdge[1] + if chamfer: + rndEdges[1:1] = [Part.Edge(Part.LineSegment(arcPt[0], arcPt[2]))] + else: + rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[0], + arcPt[1], + arcPt[2]))] + + return rndEdges + + +def filletWire(aWire, r, chamfer=False): + """Fillet each angle of a wire with r as radius. + + If chamfer is true, a `chamfer` is made instead, and `r` is the + size of the chamfer. + """ + edges = aWire.Edges + edges = Part.__sortEdges__(edges) + filEdges = [edges[0]] + + for i in range(len(edges) - 1): + result = fillet([filEdges[-1], edges[i+1]], r, chamfer) + if len(result) > 2: + filEdges[-1:] = result[0:3] + else: + filEdges[-1:] = result[0:2] + + if isReallyClosed(aWire): + result = fillet([filEdges[-1], filEdges[0]], r, chamfer) + if len(result) > 2: + filEdges[-1:] = result[0:2] + filEdges[0] = result[2] + + return Part.Wire(filEdges)