RDG-Networks 0.3.8__py3-none-any.whl → 0.3.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/METADATA +10 -2
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/RECORD +10 -9
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/WHEEL +1 -1
- RDG_networks/thickness/Classes.py +2 -1
- RDG_networks/thickness/generate_line_segments_thickness.py +21 -5
- RDG_networks/thickness/generate_line_segments_thickness_correct.py +633 -0
- RDG_networks/thickness/orientate_network.py +3 -3
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/LICENSE.txt +0 -0
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/entry_points.txt +0 -0
- {RDG_Networks-0.3.8.dist-info → RDG_Networks-0.3.10.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: RDG-Networks
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.10
|
4
4
|
Summary: Most of the code from the RDG Networks project
|
5
5
|
Home-page: https://github.com/NiekMooij/RDG_networks
|
6
6
|
Author: Niek Mooij
|
@@ -14,6 +14,14 @@ Requires-Dist: numpy
|
|
14
14
|
Requires-Dist: scipy
|
15
15
|
Requires-Dist: shapely
|
16
16
|
Requires-Dist: typing
|
17
|
+
Dynamic: author
|
18
|
+
Dynamic: author-email
|
19
|
+
Dynamic: classifier
|
20
|
+
Dynamic: description
|
21
|
+
Dynamic: home-page
|
22
|
+
Dynamic: license
|
23
|
+
Dynamic: requires-dist
|
24
|
+
Dynamic: summary
|
17
25
|
|
18
26
|
## Overview
|
19
27
|
|
@@ -8,15 +8,16 @@ RDG_networks/generate_line_segments_static.py,sha256=7KvHZi3krv-tAGydJR_gbMMmHKZ
|
|
8
8
|
RDG_networks/get_intersection_segments.py,sha256=mXB5qCy1oOps4Vu1mX6flW6v_4Xxc71YK41yOWjJX8o,2797
|
9
9
|
RDG_networks/sample_in_polygon.py,sha256=qpPpW-Da1vK8ZkVWMJ0zBsE8IgyMB619gCdybSkzKSQ,1605
|
10
10
|
RDG_networks/save_to_stl.py,sha256=St8kGw6wl8uOGx8KhrZhBfe89-mOfp5JKhz0dEDBvc0,3894
|
11
|
-
RDG_networks/thickness/Classes.py,sha256=
|
11
|
+
RDG_networks/thickness/Classes.py,sha256=zRhi2TFDwK1oARvAd1HlxnMWeHSj7KKO-u79_r23tXc,8176
|
12
12
|
RDG_networks/thickness/__init__.py,sha256=DzH-mmdrk5e1LL7oq5kg0xaDjtWR7DiCeKKchArHSIs,703
|
13
|
-
RDG_networks/thickness/generate_line_segments_thickness.py,sha256=
|
13
|
+
RDG_networks/thickness/generate_line_segments_thickness.py,sha256=euPMqyHc_RlbFuZO16SSKdZ5NvhKIJA_fOf-rvqv7iA,29214
|
14
|
+
RDG_networks/thickness/generate_line_segments_thickness_correct.py,sha256=rvvqEMGYX7imosKedyXHyTkBV4C2_24K8UxthXDTe7Q,28627
|
14
15
|
RDG_networks/thickness/generate_line_segments_thickness_static.py,sha256=6-2p4GOQFU-dP5Q9nYuaVqeb7wvxk2Fqld3A7cV2pY8,8964
|
15
|
-
RDG_networks/thickness/orientate_network.py,sha256=
|
16
|
+
RDG_networks/thickness/orientate_network.py,sha256=4jii3y89Jlw1tPmTWoUyrKE7MlHq21JuoiuwnBa1Mkk,15484
|
16
17
|
RDG_networks/thickness/sample_in_polygon.py,sha256=nJ-yqfoCCGfC6_EpGL3L1t1LOYdqWZd-7v5bxy6th34,1849
|
17
|
-
RDG_Networks-0.3.
|
18
|
-
RDG_Networks-0.3.
|
19
|
-
RDG_Networks-0.3.
|
20
|
-
RDG_Networks-0.3.
|
21
|
-
RDG_Networks-0.3.
|
22
|
-
RDG_Networks-0.3.
|
18
|
+
RDG_Networks-0.3.10.dist-info/LICENSE.txt,sha256=BHUkX2GsdTr30sKmVZ1MLGR1njnx17EX_oUuuSVZZPE,598
|
19
|
+
RDG_Networks-0.3.10.dist-info/METADATA,sha256=KmHQ5XO8lsAUBhL7uVOTqtS-wXoh7PL--U4aFyJlv40,2578
|
20
|
+
RDG_Networks-0.3.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
21
|
+
RDG_Networks-0.3.10.dist-info/entry_points.txt,sha256=coqOWe9rYYuz9VQvJGFomTzvEP7JY5T9V9gauMhSb_0,986
|
22
|
+
RDG_Networks-0.3.10.dist-info/top_level.txt,sha256=4gUUYafD5Al9V8ZSiViVGYHpRMMCsCBcGgCNodk9Syg,13
|
23
|
+
RDG_Networks-0.3.10.dist-info/RECORD,,
|
@@ -95,7 +95,7 @@ class Polygon:
|
|
95
95
|
vertices (List[Tuple[float, float]]): A list of (x, y) coordinates representing the vertices of the polygon.
|
96
96
|
"""
|
97
97
|
|
98
|
-
def __init__(self, vertices: List[tuple], middle_segment=None):
|
98
|
+
def __init__(self, vertices: List[tuple], middle_segment=None, neighbors=None):
|
99
99
|
"""
|
100
100
|
Initializes a Polygon instance with the provided vertices.
|
101
101
|
|
@@ -104,6 +104,7 @@ class Polygon:
|
|
104
104
|
"""
|
105
105
|
self.vertices = vertices
|
106
106
|
self.middle_segment = middle_segment
|
107
|
+
self.neighbors = neighbors
|
107
108
|
|
108
109
|
def area(self) -> float:
|
109
110
|
"""
|
@@ -417,7 +417,7 @@ def update_data(
|
|
417
417
|
segments_dict[segment_new_1.id] = segment_new_1
|
418
418
|
segments_dict[neighbor1_1].neighbors[id_1] = vertex_begin_1
|
419
419
|
segments_dict[neighbor1_2].neighbors[id_1] = vertex_end_1
|
420
|
-
|
420
|
+
|
421
421
|
# Update the segments_dict for the second segment
|
422
422
|
neighbors_initial_2 = {
|
423
423
|
neighbor2_1: vertex_begin_2,
|
@@ -435,7 +435,20 @@ def update_data(
|
|
435
435
|
segments_dict[neighbor2_2].neighbors[id_2] = vertex_end_2
|
436
436
|
|
437
437
|
# Update the segment_thickness_dict with the base polygon
|
438
|
-
|
438
|
+
neighbors = cycle0.copy()
|
439
|
+
neighbors.remove(f'{len(segment_thickness_dict)+1}_1')
|
440
|
+
neighbors.remove(f'{len(segment_thickness_dict)+1}_2')
|
441
|
+
neighbors = [ i[:-2] if i not in ['b1', 'b2', 'b3', 'b4'] else i for i in neighbors ]
|
442
|
+
neighbors = list(set(neighbors))
|
443
|
+
|
444
|
+
segment_thickness_dict[len(segment_thickness_dict) + 1] = Polygon(vertices=vertices0, neighbors=neighbors)
|
445
|
+
|
446
|
+
for n in neighbors:
|
447
|
+
if n in ['b1', 'b2', 'b3', 'b4']:
|
448
|
+
continue
|
449
|
+
|
450
|
+
else:
|
451
|
+
segment_thickness_dict[int(n)].neighbors.append(len(segment_thickness_dict) + 1)
|
439
452
|
|
440
453
|
return segments_dict, polygon_arr, segment_thickness_dict
|
441
454
|
|
@@ -591,14 +604,13 @@ def generate_line_segments_thickness(
|
|
591
604
|
size = len(config)
|
592
605
|
|
593
606
|
jammed = False
|
607
|
+
nucleation_points = []
|
594
608
|
for i in range(size):
|
595
609
|
if config:
|
596
610
|
nucleation_point = config[i]['location']
|
597
611
|
angles = [config[i]['angle']]
|
598
612
|
else:
|
599
613
|
nucleation_point = None
|
600
|
-
# if angles != 'uniform':
|
601
|
-
# angles=[angles[i]]
|
602
614
|
|
603
615
|
output = add_line_segment(segments_dict,
|
604
616
|
polygon_arr,
|
@@ -612,10 +624,12 @@ def generate_line_segments_thickness(
|
|
612
624
|
segments_dict, polygon_arr, segment_thickness_dict, location, angle = output
|
613
625
|
generated_config.append({ 'location': location, 'angle': angle, 'thickness': thickness_arr[i] })
|
614
626
|
|
627
|
+
nucleation_points.append(location)
|
628
|
+
|
615
629
|
else:
|
616
630
|
if config:
|
617
631
|
print('Configuration not possible. Point is skipped.')
|
618
|
-
else:
|
632
|
+
else:
|
619
633
|
print(f"Stopped at iteration {len(segment_thickness_dict)}, could not find a valid segment position.")
|
620
634
|
jammed = True
|
621
635
|
break
|
@@ -628,6 +642,8 @@ def generate_line_segments_thickness(
|
|
628
642
|
'polygon_arr': polygon_arr,
|
629
643
|
'segment_thickness_dict': segment_thickness_dict,
|
630
644
|
'jammed': jammed,
|
645
|
+
'nucleation_points': nucleation_point,
|
646
|
+
'nucleation_angles': angles,
|
631
647
|
'generated_config': generated_config}
|
632
648
|
|
633
649
|
return data_dict
|
@@ -0,0 +1,633 @@
|
|
1
|
+
import math
|
2
|
+
import numpy as np
|
3
|
+
import random
|
4
|
+
from typing import List, Dict, Tuple, Union, Optional
|
5
|
+
from shapely.geometry import Polygon as Polygon_Shapely, LineString
|
6
|
+
|
7
|
+
from .Classes import Line, LineSegment, Polygon
|
8
|
+
from .sample_in_polygon import sample_in_polygon, is_inside_polygon
|
9
|
+
|
10
|
+
def doLinesIntersect(line1: Line, line2: Line, box_size = 1) -> Tuple[bool, Union[Tuple[float, float], None]]:
|
11
|
+
"""
|
12
|
+
Check if two lines intersect and return the intersection point.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
- line1 (Line): The first line segment.
|
16
|
+
- line2 (Line): The second line segment.
|
17
|
+
- box_size (float): The size of the bounding box. Defaults to 1.
|
18
|
+
|
19
|
+
Returns:
|
20
|
+
- intersect (bool): True if the lines intersect, False otherwise.
|
21
|
+
- intersection_point (tuple or None): The intersection point (x, y) if lines intersect, None otherwise.
|
22
|
+
"""
|
23
|
+
x1, y1 = line1.location
|
24
|
+
v1, w1 = line1.direction
|
25
|
+
|
26
|
+
x2, y2 = line2.location
|
27
|
+
v2, w2 = line2.direction
|
28
|
+
|
29
|
+
determinant = v1 * w2 - v2 * w1
|
30
|
+
|
31
|
+
if determinant == 0:
|
32
|
+
return False, (None, None)
|
33
|
+
|
34
|
+
t1 = ((x2 - x1) * w2 - (y2 - y1) * v2) / determinant
|
35
|
+
t2 = ((x2 - x1) * w1 - (y2 - y1) * v1) / determinant
|
36
|
+
|
37
|
+
intersect_x = x1 + v1 * t1
|
38
|
+
intersect_y = y2 + w2 * t2
|
39
|
+
|
40
|
+
|
41
|
+
if -1e-6 < intersect_x < box_size + 1e-6 and -1e-6 < intersect_y < box_size + 1e-6:
|
42
|
+
return True, (intersect_x, intersect_y)
|
43
|
+
else:
|
44
|
+
return False, (None, None)
|
45
|
+
|
46
|
+
def doSegmentsIntersect(
|
47
|
+
segment1: LineSegment,
|
48
|
+
segment2: LineSegment,
|
49
|
+
box_size = 1
|
50
|
+
) -> Tuple[bool, Tuple[Optional[float], Optional[float]]]:
|
51
|
+
"""
|
52
|
+
Determines if two line segments intersect and returns the intersection point if they do.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
segment1 (LineSegment): The first line segment.
|
56
|
+
segment2 (LineSegment): The second line segment.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
Tuple[bool, Tuple[Optional[float], Optional[float]]]:
|
60
|
+
- A boolean indicating whether the segments intersect.
|
61
|
+
- A tuple of the x and y coordinates of the intersection point if they intersect,
|
62
|
+
otherwise (None, None).
|
63
|
+
"""
|
64
|
+
|
65
|
+
# Create line equations based on the segments' start and end points
|
66
|
+
line1 = Line(location=segment1.start, direction=np.array(segment1.end) - np.array(segment1.start))
|
67
|
+
line2 = Line(location=segment2.start, direction=np.array(segment2.end) - np.array(segment2.start))
|
68
|
+
|
69
|
+
# Check if the infinite extensions of the two lines intersect
|
70
|
+
intersect, (intersect_x, intersect_y) = doLinesIntersect(line1, line2, box_size)
|
71
|
+
|
72
|
+
# If no intersection, return False
|
73
|
+
if not intersect:
|
74
|
+
return False, (None, None)
|
75
|
+
|
76
|
+
# Check if the intersection point is within the bounds of both segments in the x-direction
|
77
|
+
xcheck = (
|
78
|
+
(segment1.end[0] <= intersect_x <= segment1.start[0]
|
79
|
+
or segment1.start[0] <= intersect_x <= segment1.end[0]
|
80
|
+
or abs(intersect_x - segment1.end[0]) < 1e-6
|
81
|
+
or abs(intersect_x - segment1.start[0]) < 1e-6)
|
82
|
+
and
|
83
|
+
(segment2.end[0] <= intersect_x <= segment2.start[0]
|
84
|
+
or segment2.start[0] <= intersect_x <= segment2.end[0]
|
85
|
+
or abs(intersect_x - segment2.end[0]) < 1e-6
|
86
|
+
or abs(intersect_x - segment2.start[0]) < 1e-6)
|
87
|
+
)
|
88
|
+
|
89
|
+
# Check if the intersection point is within the bounds of both segments in the y-direction
|
90
|
+
ycheck = (
|
91
|
+
(segment1.end[1] <= intersect_y <= segment1.start[1]
|
92
|
+
or segment1.start[1] <= intersect_y <= segment1.end[1]
|
93
|
+
or abs(intersect_y - segment1.end[1]) < 1e-6
|
94
|
+
or abs(intersect_y - segment1.start[1]) < 1e-6)
|
95
|
+
and
|
96
|
+
(segment2.end[1] <= intersect_y <= segment2.start[1]
|
97
|
+
or segment2.start[1] <= intersect_y <= segment2.end[1]
|
98
|
+
or abs(intersect_y - segment2.end[1]) < 1e-6
|
99
|
+
or abs(intersect_y - segment2.start[1]) < 1e-6)
|
100
|
+
)
|
101
|
+
|
102
|
+
# If the intersection point lies within the bounds of both segments, return True with the intersection point
|
103
|
+
if xcheck and ycheck:
|
104
|
+
return True, (intersect_x, intersect_y)
|
105
|
+
|
106
|
+
# Otherwise, return False and no intersection point
|
107
|
+
return False, (None, None)
|
108
|
+
|
109
|
+
def pick_item_with_probability(
|
110
|
+
polygon_arr: Dict[str, Dict[str, object]]
|
111
|
+
) -> Tuple[str, Dict[str, object]]:
|
112
|
+
"""
|
113
|
+
Randomly selects an item from the polygon array with a probability proportional to the area of the polygons.
|
114
|
+
|
115
|
+
Args:
|
116
|
+
polygon_arr (Dict[str, Dict[str, object]]):
|
117
|
+
A dictionary where keys are polygon identifiers (e.g., 'p1', 'p2') and values are dictionaries containing polygon properties,
|
118
|
+
including an 'area' key that stores the area of the polygon.
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
Tuple[str, Dict[str, object]]:
|
122
|
+
- The identifier of the selected polygon.
|
123
|
+
- The corresponding polygon data (dictionary) containing its properties.
|
124
|
+
"""
|
125
|
+
|
126
|
+
# Calculate the total weight (sum of areas of all polygons)
|
127
|
+
max_weight = sum(pol['area'] for pol in polygon_arr.values())
|
128
|
+
|
129
|
+
# Generate a random threshold between 0 and the total weight
|
130
|
+
threshold = random.uniform(0, max_weight)
|
131
|
+
cumulative_weight = 0
|
132
|
+
|
133
|
+
# Iterate through the polygons, accumulating weights
|
134
|
+
for item, pol in polygon_arr.items():
|
135
|
+
weight = pol['area']
|
136
|
+
cumulative_weight += weight
|
137
|
+
|
138
|
+
# Return the polygon when the cumulative weight surpasses the threshold
|
139
|
+
if cumulative_weight >= threshold:
|
140
|
+
return item, pol
|
141
|
+
|
142
|
+
def get_location_and_direction(
|
143
|
+
polygon_arr: Dict[str, Dict[str, object]],
|
144
|
+
thickness: float,
|
145
|
+
angle: float,
|
146
|
+
nucleation_point: Tuple[float, float] = None,
|
147
|
+
min_distance: float = 0,
|
148
|
+
max_attempts: int = 1000
|
149
|
+
) -> Union[Tuple[str, Dict[str, object], Tuple[float, float], np.ndarray, np.ndarray], bool]:
|
150
|
+
"""
|
151
|
+
Attempts to find a valid location and direction within a polygon for placing a new segment. The direction can either be randomly
|
152
|
+
chosen (uniformly) or from a specified list of angles. It ensures that the segment lies within the polygon's bounds given the
|
153
|
+
specified thickness.
|
154
|
+
|
155
|
+
Args:
|
156
|
+
polygon_arr (Dict[str, Dict[str, object]]):
|
157
|
+
A dictionary where the keys are polygon identifiers and the values are dictionaries containing polygon properties, including 'vertices'.
|
158
|
+
thickness (float):
|
159
|
+
The thickness of the segment that needs to fit inside the polygon.
|
160
|
+
max_attempts (int, optional):
|
161
|
+
The maximum number of attempts to find a valid location and direction. Defaults to 1000.
|
162
|
+
angle (float):
|
163
|
+
A float indicating the angle of the new segment.
|
164
|
+
nucleation_point (Tuple[float, float], optional):
|
165
|
+
predified nucleation point for the segment. Defaults to None.
|
166
|
+
min_distance (float, optional):
|
167
|
+
the minimum distance between two lines. Defaults to 0.
|
168
|
+
|
169
|
+
Returns:
|
170
|
+
Union[Tuple[str, Dict[str, object], Tuple[float, float], np.ndarray, np.ndarray], bool]:
|
171
|
+
- If a valid location and direction are found, returns a tuple containing:
|
172
|
+
- The polygon ID (`str`).
|
173
|
+
- The polygon data (`Dict[str, object]`).
|
174
|
+
- The new location as a tuple of floats (`Tuple[float, float]`).
|
175
|
+
- The direction vector as a numpy array (`np.ndarray`).
|
176
|
+
- The perpendicular vector to the direction as a numpy array (`np.ndarray`).
|
177
|
+
- The nucleation point [x,y] of the segment
|
178
|
+
- The angle of the segment.
|
179
|
+
- Returns `False` if no valid location and direction are found after the maximum attempts.
|
180
|
+
"""
|
181
|
+
direction = (np.cos(angle), np.sin(angle))
|
182
|
+
direction = np.array(direction) / np.linalg.norm(direction)
|
183
|
+
|
184
|
+
# Try to find a valid location and direction up to max_attempts
|
185
|
+
attempt = 0
|
186
|
+
while attempt < max_attempts:
|
187
|
+
polygon_id, polygon = pick_item_with_probability(polygon_arr)
|
188
|
+
|
189
|
+
# Sample a location within the polygon
|
190
|
+
#check if nucleation point is given
|
191
|
+
if nucleation_point is not None:
|
192
|
+
location_new = nucleation_point
|
193
|
+
else:
|
194
|
+
location_new = sample_in_polygon(polygon['vertices'])
|
195
|
+
|
196
|
+
# Compute the perpendicular vector to the direction
|
197
|
+
perpendicular = np.array([direction[1], -direction[0]])
|
198
|
+
perpendicular = perpendicular / np.linalg.norm(perpendicular)
|
199
|
+
|
200
|
+
# Ensure the perpendicular vector is oriented consistently (y-component is non-negative)
|
201
|
+
if perpendicular[1] < 0:
|
202
|
+
perpendicular = -perpendicular
|
203
|
+
|
204
|
+
# Compute the positions for the segment with thickness, shifted by half-thickness along the perpendicular direction
|
205
|
+
p1 = np.array(location_new) + (thickness/2 + min_distance) * perpendicular
|
206
|
+
p2 = np.array(location_new) - (thickness/2 + min_distance) * perpendicular
|
207
|
+
|
208
|
+
# Check if both endpoints of the segment are inside the polygon
|
209
|
+
if is_inside_polygon(polygon['vertices'], p1) and is_inside_polygon(polygon['vertices'], p2):
|
210
|
+
return polygon_id, polygon, location_new, direction, perpendicular, angle
|
211
|
+
|
212
|
+
attempt += 1
|
213
|
+
|
214
|
+
# If no valid location and direction is found, return False
|
215
|
+
return False
|
216
|
+
|
217
|
+
def get_polygons(polygon_id, polygon_arr, neighbor1_1, neighbor1_2, vertex_begin_1, vertex_end_1, neighbor2_1, neighbor2_2, vertex_begin_2, vertex_end_2, segment_new_id_1, segment_new_id_2):
|
218
|
+
# Extract vertices and cycle (faces) of the original polygon
|
219
|
+
vertices = polygon_arr[polygon_id]['vertices']
|
220
|
+
cycle = polygon_arr[polygon_id]['faces']
|
221
|
+
|
222
|
+
# Get first cycle and vertices
|
223
|
+
index_start_1, index_end_1 = (cycle.index(neighbor1_1), cycle.index(neighbor1_2))
|
224
|
+
if index_start_1 < index_end_1:
|
225
|
+
cycle1 = [segment_new_id_1] + cycle[index_start_1:index_end_1+1]
|
226
|
+
vertices1 = [vertex_begin_1] + vertices[index_start_1:index_end_1] + [vertex_end_1]
|
227
|
+
else:
|
228
|
+
cycle1 = [segment_new_id_1] + cycle[index_start_1:] + cycle[:index_end_1+1]
|
229
|
+
vertices1 = [vertex_begin_1] + vertices[index_start_1:] + vertices[:index_end_1] + [vertex_end_1]
|
230
|
+
|
231
|
+
# Get second cycle and vertices
|
232
|
+
index_start_2, index_end_2 = (cycle.index(neighbor2_2), cycle.index(neighbor2_1))
|
233
|
+
if index_start_2 < index_end_2:
|
234
|
+
cycle2 = [segment_new_id_2] + cycle[index_start_2:index_end_2+1]
|
235
|
+
vertices2 = [vertex_end_2] + vertices[index_start_2:index_end_2] + [vertex_begin_2]
|
236
|
+
else:
|
237
|
+
cycle2 = [segment_new_id_2] + cycle[index_start_2:] + cycle[:index_end_2+1]
|
238
|
+
vertices2 = [vertex_end_2] + vertices[index_start_2:] + vertices[:index_end_2] + [vertex_begin_2]
|
239
|
+
|
240
|
+
# Get middle cycle and vertices
|
241
|
+
cycle0 = [neighbor1_1, segment_new_id_1, neighbor1_2]
|
242
|
+
vertices0 = [vertex_begin_1, vertex_end_1]
|
243
|
+
|
244
|
+
index_start_0, index_end_0 = (cycle.index(neighbor1_2), cycle.index(neighbor2_2))
|
245
|
+
if index_start_0 < index_end_0:
|
246
|
+
cycle0 = cycle0 + cycle[index_start_0:index_end_0+1]
|
247
|
+
vertices0 = vertices0 + vertices[index_start_0:index_end_0]
|
248
|
+
|
249
|
+
elif index_start_0 > index_end_0:
|
250
|
+
cycle0 = cycle0 + cycle[index_start_0:] + cycle[:index_end_0+1]
|
251
|
+
vertices0 = vertices0 + vertices[index_start_0:] + vertices[:index_end_0]
|
252
|
+
|
253
|
+
cycle0 = cycle0 + [segment_new_id_2]
|
254
|
+
vertices0 = vertices0 + [vertex_end_2] + [vertex_begin_2]
|
255
|
+
|
256
|
+
index_start_0, index_end_0 = (cycle.index(neighbor2_1), cycle.index(neighbor1_1))
|
257
|
+
if index_start_0 < index_end_0:
|
258
|
+
cycle0 = cycle0 + cycle[index_start_0:index_end_0+1]
|
259
|
+
vertices0 = vertices0 + vertices[index_start_0:index_end_0]
|
260
|
+
|
261
|
+
elif index_start_0 > index_end_0:
|
262
|
+
cycle0 = cycle0 + cycle[index_start_0:] + cycle[:index_end_0+1]
|
263
|
+
vertices0 = vertices0 + vertices[index_start_0:] + vertices[:index_end_0]
|
264
|
+
|
265
|
+
return cycle0, vertices0, cycle1, vertices1, cycle2, vertices2
|
266
|
+
|
267
|
+
def get_new_segment(
|
268
|
+
line_segments_to_check: List[LineSegment],
|
269
|
+
location: Tuple[float, float],
|
270
|
+
direction: Tuple[float, float],
|
271
|
+
id: Optional[int] = None,
|
272
|
+
box_size: float = 1
|
273
|
+
) -> LineSegment:
|
274
|
+
"""
|
275
|
+
Creates a new line segment by extending a given location in a specified direction and
|
276
|
+
determines its neighbors by checking intersections with other line segments.
|
277
|
+
|
278
|
+
Args:
|
279
|
+
line_segments_to_check (List[LineSegment]): List of existing line segments to check for intersections.
|
280
|
+
location (Tuple[float, float]): The starting point (x, y) for the new line segment.
|
281
|
+
direction (Tuple[float, float]): The direction vector in which to extend the line segment.
|
282
|
+
id (Optional[int]): Optional ID for the new line segment. If not provided, defaults to None.
|
283
|
+
box_size(optional[Int]]): The size of the box. Defaults to 1.
|
284
|
+
|
285
|
+
Returns:
|
286
|
+
LineSegment: A new line segment object with its neighbors based on intersections.
|
287
|
+
"""
|
288
|
+
|
289
|
+
# Create a temporary line segment extending from the location in both directions
|
290
|
+
s_temp = LineSegment(start=np.array(location) - 10*np.sqrt(2)*box_size * np.array(direction), end=np.array(location) + 10*np.sqrt(2)*box_size * np.array(direction))
|
291
|
+
|
292
|
+
intersection_points = []
|
293
|
+
|
294
|
+
# Check for intersections with existing line segments
|
295
|
+
for segment in line_segments_to_check:
|
296
|
+
intersect, (intersect_x, intersect_y) = doSegmentsIntersect(s_temp, segment, box_size)
|
297
|
+
|
298
|
+
if intersect:
|
299
|
+
segment_length = math.sqrt(
|
300
|
+
(location[0] - intersect_x) ** 2
|
301
|
+
+ (location[1] - intersect_y) ** 2
|
302
|
+
)
|
303
|
+
intersection_points.append(
|
304
|
+
{"id": segment.id, "point": (intersect_x, intersect_y), "segment_length": segment_length}
|
305
|
+
)
|
306
|
+
|
307
|
+
# Divide intersections into ones behind and in front of the new line
|
308
|
+
intersections_b = [intersection for intersection in intersection_points if intersection["point"][0] < location[0]]
|
309
|
+
intersections_f = [intersection for intersection in intersection_points if intersection["point"][0] > location[0]]
|
310
|
+
|
311
|
+
if not intersections_b or not intersections_f:
|
312
|
+
intersections_b = [intersection for intersection in intersection_points if intersection["point"][1] < location[1]]
|
313
|
+
intersections_f = [intersection for intersection in intersection_points if intersection["point"][1] > location[1]]
|
314
|
+
|
315
|
+
# Determine the closest intersections for segment start and end
|
316
|
+
s_start = min(intersections_b, key=lambda x: x["segment_length"])
|
317
|
+
s_end = min(intersections_f, key=lambda x: x["segment_length"])
|
318
|
+
start, end = s_start['point'], s_end['point']
|
319
|
+
start_id, end_id = s_start['id'], s_end['id']
|
320
|
+
|
321
|
+
# Ensure the start comes before the end
|
322
|
+
if start[0] > end[0]:
|
323
|
+
start, end = end, start
|
324
|
+
start_id, end_id = end_id, start_id
|
325
|
+
|
326
|
+
# Create a new line segment and assign neighbors
|
327
|
+
neighbors_initial = {start_id: start, end_id: end}
|
328
|
+
segment_new = LineSegment(start=start, end=end, id=id, neighbors_initial=neighbors_initial, neighbors=neighbors_initial)
|
329
|
+
|
330
|
+
return segment_new
|
331
|
+
|
332
|
+
def update_data(
|
333
|
+
segments_dict: Dict[int, LineSegment],
|
334
|
+
polygon_arr: Dict[str, Dict[str, object]],
|
335
|
+
polygon_id: str,
|
336
|
+
segment_thickness_dict: Dict[int, Polygon],
|
337
|
+
vertices0: List[Tuple[float, float]],
|
338
|
+
vertices1: List[Tuple[float, float]],
|
339
|
+
vertices2: List[Tuple[float, float]],
|
340
|
+
cycle0: List[int],
|
341
|
+
cycle1: List[int],
|
342
|
+
cycle2: List[int],
|
343
|
+
neighbor1_1: int,
|
344
|
+
neighbor1_2: int,
|
345
|
+
neighbor2_1: int,
|
346
|
+
neighbor2_2: int,
|
347
|
+
vertex_begin_1: Tuple[float, float],
|
348
|
+
vertex_end_1: Tuple[float, float],
|
349
|
+
vertex_begin_2: Tuple[float, float],
|
350
|
+
vertex_end_2: Tuple[float, float],
|
351
|
+
id_1: int,
|
352
|
+
id_2: int
|
353
|
+
) -> Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
|
354
|
+
"""
|
355
|
+
Updates the segments, polygons, and segment thickness dictionaries by adding new data derived
|
356
|
+
from provided vertices and neighbor information.
|
357
|
+
|
358
|
+
Args:
|
359
|
+
segments_dict (Dict[int, LineSegment]): A dictionary of segments with segment ID as the key.
|
360
|
+
polygon_arr (Dict[str, Dict[str, object]]): A dictionary of polygons with polygon ID as the key.
|
361
|
+
polygon_id (str): The ID of the polygon being updated.
|
362
|
+
segment_thickness_dict (Dict[int, Polygon]): A dictionary mapping thickness information to polygon objects.
|
363
|
+
vertices0 (List[Tuple[float, float]]): Vertices of the base polygon.
|
364
|
+
vertices1 (List[Tuple[float, float]]): Vertices of the first new polygon.
|
365
|
+
vertices2 (List[Tuple[float, float]]): Vertices of the second new polygon.
|
366
|
+
cycle0 (List[int]): List of face indices for the base polygon.
|
367
|
+
cycle1 (List[int]): List of face indices for the first new polygon.
|
368
|
+
cycle2 (List[int]): List of face indices for the second new polygon.
|
369
|
+
neighbor1_1 (int): ID of the first neighbor of the first segment.
|
370
|
+
neighbor1_2 (int): ID of the second neighbor of the first segment.
|
371
|
+
neighbor2_1 (int): ID of the first neighbor of the second segment.
|
372
|
+
neighbor2_2 (int): ID of the second neighbor of the second segment.
|
373
|
+
vertex_begin_1 (Tuple[float, float]): Starting vertex of the first segment.
|
374
|
+
vertex_end_1 (Tuple[float, float]): Ending vertex of the first segment.
|
375
|
+
vertex_begin_2 (Tuple[float, float]): Starting vertex of the second segment.
|
376
|
+
vertex_end_2 (Tuple[float, float]): Ending vertex of the second segment.
|
377
|
+
id_1 (int): ID of the first new segment.
|
378
|
+
id_2 (int): ID of the second new segment.
|
379
|
+
|
380
|
+
Returns:
|
381
|
+
Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
|
382
|
+
- Updated dictionary of line segments.
|
383
|
+
- Updated dictionary of polygons.
|
384
|
+
- Updated dictionary of segment thickness.
|
385
|
+
"""
|
386
|
+
|
387
|
+
# Update polygon_arr (a dictionary of polygons)
|
388
|
+
polygon_new_1 = {
|
389
|
+
f'p{len(polygon_arr) + 1}': {
|
390
|
+
'vertices': vertices1,
|
391
|
+
'area': Polygon(vertices=vertices1).area(),
|
392
|
+
'faces': cycle1
|
393
|
+
}
|
394
|
+
}
|
395
|
+
polygon_new_2 = {
|
396
|
+
polygon_id: {
|
397
|
+
'vertices': vertices2,
|
398
|
+
'area': Polygon(vertices=vertices2).area(),
|
399
|
+
'faces': cycle2
|
400
|
+
}
|
401
|
+
}
|
402
|
+
polygon_arr.update(polygon_new_1)
|
403
|
+
polygon_arr.update(polygon_new_2)
|
404
|
+
|
405
|
+
# Update the segments_dict for the first segment
|
406
|
+
neighbors_initial_1 = {
|
407
|
+
neighbor1_1: vertex_begin_1,
|
408
|
+
neighbor1_2: vertex_end_1
|
409
|
+
}
|
410
|
+
segment_new_1 = LineSegment(
|
411
|
+
start=vertex_begin_1,
|
412
|
+
end=vertex_end_1,
|
413
|
+
id=id_1,
|
414
|
+
neighbors_initial=neighbors_initial_1,
|
415
|
+
neighbors=neighbors_initial_1
|
416
|
+
)
|
417
|
+
segments_dict[segment_new_1.id] = segment_new_1
|
418
|
+
segments_dict[neighbor1_1].neighbors[id_1] = vertex_begin_1
|
419
|
+
segments_dict[neighbor1_2].neighbors[id_1] = vertex_end_1
|
420
|
+
|
421
|
+
# Update the segments_dict for the second segment
|
422
|
+
neighbors_initial_2 = {
|
423
|
+
neighbor2_1: vertex_begin_2,
|
424
|
+
neighbor2_2: vertex_end_2
|
425
|
+
}
|
426
|
+
segment_new_2 = LineSegment(
|
427
|
+
start=vertex_begin_2,
|
428
|
+
end=vertex_end_2,
|
429
|
+
id=id_2,
|
430
|
+
neighbors_initial=neighbors_initial_2,
|
431
|
+
neighbors=neighbors_initial_2
|
432
|
+
)
|
433
|
+
segments_dict[segment_new_2.id] = segment_new_2
|
434
|
+
segments_dict[neighbor2_1].neighbors[id_2] = vertex_begin_2
|
435
|
+
segments_dict[neighbor2_2].neighbors[id_2] = vertex_end_2
|
436
|
+
|
437
|
+
# Update the segment_thickness_dict with the base polygon
|
438
|
+
segment_thickness_dict[len(segment_thickness_dict) + 1] = Polygon(vertices=vertices0)
|
439
|
+
|
440
|
+
return segments_dict, polygon_arr, segment_thickness_dict
|
441
|
+
|
442
|
+
def add_line_segment(
|
443
|
+
segments_dict: Dict[int, LineSegment],
|
444
|
+
polygon_arr: Dict[str, Dict[str, object]],
|
445
|
+
segment_thickness_dict: Dict[int, Polygon],
|
446
|
+
angle: float,
|
447
|
+
thickness: float = 0,
|
448
|
+
nucleation_point: Tuple[float, float] = None,
|
449
|
+
min_distance: float = 0,
|
450
|
+
box_size: float = 1,
|
451
|
+
max_attempts: int = 1000
|
452
|
+
) -> Union[Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon], List[float], float], bool]:
|
453
|
+
"""
|
454
|
+
Adds a new line segment to the segments and polygon data structures, with a given thickness and angle distribution.
|
455
|
+
|
456
|
+
Args:
|
457
|
+
segments_dict (Dict[int, LineSegment]): A dictionary containing the current line segments.
|
458
|
+
polygon_arr (Dict[str, Dict[str, object]]): A dictionary containing the current polygons and their properties.
|
459
|
+
segment_thickness_dict (Dict[int, Polygon]): A dictionary storing the thickness information mapped to polygons.
|
460
|
+
thickness (float): The thickness of the new segment to be added. Defaults to 0.
|
461
|
+
angles (str): The angle distribution method. Defaults to 'uniform'.
|
462
|
+
nucleation_point (Tuple[float, float]): A predefined nucleation point for the new segment. Defaults to None.
|
463
|
+
min_distance (float): The minimum distance between two lines. Defaults to 0.
|
464
|
+
box_size (float): The size of the box. Defaults to 1.
|
465
|
+
max_attempts (int): The maximum number of attempts to find a valid location and direction. Defaults to 1000.
|
466
|
+
|
467
|
+
Returns:
|
468
|
+
Union[Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]], List[float], float, bool]:
|
469
|
+
- A tuple containing the updated segments dictionary, polygon dictionary, and thickness dictionary,
|
470
|
+
or False if no valid location for the new segment is found.
|
471
|
+
-nucleation point in a list [x,y] and the angle of the segment in radians.
|
472
|
+
"""
|
473
|
+
|
474
|
+
# Get a valid location and direction, or return False if none is found
|
475
|
+
loc = get_location_and_direction(polygon_arr, angle=angle, thickness=thickness, nucleation_point=nucleation_point, min_distance=min_distance, max_attempts=max_attempts)
|
476
|
+
if loc:
|
477
|
+
polygon_id, polygon, location_new, direction_new, perpendicular, angle_new = loc
|
478
|
+
else:
|
479
|
+
print('No valid location found')
|
480
|
+
return False
|
481
|
+
|
482
|
+
# Get the borders of the new segment with the given thickness
|
483
|
+
line_segments_to_check = [segments_dict[segment] for segment in polygon['faces']]
|
484
|
+
middle_segment = get_new_segment(line_segments_to_check, location=location_new, direction=direction_new, box_size=box_size)
|
485
|
+
s1 = get_new_segment(line_segments_to_check, location=np.array(location_new) + thickness * perpendicular / 2, direction=direction_new,box_size=box_size)
|
486
|
+
s2 = get_new_segment(line_segments_to_check, location=np.array(location_new) - thickness * perpendicular / 2, direction=direction_new, box_size=box_size)
|
487
|
+
|
488
|
+
# Extract neighbor information and segment vertices
|
489
|
+
neighbor1_1, neighbor1_2 = list(s1.neighbors.keys())
|
490
|
+
vertex_begin_1, vertex_end_1 = list(s1.neighbors.values())
|
491
|
+
neighbor2_1, neighbor2_2 = list(s2.neighbors.keys())
|
492
|
+
vertex_begin_2, vertex_end_2 = list(s2.neighbors.values())
|
493
|
+
id_1 = str(int((len(segments_dict.keys()) - 2) / 2)) + '_1'
|
494
|
+
id_2 = str(int((len(segments_dict.keys()) - 2) / 2)) + '_2'
|
495
|
+
|
496
|
+
# Get the resulting polygons after splitting
|
497
|
+
cycle0, vertices0, cycle1, vertices1, cycle2, vertices2 = get_polygons(
|
498
|
+
polygon_id,
|
499
|
+
polygon_arr,
|
500
|
+
neighbor1_1,
|
501
|
+
neighbor1_2,
|
502
|
+
vertex_begin_1,
|
503
|
+
vertex_end_1,
|
504
|
+
neighbor2_1,
|
505
|
+
neighbor2_2,
|
506
|
+
vertex_begin_2=vertex_begin_2,
|
507
|
+
vertex_end_2=vertex_end_2,
|
508
|
+
segment_new_id_1=id_1,
|
509
|
+
segment_new_id_2=id_2
|
510
|
+
)
|
511
|
+
|
512
|
+
# Update all relevant data structures
|
513
|
+
segments_dict, polygon_arr, segment_thickness_dict = update_data(
|
514
|
+
segments_dict,
|
515
|
+
polygon_arr,
|
516
|
+
polygon_id,
|
517
|
+
segment_thickness_dict,
|
518
|
+
vertices0,
|
519
|
+
vertices1,
|
520
|
+
vertices2,
|
521
|
+
cycle0,
|
522
|
+
cycle1,
|
523
|
+
cycle2,
|
524
|
+
neighbor1_1,
|
525
|
+
neighbor1_2,
|
526
|
+
neighbor2_1,
|
527
|
+
neighbor2_2,
|
528
|
+
vertex_begin_1,
|
529
|
+
vertex_end_1,
|
530
|
+
vertex_begin_2,
|
531
|
+
vertex_end_2,
|
532
|
+
id_1,
|
533
|
+
id_2
|
534
|
+
)
|
535
|
+
|
536
|
+
# Associate the middle segment with the newly created thickness entry
|
537
|
+
segment_thickness_dict[list(segment_thickness_dict.keys())[-1]].middle_segment = middle_segment
|
538
|
+
|
539
|
+
return segments_dict, polygon_arr, segment_thickness_dict, location_new, angle_new
|
540
|
+
|
541
|
+
def generate_line_segments_thickness(
|
542
|
+
size: int,
|
543
|
+
thickness_arr: List[float],
|
544
|
+
angles: str = 'uniform',
|
545
|
+
config: List[List[float]] = None,
|
546
|
+
epsilon: float = 0,
|
547
|
+
box_size: float = 1
|
548
|
+
) -> Tuple[Dict[str, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon], np.ndarray]:
|
549
|
+
"""
|
550
|
+
Generates a specified number of line segments and updates the polygon and segment thickness dictionaries.
|
551
|
+
|
552
|
+
Args:
|
553
|
+
size (int): The number of line segments to generate.
|
554
|
+
thickness_arr (List[float]): A list containing the thickness values for each segment to be generated.
|
555
|
+
angles (str): Angle used in the generation of the segments.
|
556
|
+
config (List[List[float]]): A list of configurations for the nucleation points and angles.
|
557
|
+
epsilon (float): the minimum distance between two line.
|
558
|
+
box_size (float): the size of the box.
|
559
|
+
|
560
|
+
Returns:
|
561
|
+
Tuple[Dict[str, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
|
562
|
+
- Updated dictionary of line segments.
|
563
|
+
- Updated dictionary of polygons.
|
564
|
+
- Updated dictionary of segment thicknesses.
|
565
|
+
- Array of the nucleation points and angles [x,y,theta].
|
566
|
+
"""
|
567
|
+
|
568
|
+
# Initialize border segments for a square and its polygon representation
|
569
|
+
borders = [
|
570
|
+
LineSegment((box_size, 0), (0, 0), id='b1', neighbors_initial={'b2': (0, 0), 'b4': (box_size, 0)}, neighbors={'b2': (0, 0), 'b4': (box_size, 0)}),
|
571
|
+
LineSegment((0, box_size), (0, 0), id='b2', neighbors_initial={'b1': (0, 0), 'b3': (0, box_size)}, neighbors={'b1': (0, 0), 'b3': (0, box_size)}),
|
572
|
+
LineSegment((0, box_size), (box_size, box_size), id='b3', neighbors_initial={'b2': (0, box_size), 'b4': (box_size, box_size)}, neighbors={'b2': (0, box_size), 'b4': (box_size, box_size)}),
|
573
|
+
LineSegment((box_size, box_size), (box_size, 0), id='b4', neighbors_initial={'b1': (box_size, 0), 'b3': (box_size, box_size)}, neighbors={'b1': (box_size, 0), 'b3': (box_size, box_size)})
|
574
|
+
]
|
575
|
+
|
576
|
+
polygon_arr = {
|
577
|
+
'p1': {
|
578
|
+
'vertices': [(0, 0), (0, box_size), (box_size, box_size), (box_size, 0)],
|
579
|
+
'area': box_size**2,
|
580
|
+
'faces': ['b1', 'b2', 'b3', 'b4']
|
581
|
+
}
|
582
|
+
}
|
583
|
+
|
584
|
+
segments = borders
|
585
|
+
segments_dict = {segment.id: segment for segment in segments}
|
586
|
+
segment_thickness_dict = {}
|
587
|
+
generated_config = []
|
588
|
+
|
589
|
+
if config is not None and size > len(config):
|
590
|
+
print("The size of the configuration is smaller than the size of the segments. Generated a network of the same size as the configuration.")
|
591
|
+
size = len(config)
|
592
|
+
|
593
|
+
jammed = False
|
594
|
+
for i in range(size):
|
595
|
+
if config:
|
596
|
+
nucleation_point = config[i]['location']
|
597
|
+
angles = [config[i]['angle']]
|
598
|
+
else:
|
599
|
+
nucleation_point = None
|
600
|
+
# if angles != 'uniform':
|
601
|
+
# angles=[angles[i]]
|
602
|
+
|
603
|
+
output = add_line_segment(segments_dict,
|
604
|
+
polygon_arr,
|
605
|
+
segment_thickness_dict,
|
606
|
+
thickness=thickness_arr[i],
|
607
|
+
min_distance = epsilon,
|
608
|
+
nucleation_point = nucleation_point,
|
609
|
+
angle=angles[i],
|
610
|
+
box_size=box_size)
|
611
|
+
if output:
|
612
|
+
segments_dict, polygon_arr, segment_thickness_dict, location, angle = output
|
613
|
+
generated_config.append({ 'location': location, 'angle': angle, 'thickness': thickness_arr[i] })
|
614
|
+
|
615
|
+
else:
|
616
|
+
if config:
|
617
|
+
print('Configuration not possible. Point is skipped.')
|
618
|
+
else:
|
619
|
+
print(f"Stopped at iteration {len(segment_thickness_dict)}, could not find a valid segment position.")
|
620
|
+
jammed = True
|
621
|
+
break
|
622
|
+
|
623
|
+
# Uncomment the following line if you want progress feedback
|
624
|
+
percentage = np.round(i / size * 100, 3)
|
625
|
+
print(f'generate_segments: {percentage}% done', end='\r')
|
626
|
+
|
627
|
+
data_dict = {'segments_dict': segments_dict,
|
628
|
+
'polygon_arr': polygon_arr,
|
629
|
+
'segment_thickness_dict': segment_thickness_dict,
|
630
|
+
'jammed': jammed,
|
631
|
+
'generated_config': generated_config}
|
632
|
+
|
633
|
+
return data_dict
|
@@ -170,7 +170,7 @@ def rotate_network(
|
|
170
170
|
middle_segment_new = LineSegment(start=start, end=end)
|
171
171
|
|
172
172
|
# Store the rotated segment in the new dictionary
|
173
|
-
segment_thickness_dict_new[id] = Polygon(vertices=vertices_new, middle_segment=middle_segment_new)
|
173
|
+
segment_thickness_dict_new[id] = Polygon(vertices=vertices_new, middle_segment=middle_segment_new, neighbors=segment.neighbors)
|
174
174
|
|
175
175
|
return segment_thickness_dict_new
|
176
176
|
|
@@ -237,7 +237,7 @@ def clip_network(
|
|
237
237
|
middle_segment_new = LineSegment(start=start, end=end)
|
238
238
|
|
239
239
|
# Create a new clipped polygon with updated vertices and middle segment
|
240
|
-
pol_new = Polygon(vertices=vertices_new, middle_segment=middle_segment_new)
|
240
|
+
pol_new = Polygon(vertices=vertices_new, middle_segment=middle_segment_new, neighbors=segment.neighbors)
|
241
241
|
pol_new.sort_vertices() # Ensure vertices are sorted
|
242
242
|
segment_thickness_dict_new[id] = pol_new
|
243
243
|
|
@@ -285,7 +285,7 @@ def translate_network(
|
|
285
285
|
middle_segment_new = LineSegment(start=start, end=end)
|
286
286
|
|
287
287
|
# Store the translated segment in the new dictionary
|
288
|
-
segment_thickness_dict_new[id] = Polygon(vertices=vertices_new, middle_segment=middle_segment_new)
|
288
|
+
segment_thickness_dict_new[id] = Polygon(vertices=vertices_new, middle_segment=middle_segment_new, neighbors=segment.neighbors)
|
289
289
|
|
290
290
|
return segment_thickness_dict_new
|
291
291
|
|
File without changes
|
File without changes
|
File without changes
|