# *************************************************************************** # * Copyright (c) 2009, 2010 Yorik van Havre * # * Copyright (c) 2009, 2010 Ken Cline * # * * # * 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. * # * * # * This program 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 this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** """Define geometry functions for manipulating shapes in the Draft Workbench. These functions are used by different object creation functions of the Draft Workbench, both in `Draft.py` and `DraftTools.py`. They operate on the internal shapes (`Part::TopoShape`) of different objects and on their subelements, that is, vertices, edges, and faces. """ ## \defgroup DRAFTGEOMUTILS DraftGeomUtils # \ingroup UTILITIES # \brief Shape manipulation utilities for the Draft workbench # # Shapes manipulation utilities ## \addtogroup DRAFTGEOMUTILS # @{ import cmath import math import FreeCAD import Part import DraftVecUtils from FreeCAD import Vector __title__ = "FreeCAD Draft Workbench - Geometry library" __author__ = "Yorik van Havre, Jacques-Antoine Gaudin, Ken Cline" __url__ = ["https://www.freecadweb.org"] from draftgeoutils.general import PARAMGRP as params from draftgeoutils.general import NORM # Generic functions ********************************************************* from draftgeoutils.general import precision from draftgeoutils.general import vec from draftgeoutils.general import edg from draftgeoutils.general import getVerts from draftgeoutils.general import v1 from draftgeoutils.general import isNull from draftgeoutils.general import isPtOnEdge from draftgeoutils.general import hasCurves from draftgeoutils.general import isAligned from draftgeoutils.general import getQuad from draftgeoutils.general import areColinear from draftgeoutils.general import hasOnlyWires from draftgeoutils.general import geomType from draftgeoutils.general import isValidPath # edge functions ************************************************************* from draftgeoutils.edges import findEdge from draftgeoutils.intersections import findIntersection from draftgeoutils.intersections import wiresIntersect from draftgeoutils.offsets import pocket2d from draftgeoutils.edges import orientEdge from draftgeoutils.geometry import mirror from draftgeoutils.arcs import isClockwise from draftgeoutils.edges import isSameLine from draftgeoutils.arcs import isWideAngle from draftgeoutils.general import findClosest from draftgeoutils.faces import concatenate from draftgeoutils.faces import getBoundary from draftgeoutils.edges import isLine from draftgeoutils.sort_edges import sortEdges from draftgeoutils.sort_edges import sortEdgesOld from draftgeoutils.edges import invert from draftgeoutils.wires import flattenWire from draftgeoutils.wires import findWires from draftgeoutils.wires import findWiresOld2 from draftgeoutils.wires import superWire from draftgeoutils.edges import findMidpoint from draftgeoutils.geometry import findPerpendicular from draftgeoutils.offsets import offset from draftgeoutils.wires import isReallyClosed from draftgeoutils.geometry import getSplineNormal from draftgeoutils.geometry import getNormal from draftgeoutils.geometry import getRotation from draftgeoutils.geometry import calculatePlacement from draftgeoutils.offsets import offsetWire from draftgeoutils.intersections import connect from draftgeoutils.geometry import findDistance from draftgeoutils.intersections import angleBisection from draftgeoutils.circles import findClosestCircle from draftgeoutils.faces import isCoplanar from draftgeoutils.geometry import isPlanar from draftgeoutils.wires import findWiresOld from draftgeoutils.edges import getTangent from draftgeoutils.faces import bind from draftgeoutils.faces import cleanFaces from draftgeoutils.cuboids import isCubic from draftgeoutils.cuboids import getCubicDimensions from draftgeoutils.wires import removeInterVertices from draftgeoutils.arcs import arcFromSpline from draftgeoutils.fillets import fillet from draftgeoutils.fillets import filletWire from draftgeoutils.circles import getCircleFromSpline from draftgeoutils.wires import curvetowire from draftgeoutils.wires import cleanProjection from draftgeoutils.wires import curvetosegment from draftgeoutils.wires import tessellateProjection from draftgeoutils.wires import rebaseWire from draftgeoutils.faces import removeSplitter # circle functions ********************************************************* def getBoundaryAngles(angle, alist): """returns the 2 closest angles from the list that encompass the given angle""" negs = True while negs: negs = False for i in range(len(alist)): if alist[i] < 0: alist[i] = 2*math.pi + alist[i] negs = True if angle < 0: angle = 2*math.pi + angle negs = True lower = None for a in alist: if a < angle: if lower is None: lower = a else: if a > lower: lower = a if lower is None: lower = 0 for a in alist: if a > lower: lower = a higher = None for a in alist: if a > angle: if higher is None: higher = a else: if a < higher: higher = a if higher is None: higher = 2*math.pi for a in alist: if a < higher: higher = a return (lower,higher) def circleFrom2tan1pt(tan1, tan2, point): """circleFrom2tan1pt(edge, edge, Vector)""" if (geomType(tan1) == "Line") and (geomType(tan2) == "Line") and isinstance(point, FreeCAD.Vector): return circlefrom2Lines1Point(tan1, tan2, point) elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Line") and isinstance(point, FreeCAD.Vector): return circlefromCircleLinePoint(tan1, tan2, point) elif (geomType(tan2) == "Circle") and (geomType(tan1) == "Line") and isinstance(point, FreeCAD.Vector): return circlefromCircleLinePoint(tan2, tan1, point) elif (geomType(tan2) == "Circle") and (geomType(tan1) == "Circle") and isinstance(point, FreeCAD.Vector): return circlefrom2Circles1Point(tan2, tan1, point) def circleFrom2tan1rad(tan1, tan2, rad): """circleFrom2tan1rad(edge, edge, float)""" if (geomType(tan1) == "Line") and (geomType(tan2) == "Line"): return circleFrom2LinesRadius(tan1, tan2, rad) elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Line"): return circleFromCircleLineRadius(tan1, tan2, rad) elif (geomType(tan1) == "Line") and (geomType(tan2) == "Circle"): return circleFromCircleLineRadius(tan2, tan1, rad) elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Circle"): return circleFrom2CirclesRadius(tan1, tan2, rad) def circleFrom1tan2pt(tan1, p1, p2): if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector): return circlefrom1Line2Points(tan1, p1, p2) if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector): return circlefrom1Circle2Points(tan1, p1, p2) def circleFrom1tan1pt1rad(tan1, p1, rad): if (geomType(tan1) == "Line") and isinstance(p1, FreeCAD.Vector): return circleFromPointLineRadius(p1, tan1, rad) if (geomType(tan1) == "Circle") and isinstance(p1, FreeCAD.Vector): return circleFromPointCircleRadius(p1, tan1, rad) def circleFrom3tan(tan1, tan2, tan3): tan1IsLine = (geomType(tan1) == "Line") tan2IsLine = (geomType(tan2) == "Line") tan3IsLine = (geomType(tan3) == "Line") tan1IsCircle = (geomType(tan1) == "Circle") tan2IsCircle = (geomType(tan2) == "Circle") tan3IsCircle = (geomType(tan3) == "Circle") if tan1IsLine and tan2IsLine and tan3IsLine: return circleFrom3LineTangents(tan1, tan2, tan3) elif tan1IsCircle and tan2IsCircle and tan3IsCircle: return circleFrom3CircleTangents(tan1, tan2, tan3) elif (tan1IsCircle and tan2IsLine and tan3IsLine): return circleFrom1Circle2Lines(tan1, tan2, tan3) elif (tan1IsLine and tan2IsCircle and tan3IsLine): return circleFrom1Circle2Lines(tan2, tan1, tan3) elif (tan1IsLine and tan2IsLine and tan3IsCircle): return circleFrom1Circle2Lines(tan3, tan1, tan2) elif (tan1IsLine and tan2IsCircle and tan3IsCircle): return circleFrom2Circle1Lines(tan2, tan3, tan1) elif (tan1IsCircle and tan2IsLine and tan3IsCircle): return circleFrom2Circle1Lines(tan1, tan3, tan2) elif (tan1IsCircle and tan2IsCircle and tan3IsLine): return circleFrom2Circle1Lines(tan1, tan2, tan3) from draftgeoutils.circles import circlefrom2Lines1Point from draftgeoutils.circles import circlefrom1Line2Points from draftgeoutils.circles import circleFrom2LinesRadius from draftgeoutils.circles import circleFrom3LineTangents from draftgeoutils.circles import circleFromPointLineRadius from draftgeoutils.circles import circleFrom2PointsRadius from draftgeoutils.arcs import arcFrom2Pts #############################33 to include from draftgeoutils.circles_apollonius import outerSoddyCircle from draftgeoutils.circles_apollonius import innerSoddyCircle from draftgeoutils.circles_apollonius import circleFrom3CircleTangents from draftgeoutils.linear_algebra import linearFromPoints from draftgeoutils.linear_algebra import determinant from draftgeoutils.circles import findHomotheticCenterOfCircles from draftgeoutils.circles import findRadicalAxis from draftgeoutils.circles import findRadicalCenter def pointInversion(circle, point): """Circle inversion of a point. pointInversion(Circle, Vector) Will calculate the inversed point an return it. If the given point is equal to the center of the circle "None" will be returned. See also: http://en.wikipedia.org/wiki/Inversive_geometry """ if (geomType(circle) == "Circle") and isinstance(point, FreeCAD.Vector): cen = circle.Curve.Center rad = circle.Curve.Radius if DraftVecUtils.equals(cen, point): return None # Inverse the distance of the point # dist(cen -> P) = r^2 / dist(cen -> invP) dist = DraftVecUtils.dist(point, cen) invDist = rad**2 / d invPoint = Vector(0, 0, point.z) invPoint.x = cen.x + (point.x - cen.x) * invDist / dist; invPoint.y = cen.y + (point.y - cen.y) * invDist / dist; return invPoint else: FreeCAD.Console.PrintMessage("debug: pointInversion bad parameters!\n") return None def polarInversion(circle, edge): """Return the inversion pole of a line. polarInversion(circle, edge): edge ... The polar. i.e. The nearest point on the line is inversed. http://mathworld.wolfram.com/InversionPole.html """ if (geomType(circle) == "Circle") and (geomType(edge) == "Line"): nearest = circle.Curve.Center.add(findDistance(circle.Curve.Center, edge, False)) if nearest: inversionPole = pointInversion(circle, nearest) if inversionPole: return inversionPole else: FreeCAD.Console.PrintMessage("debug: circleInversionPole bad parameters!\n") return None def circleInversion(circle, circle2): """ pointInversion(Circle, Circle) Circle inversion of a circle. """ if (geomType(circle) == "Circle") and (geomType(circle2) == "Circle"): cen1 = circle.Curve.Center rad1 = circle.Curve.Radius if DraftVecUtils.equals(cen1, point): return None invCen2 = Inversion(circle, circle2.Curve.Center) pointOnCircle2 = Vector.add(circle2.Curve.Center, Vector(circle2.Curve.Radius, 0, 0)) invPointOnCircle2 = Inversion(circle, pointOnCircle2) return Part.Circle(invCen2, norm, DraftVecUtils.dist(invCen2, invPointOnCircle2)) else: FreeCAD.Console.PrintMessage("debug: circleInversion bad parameters!\n") return None ## @}