def circlefrom1Line2Points(edge, p1, p2): """circlefrom1Line2Points(edge, Vector, Vector)""" p1_p2 = edg(p1, p2) s = findIntersection(edge, p1_p2, True, True) if not s: return None s = s[0] v1 = p1.sub(s) v2 = p2.sub(s) projectedDist = math.sqrt(abs(v1.dot(v2))) edgeDir = vec(edge) edgeDir.normalize() projectedCen1 = Vector.add(s, Vector(edgeDir).multiply(projectedDist)) projectedCen2 = Vector.add(s, Vector(edgeDir).multiply(-projectedDist)) perpEdgeDir = edgeDir.cross(Vector(0, 0, 1)) perpCen1 = Vector.add(projectedCen1, perpEdgeDir) perpCen2 = Vector.add(projectedCen2, perpEdgeDir) mid = findMidpoint(p1_p2) x = DraftVecUtils.crossproduct(vec(p1_p2)) x.normalize() perp_mid = Vector.add(mid, x) cen1 = findIntersection(edg(projectedCen1, perpCen1), edg(mid, perp_mid), True, True) cen2 = findIntersection(edg(projectedCen2, perpCen2), edg(mid, perp_mid), True, True) circles = [] if cen1: radius = DraftVecUtils.dist(projectedCen1, cen1[0]) circles.append(Part.Circle(cen1[0], NORM, radius)) if cen2: radius = DraftVecUtils.dist(projectedCen2, cen2[0]) circles.append(Part.Circle(cen2[0], NORM, radius)) if circles: return circles else: return None
def cleanProjection(shape, tessellate=True, seglength=0.05): """Return a valid compound of edges, by recreating them. This is because the projection algorithm somehow creates wrong shapes. They display fine, but on loading the file the shape is invalid. Now with tanderson's fix to `ProjectionAlgos`, that isn't the case, but this function can be used for tessellating ellipses and splines for DXF output-DF. """ oldedges = shape.Edges newedges = [] for e in oldedges: try: if geomType(e) == "Line": newedges.append(e.Curve.toShape()) elif geomType(e) == "Circle": if len(e.Vertexes) > 1: mp = findMidpoint(e) a = Part.Arc(e.Vertexes[0].Point, mp, e.Vertexes[-1].Point).toShape() newedges.append(a) else: newedges.append(e.Curve.toShape()) elif geomType(e) == "Ellipse": if tessellate: newedges.append(Part.Wire(curvetowire(e, seglength))) else: if len(e.Vertexes) > 1: a = Part.Arc(e.Curve, e.FirstParameter, e.LastParameter).toShape() newedges.append(a) else: newedges.append(e.Curve.toShape()) elif (geomType(e) == "BSplineCurve" or geomType(e) == "BezierCurve"): if tessellate: newedges.append(Part.Wire(curvetowire(e, seglength))) else: if isLine(e.Curve): line = Part.LineSegment(e.Vertexes[0].Point, e.Vertexes[-1].Point).toShape() newedges.append(line) else: newedges.append(e.Curve.toShape(e.FirstParameter, e.LastParameter)) else: newedges.append(e) except Part.OCCError: print("Debug: error cleaning edge ", e) return Part.makeCompound(newedges)
def circleFrom2PointsRadius(p1, p2, radius): """Return a list of circles from two points, and one radius. The two points must not be equal. It calculates up to 2 possible centers. """ if DraftVecUtils.equals(p1, p2): return None p1_p2 = Part.LineSegment(p1, p2).toShape() dist_p1p2 = DraftVecUtils.dist(p1, p1) mid = findMidpoint(p1_p2) if dist_p1p2 == 2*radius: circle = Part.Circle(mid, NORM, radius) if circle: return [circle] else: return None _dir = vec(p1_p2) _dir.normalize() perpDir = _dir.cross(App.Vector(0, 0, 1)) perpDir.normalize() dist = math.sqrt(radius**2 - (dist_p1p2 / 2.0)**2) cen1 = App.Vector.add(mid, App.Vector(perpDir).multiply(dist)) cen2 = App.Vector.add(mid, App.Vector(perpDir).multiply(-dist)) circles = [] if cen1: circles.append(Part.Circle(cen1, NORM, radius)) if cen2: circles.append(Part.Circle(cen2, NORM, radius)) if circles: return circles else: return None
def circleFrom2PointsRadius(p1, p2, radius): """circleFrom2PointsRadiust(Vector, Vector, radius)""" if DraftVecUtils.equals(p1, p2): return None p1_p2 = Part.LineSegment(p1, p2).toShape() dist_p1p2 = DraftVecUtils.dist(p1, p1) mid = findMidpoint(p1_p2) if dist_p1p2 == 2 * radius: circle = Part.Circle(mid, NORM, radius) if circle: return [circle] else: return None dir = vec(p1_p2) dir.normalize() perpDir = dir.cross(Vector(0, 0, 1)) perpDir.normalize() dist = math.sqrt(radius**2 - (dist_p1p2 / 2.0)**2) cen1 = Vector.add(mid, Vector(perpDir).multiply(dist)) cen2 = Vector.add(mid, Vector(perpDir).multiply(-dist)) circles = [] if cen1: circles.append(Part.Circle(cen1, NORM, radius)) if cen2: circles.append(Part.Circle(cen2, NORM, radius)) if circles: return circles else: return None
def connect(edges, closed=False): """Connect the edges in the given list by their intersections.""" nedges = [] v2 = None for i in range(len(edges)): curr = edges[i] # print("debug: DraftGeomUtils.connect edge ", i, " : ", # curr.Vertexes[0].Point, curr.Vertexes[-1].Point) if i > 0: prev = edges[i - 1] else: if closed: prev = edges[-1] else: prev = None if i < (len(edges) - 1): _next = edges[i + 1] else: if closed: _next = edges[0] else: _next = None if prev: # print("debug: DraftGeomUtils.connect prev : ", # prev.Vertexes[0].Point, prev.Vertexes[-1].Point) # If the edge pairs has intersection and if there is prev v2 # (prev v2 was calculated intersection), do not calculate # again, just use it as current v1 - avoid chance of slight # difference in result. And, if edge pairs # has no intersection (parallel edges, line # - arc do no intersect, etc.), so just just current # edge endpoints as v1 and connect these 2 non-intersecting # edges # Seem have chance that 2 parallel edges offset same width, # result in 2 colinear edges - Wall / DraftGeomUtils # seem make them 1 edge and thus 1 vertical plane i = findIntersection(curr, prev, True, True) if i: if v2: v1 = v2 else: v1 = i[DraftVecUtils.closest(curr.Vertexes[0].Point, i)] else: v1 = curr.Vertexes[0].Point nedges.append(Part.LineSegment(v2, v1).toShape()) else: v1 = curr.Vertexes[0].Point if _next: # print("debug: DraftGeomUtils.connect _next : ", # _next.Vertexes[0].Point, _next.Vertexes[-1].Point) i = findIntersection(curr, _next, True, True) if i: v2 = i[DraftVecUtils.closest(curr.Vertexes[-1].Point, i)] else: v2 = curr.Vertexes[-1].Point else: v2 = curr.Vertexes[-1].Point if geomType(curr) == "Line": if v1 != v2: nedges.append(Part.LineSegment(v1, v2).toShape()) elif geomType(curr) == "Circle": if v1 != v2: nedges.append(Part.Arc(v1, findMidpoint(curr), v2).toShape()) try: return Part.Wire(nedges) except: print("DraftGeomUtils.connect: unable to connect edges") for e in nedges: print(e.Curve, " ", e.Vertexes[0].Point, " ", e.Vertexes[-1].Point) return None
def sortEdgesOld(lEdges, aVertex=None): """Sort edges. Deprecated. Use Part.__sortEdges__ instead.""" raise DeprecationWarning("Deprecated. Use Part.__sortEdges__ instead") # There is no reason to limit this to lines only because # every non-closed edge always has exactly two vertices (wmayer) # for e in lEdges: # if not isinstance(e.Curve,Part.LineSegment): # print("Sortedges cannot treat wired containing curves yet.") # return lEdges def lookfor(aVertex, inEdges): """Look for a vertex in the list of edges. Returns count, the position of the instance the position in the instance and the instance of the Edge. """ count = 0 linstances = [] # lists the instances of aVertex for i in range(len(inEdges)): for j in range(2): if aVertex.Point == inEdges[i].Vertexes[j-1].Point: instance = inEdges[i] count += 1 linstances += [i, j-1, instance] return [count] + linstances if len(lEdges) < 2: if aVertex is None: return lEdges else: result = lookfor(aVertex, lEdges) if result[0] != 0: if aVertex.Point == result[3].Vertexes[0].Point: return lEdges else: if geomType(result[3]) == "Line": return [Part.LineSegment(aVertex.Point, result[3].Vertexes[0].Point).toShape()] elif geomType(result[3]) == "Circle": mp = findMidpoint(result[3]) return [Part.Arc(aVertex.Point, mp, result[3].Vertexes[0].Point).toShape()] elif (geomType(result[3]) == "BSplineCurve" or geomType(result[3]) == "BezierCurve"): if isLine(result[3].Curve): return [Part.LineSegment(aVertex.Point, result[3].Vertexes[0].Point).toShape()] else: return lEdges else: return lEdges olEdges = [] # ol stands for ordered list if aVertex is None: for i in range(len(lEdges)*2): if len(lEdges[i/2].Vertexes) > 1: result = lookfor(lEdges[i/2].Vertexes[i % 2], lEdges) if result[0] == 1: # Have we found an end ? olEdges = sortEdgesOld(lEdges, result[3].Vertexes[result[2]]) return olEdges # if the wire is closed there is no end so choose 1st Vertex # print("closed wire, starting from ",lEdges[0].Vertexes[0].Point) return sortEdgesOld(lEdges, lEdges[0].Vertexes[0]) else: # print("looking ",aVertex.Point) result = lookfor(aVertex, lEdges) if result[0] != 0: del lEdges[result[1]] _next = sortEdgesOld(lEdges, result[3].Vertexes[-((-result[2])^1)]) # print("result ", result[3].Vertexes[0].Point, " ", # result[3].Vertexes[1].Point, " compared to ",aVertex.Point) if aVertex.Point == result[3].Vertexes[0].Point: # print("keeping") olEdges += [result[3]] + _next else: # print("inverting", result[3].Curve) if geomType(result[3]) == "Line": newedge = Part.LineSegment(aVertex.Point, result[3].Vertexes[0].Point).toShape() olEdges += [newedge] + _next elif geomType(result[3]) == "Circle": mp = findMidpoint(result[3]) newedge = Part.Arc(aVertex.Point, mp, result[3].Vertexes[0].Point).toShape() olEdges += [newedge] + _next elif (geomType(result[3]) == "BSplineCurve" or geomType(result[3]) == "BezierCurve"): if isLine(result[3].Curve): newedge = Part.LineSegment(aVertex.Point, result[3].Vertexes[0].Point).toShape() olEdges += [newedge] + _next else: olEdges += [result[3]] + _next else: olEdges += [result[3]] + _next return olEdges else: return []
def superWire(edgeslist, closed=False): """Force a wire between edges that don't have coincident endpoints. Forces a wire between edges that don't necessarily have coincident endpoints. If closed=True, the wire will always be closed. """ def median(v1, v2): vd = v2.sub(v1) vd.scale(0.5, 0.5, 0.5) return v1.add(vd) edges = Part.__sortEdges__(edgeslist) print(edges) newedges = [] for i in range(len(edges)): curr = edges[i] if i == 0: if closed: prev = edges[-1] else: prev = None else: prev = edges[i - 1] if i == (len(edges) - 1): if closed: _next = edges[0] else: _next = None else: _next = edges[i + 1] print(i, prev, curr, _next) if prev: if curr.Vertexes[0].Point == prev.Vertexes[-1].Point: p1 = curr.Vertexes[0].Point else: p1 = median(curr.Vertexes[0].Point, prev.Vertexes[-1].Point) else: p1 = curr.Vertexes[0].Point if _next: if curr.Vertexes[-1].Point == _next.Vertexes[0].Point: p2 = _next.Vertexes[0].Point else: p2 = median(curr.Vertexes[-1].Point, _next.Vertexes[0].Point) else: p2 = curr.Vertexes[-1].Point if geomType(curr) == "Line": print("line", p1, p2) newedges.append(Part.LineSegment(p1, p2).toShape()) elif geomType(curr) == "Circle": p3 = findMidpoint(curr) print("arc", p1, p3, p2) newedges.append(Part.Arc(p1, p3, p2).toShape()) else: print("Cannot superWire edges that are not lines or arcs") return None print(newedges) return Part.Wire(newedges)
def connect(edges, closed=False): """Connect the edges in the given list by their intersections.""" inters_list = [] # List of intersections (with the previous edge). for i, curr in enumerate(edges): if i > 0: prev = edges[i - 1] elif closed: prev = edges[-1] else: inters_list.append(None) continue curr_inters_list = (findIntersection(prev, curr, True, True)) if len(curr_inters_list) == 0: inters_list.append(None) elif len(curr_inters_list) == 1: inters_list.append(curr_inters_list[0]) else: inters = curr_inters_list[DraftVecUtils.closest( curr.Vertexes[0].Point, curr_inters_list)] inters_list.append(inters) new_edges = [] for i, curr in enumerate(edges): curr_sta = inters_list[i] if i < (len(edges) - 1): curr_end = inters_list[i + 1] elif closed: curr_end = inters_list[0] else: curr_end = None if curr_sta is None: curr_sta = curr.Vertexes[0].Point if i > 0: prev = edges[i - 1] elif closed: prev = edges[-1] else: prev = None if prev is not None: prev_end = prev.Vertexes[-1].Point new_edges.append( Part.LineSegment(prev_end, curr_sta).toShape()) if curr_end is None: curr_end = curr.Vertexes[-1].Point if curr_sta != curr_end: if geomType(curr) == "Line": new_edges.append( Part.LineSegment(curr_sta, curr_end).toShape()) elif geomType(curr) == "Circle": new_edges.append( Part.Arc(curr_sta, findMidpoint(curr), curr_end).toShape()) try: return Part.Wire(new_edges) except Part.OCCError: print("DraftGeomUtils.connect: unable to connect edges") for edge in new_edges: print(edge.Curve, " ", edge.Vertexes[0].Point, " ", edge.Vertexes[-1].Point) return None