1 # SPDX-FileCopyrightText: 2014-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 def line_merger(lines
, precision
=6):
7 merger
= _LineMerger(lines
, precision
)
8 return merger
.polylines
11 def _round_point(point
, precision
):
12 return tuple(round(c
, precision
) for c
in point
)
16 def __init__(self
, lines
, precision
):
17 self
.segments
= set() # single lines as tuples: ((sx, sy[, sz]), (ex, ey[, ez]))
18 self
.used_segments
= set()
19 self
.points
= dict() # key: point -> value: list of segments with this point as start or end point
20 self
.precision
= precision
22 self
.polylines
= self
.merge_lines() # result of merging process
24 def setup(self
, lines
):
26 s
= _round_point(line
.start
, self
.precision
)
27 e
= _round_point(line
.end
, self
.precision
)
28 self
.add_segment(s
, e
)
30 def add_segment(self
, start
, end
):
32 return # this is not a segment
33 if end
< start
: # order start and end points to detect all doubles
34 segment
= (end
, start
)
36 segment
= (start
, end
)
37 if segment
in self
.segments
:
38 return # this segment already exist
39 self
.segments
.add(segment
)
40 self
.add_point(start
, segment
)
41 self
.add_point(end
, segment
)
43 def add_point(self
, point
, segment
):
44 segments
= self
.points
.get(point
)
47 self
.points
[point
] = segments
48 segments
.append(segment
)
50 def get_segment_with_point(self
, point
):
51 segments
= self
.points
.get(point
)
55 # Very important: do not return already used segments
56 for segment
in segments
:
57 if segment
not in self
.used_segments
:
61 def mark_as_used_segment(self
, segment
):
62 self
.used_segments
.add(segment
)
63 self
.segments
.discard(segment
)
65 def merge_lines(self
):
66 def get_extension_point(point
):
67 extension
= self
.get_segment_with_point(point
)
68 if extension
is not None:
69 self
.mark_as_used_segment(extension
)
70 if extension
[0] == point
:
77 while len(self
.segments
):
78 segment
= self
.segments
.pop() # take an arbitrary segment
79 self
.mark_as_used_segment(segment
)
80 polyline
= list(segment
) # start a new polyline
83 while extend_start
or extend_end
:
85 extension_point
= get_extension_point(polyline
[0]) # extend start of polyline
86 if extension_point
is not None:
87 polyline
.insert(0, extension_point
)
91 extension_point
= get_extension_point(polyline
[-1]) # extend end of polyline
92 if extension_point
is not None:
93 polyline
.append(extension_point
)
96 polylines
.append(polyline
)