Code: Select all
V3 = App.Vector
def vertexSameLoc(v1, v2, tol = 1e-7):
'''
v1, v2 App.Vertex
tol: tolerance float
returns Boolean : same position within tol
'''
return abs((v1.Point - v2.Point).Length) <= tol
def matchingEdge(edgechain, edgelist, tol = 1e-7):
'''
Looks for an edge in edgelist with an end point co-located (within tol)
with an endpoint of edgechain
edgechain: list of consecutive edges
edgelist: list of edges
returns: (edge, i , j) i is chain end, j is edge end
'''
for edget in edgelist:
for j in [0, -1]:
for i in [0, -1]:
if vertexSameLoc(edgechain[i].Vertexes[i], edget.Vertexes[j], tol):
return (edget, i, j)
return None
def reversedEdge(edge):
''' reverses the geometry of edge - swapping the vertices
'''
curve = edge.Curve.trim(*edge.ParameterRange)
curve.reverse()
revedge = Part.Edge(curve)
#print(f' {[v.Point for v in edge.Vertexes]} rev: {[v.Point for v in revedge.Vertexes]}')
return revedge
def sortEdges1(edges, tol = 1e-7):
''' edges: list of Part.Edge
tol: float tolerance
returns: (closededges, edgechain, remainingedges)
'''
closededges = edgechain = []
remainingedges = edges.copy()
for i, edge in enumerate(remainingedges):
if edge.isClosed() or vertexSameLoc(edge.Vertexes[0], edge.Vertexes[-1], tol):
closededges.append(edge)
del remainingedges[i]
if len(remainingedges) == 0:
return (closededges, [], remainingedges)
else:
edgechain = [remainingedges.pop(0)]
while True:
numremaining = len(remainingedges)
match = matchingEdge(edgechain, remainingedges, tol)
print(f'Match {match}')
if match:
edgematch, i, j = match
if i == 0 and j == 0:
#print('begin/begin')
edgechain.insert(0, reversedEdge(edgematch))
elif i == 0 and j == -1:
#print('begin/end')
edgechain.insert(0, edgematch)
elif i == -1 and j == 0:
#print('end/begin')
edgechain.append(edgematch)
elif i == -1 and j == -1:
#print('end/end')
edgechain.append(reversedEdge(edgematch))
else:
print("This can't happen")
remainingedges.remove(edgematch)
#print(f'Edgechain{edgechain}')
#print(f'Remaining {remainingedges}')
if len(remainingedges) == numremaining or len(remainingedges) == 0:
break
for edge in closededges:
for v in edge.Vertexes:
v.Tolerance = 2*tol
for edge in edgechain:
for v in edge.Vertexes:
v.Tolerance = 2*tol
for edge in remainingedges:
for v in edge.Vertexes:
v.Tolerance = 2*tol
return (closededges, edgechain, remainingedges)
def sortEdges2(edges, tol = 1e-7):
'''
edges: List of Part.Edge
tol: float tolerance
returns: List of lists of serially connected edges
'''
a, b, c = sortEdges1(edges, tol)
blist = [[e] for e in a]
blist.append(b)
for i in range(100):
if len(c) > 0:
aa, bb, c = sortEdges1(c, tol)
blist.append(bb)
if len(c) == 0:
break
return blist
#### a test
def makeEdgeList(eps):
p0 = V3(-100,0,0)
p1 = V3(0,100,0)
p2 = V3(100,100,0)
p3 = V3(0,100,0)
epsv = eps * p2
e0 = Part.makeLine(p0+epsv, p1 + epsv)
e1 = Part.makeLine(p2-epsv, p1 - epsv) #reversed
e2 = Part.makeLine(p2+epsv, p3 + epsv)
#e3 = Part.makeLine(p0-epsv, p3 - epsv) #reversed
e3 = Part.makeCircle(100, V3(0,0,0), V3(0,0,1), 180, 360)
edges = [e0, e2, e1, e3]
return edges
rect = makeEdgeList(1e-5)
App.newDocument()
import OpenSCADdxf
c,f=OpenSCADdxf.importEZDXFshape("/Users/ed/Downloads/SLvl-2D-BodySketch.dxf",retcompound=True,retfaces=True)
#Collect the edges from an object that is created silently by that routine:
the_edges=OpenSCADdxf.mylayerlist[0]
ll = sortEdges2(the_edges + rect, 1e-2)
for l in ll:
try:
w = Part.Wire(l)
Part.show(w, 'Wire')
except:
print('Failed to make wire')
sortedges2(edges, tol = 1e-7) applies sortedges1 to the edge list, returning a list of chain lists.
Note that like the Part.sortEdge function, you don't get predictable (or useful?) results if the edges have any t-junctions. Traversal will depend on the ordering of the input edges.
This routine is not at all polished, given it will become redundant when Part.sortEdges() acquires a tolerance argument. I found writing it educational however. Try it on data and see if I missed anything important.