This includes `arcs`, `circle_inversion`, `circles`, `circles_apollonius`, `circles_incomplete`, `cuboids`, `edges`, `faces`, `fillets`, `general`, `geometry`, `intersections`, `linear_geometry`, `offsets`, `sort_edges`, `wires`. These are added to the `draftgeoutils` Doxygen group so that the functions contained in each module are listed appropriately in the automatically generated documentation.
229 lines
9.7 KiB
Python
229 lines
9.7 KiB
Python
# ***************************************************************************
|
|
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
|
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
|
# * *
|
|
# * 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 to sort lists of edges."""
|
|
## @package sort_edges
|
|
# \ingroup draftgeoutils
|
|
# \brief Provides various functions to sort lists of edges.
|
|
|
|
import lazy_loader.lazy_loader as lz
|
|
|
|
from draftgeoutils.general import geomType
|
|
from draftgeoutils.edges import findMidpoint, isLine, invert
|
|
|
|
# Delay import of module until first use because it is heavy
|
|
Part = lz.LazyLoader("Part", globals(), "Part")
|
|
|
|
## \addtogroup draftgeoutils
|
|
# @{
|
|
|
|
|
|
def sortEdges(edges):
|
|
"""Sort edges. Deprecated. Use Part.__sortEdges__ instead."""
|
|
raise DeprecationWarning("Deprecated. Use Part.__sortEdges__ instead")
|
|
|
|
if len(edges) < 2:
|
|
return edges
|
|
|
|
# Build a dictionary of edges according to their end points.
|
|
# Each entry is a set of edges that starts, or ends, at the
|
|
# given vertex hash.
|
|
sdict = dict()
|
|
edict = dict()
|
|
nedges = []
|
|
for e in edges:
|
|
if hasattr(e, "Length"):
|
|
if e.Length != 0:
|
|
sdict.setdefault(e.Vertexes[0].hashCode(), []).append(e)
|
|
edict.setdefault(e.Vertexes[-1].hashCode(), []).append(e)
|
|
nedges.append(e)
|
|
|
|
if not nedges:
|
|
print("DraftGeomUtils.sortEdges: zero-length edges")
|
|
return edges
|
|
|
|
# Find the start of the path. The start is the vertex that appears
|
|
# in the sdict dictionary but not in the edict dictionary, and has
|
|
# only one edge ending there.
|
|
startedge = None
|
|
for v, se in sdict.items():
|
|
if v not in edict and len(se) == 1:
|
|
startedge = se
|
|
break
|
|
|
|
# The above may not find a start vertex; if the start edge is reversed,
|
|
# the start vertex will appear in edict (and not sdict).
|
|
if not startedge:
|
|
for v, se in edict.items():
|
|
if v not in sdict and len(se) == 1:
|
|
startedge = se
|
|
break
|
|
|
|
# If we still have no start vertex, it was a closed path. If so, start
|
|
# with the first edge in the supplied list
|
|
if not startedge:
|
|
startedge = nedges[0]
|
|
v = startedge.Vertexes[0].hashCode()
|
|
|
|
# Now build the return list by walking the edges starting at the start
|
|
# vertex we found. We're done when we've visited each edge, so the
|
|
# end check is simply the count of input elements (that works for closed
|
|
# as well as open paths).
|
|
ret = list()
|
|
# store the hash code of the last edge, to avoid picking the same edge back
|
|
eh = None
|
|
for i in range(len(nedges)):
|
|
try:
|
|
eset = sdict[v]
|
|
e = eset.pop()
|
|
if not eset:
|
|
del sdict[v]
|
|
if e.hashCode() == eh:
|
|
raise KeyError
|
|
v = e.Vertexes[-1].hashCode()
|
|
eh = e.hashCode()
|
|
except KeyError:
|
|
try:
|
|
eset = edict[v]
|
|
e = eset.pop()
|
|
if not eset:
|
|
del edict[v]
|
|
if e.hashCode() == eh:
|
|
raise KeyError
|
|
v = e.Vertexes[0].hashCode()
|
|
eh = e.hashCode()
|
|
e = invert(e)
|
|
except KeyError:
|
|
print("DraftGeomUtils.sortEdges failed - running old version")
|
|
return sortEdgesOld(edges)
|
|
ret.append(e)
|
|
|
|
return ret
|
|
|
|
|
|
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 []
|
|
|
|
## @}
|