| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | """Provides various functions to work with edges.""" |
| | |
| | |
| | |
| |
|
| | import lazy_loader.lazy_loader as lz |
| |
|
| | import FreeCAD as App |
| | import DraftVecUtils |
| |
|
| | from draftgeoutils.general import geomType, vec |
| |
|
| | |
| | Part = lz.LazyLoader("Part", globals(), "Part") |
| |
|
| | |
| | |
| |
|
| |
|
| | def findEdge(anEdge, aList): |
| | """Return True if edge is found in list of edges.""" |
| | for e in range(len(aList)): |
| | if str(anEdge.Curve) == str(aList[e].Curve): |
| | if DraftVecUtils.equals(anEdge.Vertexes[0].Point, aList[e].Vertexes[0].Point): |
| | if DraftVecUtils.equals(anEdge.Vertexes[-1].Point, aList[e].Vertexes[-1].Point): |
| | return e |
| | return None |
| |
|
| |
|
| | def orientEdge(edge, normal=None, make_arc=False): |
| | """Re-orient the edge such that it is in the XY plane. |
| | |
| | Re-orients `edge` such that it is in the XY plane. |
| | If `normal` is passed, this is used as the basis for the rotation, |
| | otherwise the placement of `edge` is used. |
| | """ |
| | |
| | edge = edge.copy() |
| | xyDir = App.Vector(0, 0, 1) |
| | base = App.Vector(0, 0, 0) |
| |
|
| | if normal: |
| | angle = DraftVecUtils.angle(normal, xyDir) * App.Units.Radian |
| | axis = normal.cross(xyDir) |
| | else: |
| | axis = edge.Placement.Rotation.Axis |
| | angle = -1 * edge.Placement.Rotation.Angle * App.Units.Radian |
| | if axis == App.Vector(0.0, 0.0, 0.0): |
| | axis = App.Vector(0.0, 0.0, 1.0) |
| | if angle: |
| | edge.rotate(base, axis, angle) |
| | if isinstance(edge.Curve, Part.Line): |
| | return Part.LineSegment(edge.Curve, edge.FirstParameter, edge.LastParameter) |
| | elif make_arc and isinstance(edge.Curve, Part.Circle) and not edge.Closed: |
| | return Part.ArcOfCircle( |
| | edge.Curve, edge.FirstParameter, edge.LastParameter, edge.Curve.Axis.z > 0 |
| | ) |
| | elif make_arc and isinstance(edge.Curve, Part.Ellipse) and not edge.Closed: |
| | return Part.ArcOfEllipse( |
| | edge.Curve, edge.FirstParameter, edge.LastParameter, edge.Curve.Axis.z > 0 |
| | ) |
| | return edge.Curve |
| |
|
| |
|
| | def isSameLine(e1, e2): |
| | """Return True if the 2 edges are lines and have the same points.""" |
| | if not isinstance(e1.Curve, Part.LineSegment): |
| | return False |
| | if not isinstance(e2.Curve, Part.LineSegment): |
| | return False |
| |
|
| | if DraftVecUtils.equals(e1.Vertexes[0].Point, e2.Vertexes[0].Point) and DraftVecUtils.equals( |
| | e1.Vertexes[-1].Point, e2.Vertexes[-1].Point |
| | ): |
| | return True |
| | elif DraftVecUtils.equals(e1.Vertexes[-1].Point, e2.Vertexes[0].Point) and DraftVecUtils.equals( |
| | e1.Vertexes[0].Point, e2.Vertexes[-1].Point |
| | ): |
| | return True |
| | return False |
| |
|
| |
|
| | def is_line(bspline): |
| | """Return True if the given BSpline curve is a straight line.""" |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | start_point = bspline.StartPoint |
| | end_point = bspline.EndPoint |
| | dist_start_end = end_point.distanceToPoint(start_point) |
| | if abs(bspline.length() - dist_start_end) < 1e-7: |
| | return True |
| |
|
| | return False |
| |
|
| |
|
| | def invert(shape): |
| | """Return an inverted copy of the edge or wire contained in the shape.""" |
| | if shape.ShapeType == "Wire": |
| | edges = [invert(edge) for edge in shape.OrderedEdges] |
| | edges.reverse() |
| | return Part.Wire(edges) |
| | elif shape.ShapeType == "Edge": |
| | if len(shape.Vertexes) == 1: |
| | return shape |
| | if geomType(shape) == "Line": |
| | return Part.LineSegment(shape.Vertexes[-1].Point, shape.Vertexes[0].Point).toShape() |
| | elif geomType(shape) == "Circle": |
| | mp = findMidpoint(shape) |
| | return Part.Arc(shape.Vertexes[-1].Point, mp, shape.Vertexes[0].Point).toShape() |
| | elif geomType(shape) in ["BSplineCurve", "BezierCurve"]: |
| | if isLine(shape.Curve): |
| | return Part.LineSegment(shape.Vertexes[-1].Point, shape.Vertexes[0].Point).toShape() |
| |
|
| | print("DraftGeomUtils.invert: unable to invert", shape.Curve) |
| | return shape |
| | else: |
| | print("DraftGeomUtils.invert: unable to handle", shape.ShapeType) |
| | return shape |
| |
|
| |
|
| | def findMidpoint(edge): |
| | """Return the midpoint of an edge.""" |
| | if edge.Length == 0: |
| | return None |
| | else: |
| | return edge.valueAt(edge.Curve.parameterAtDistance(edge.Length / 2, edge.FirstParameter)) |
| |
|
| |
|
| | def getTangent(edge, from_point=None): |
| | """Return the tangent to an edge, including BSpline and circular arcs. |
| | |
| | If from_point is given, it is used to calculate the tangent, |
| | only useful for a circular arc. |
| | """ |
| | if geomType(edge) == "Line": |
| | return vec(edge) |
| |
|
| | elif geomType(edge) == "BSplineCurve" or geomType(edge) == "BezierCurve": |
| | if not from_point: |
| | return None |
| | cp = edge.Curve.parameter(from_point) |
| | return edge.Curve.tangent(cp)[0] |
| |
|
| | elif geomType(edge) == "Circle": |
| | if not from_point: |
| | v1 = edge.Vertexes[0].Point.sub(edge.Curve.Center) |
| | else: |
| | v1 = from_point.sub(edge.Curve.Center) |
| | return v1.cross(edge.Curve.Axis) |
| |
|
| | return None |
| |
|
| |
|
| | def get_referenced_edges(property_value): |
| | """Return the Edges referenced by the value of a App:PropertyLink, App::PropertyLinkList, |
| | App::PropertyLinkSub or App::PropertyLinkSubList property.""" |
| | edges = [] |
| | if not isinstance(property_value, list): |
| | property_value = [property_value] |
| | for element in property_value: |
| | if hasattr(element, "Shape") and element.Shape: |
| | edges += element.Shape.Edges |
| | elif isinstance(element, tuple) and len(element) == 2: |
| | object, subelement_names = element |
| | if hasattr(object, "Shape") and object.Shape: |
| | if len(subelement_names) == 1 and subelement_names[0] == "": |
| | edges += object.Shape.Edges |
| | else: |
| | for subelement_name in subelement_names: |
| | if subelement_name.startswith("Edge"): |
| | edge_number = int(subelement_name.lstrip("Edge")) - 1 |
| | if edge_number < len(object.Shape.Edges): |
| | edges.append(object.Shape.Edges[edge_number]) |
| | return edges |
| |
|
| |
|
| | |
| |
|
| | isLine = is_line |
| |
|
| | |
| |
|