@@ -263,7 +263,6 @@ def mesh_xsections(self, m, neighborhood=None):
263
263
Returns a list of Polylines.
264
264
'''
265
265
import operator
266
- import scipy .sparse as sp
267
266
from blmath .geometry import Polyline
268
267
269
268
# 1: Select those faces that intersect the plane, fs
@@ -294,54 +293,72 @@ def edge_from_face(f):
294
293
verts = verts [list (np .sqrt (np .sum (np .diff (verts , axis = 0 ) ** 2 , axis = 1 )) > eps ) + [True ]]
295
294
# the True at the end there is because np.diff returns pairwise differences; one less element than the original array
296
295
297
- # 4: Build the edge adjacency matrix
298
- E = sp .dok_matrix ((verts .shape [0 ], verts .shape [0 ]), dtype = np .bool )
296
+ class Graph (object ):
297
+ # A little utility class to build a symmetric graph
298
+ def __init__ (self , size ):
299
+ self .size = size
300
+ self .d = {}
301
+ def __len__ (self ):
302
+ return len (self .d )
303
+ def add_edge (self , ii , jj ):
304
+ assert ii >= 0 and ii < self .size
305
+ assert jj >= 0 and jj < self .size
306
+ if ii not in self .d :
307
+ self .d [ii ] = set ()
308
+ if jj not in self .d :
309
+ self .d [jj ] = set ()
310
+ self .d [ii ].add (jj )
311
+ self .d [jj ].add (ii )
312
+
313
+ # 4: Build the edge adjacency graph
314
+ G = Graph (verts .shape [0 ])
299
315
def indexof (v , in_this ):
300
316
return np .nonzero (np .all (np .abs (in_this - v ) < eps , axis = 1 ))[0 ]
301
317
for ii , v in enumerate (verts ):
302
318
for other_v in list (v2s [indexof (v , v1s )]) + list (v1s [indexof (v , v2s )]):
303
319
neighbors = indexof (other_v , verts )
304
- E [ ii , neighbors ] = True
305
- E [ neighbors , ii ] = True
320
+ for jj in neighbors :
321
+ G . add_edge ( ii , jj )
306
322
307
- def eulerPath ( E ):
323
+ def euler_path ( graph ):
308
324
# Based on code from Przemek Drochomirecki, Krakow, 5 Nov 2006
309
325
# http://code.activestate.com/recipes/498243-finding-eulerian-path-in-undirected-graph/
310
326
# Under PSF License
311
327
# NB: MUTATES graph
312
- if len (E .nonzero ()[0 ]) == 0 :
313
- return None
328
+
314
329
# counting the number of vertices with odd degree
315
- odd = list ( np . nonzero ( np . bitwise_and ( np . sum ( E , axis = 0 ), 1 ))[ 1 ])
316
- odd .append (np . nonzero ( E )[ 0 ] [0 ])
330
+ odd = [ x for x in graph . keys () if len ( graph [ x ]) & 1 ]
331
+ odd .append (graph . keys () [0 ])
317
332
# This check is appropriate if there is a single connected component.
318
333
# Since we're willing to take away one connected component per call,
319
334
# we skip this check.
320
- # if len(odd) > 3:
335
+ # if len(odd)> 3:
321
336
# return None
322
337
stack = [odd [0 ]]
323
338
path = []
324
339
# main algorithm
325
340
while stack :
326
341
v = stack [- 1 ]
327
- nonzero = np .nonzero (E )
328
- nbrs = nonzero [1 ][nonzero [0 ] == v ]
329
- if len (nbrs ) > 0 :
330
- u = nbrs [0 ]
342
+ if v in graph :
343
+ u = graph [v ].pop ()
331
344
stack .append (u )
332
- # deleting edge u-v
333
- E [u , v ] = False
334
- E [v , u ] = False
345
+ # deleting edge u-v (v-u already removed by pop)
346
+ graph [u ].remove (v )
347
+ # graph[v].remove(u)
348
+ if len (graph [v ]) == 0 :
349
+ del graph [v ]
350
+ if len (graph [u ]) == 0 :
351
+ del graph [u ]
335
352
else :
336
353
path .append (stack .pop ())
337
354
return path
338
355
339
356
# 5: Find the paths for each component
340
357
components = []
341
358
components_closed = []
342
- while len (E . nonzero ()[ 0 ] ) > 0 :
343
- # This works because eulerPath mutates the graph as it goes
344
- path = eulerPath ( E )
359
+ while len (G ) > 0 :
360
+ # This works because euler_path mutates the graph as it goes
361
+ path = euler_path ( G . d )
345
362
if path is None :
346
363
raise ValueError ("mesh slice has too many odd degree edges; can't find a path along the edge" )
347
364
component_verts = verts [path ]
0 commit comments