RDG-Networks 0.3.2__tar.gz → 0.3.4__tar.gz
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.2 → rdg_networks-0.3.4}/PKG-INFO +1 -1
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/PKG-INFO +1 -1
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/SOURCES.txt +0 -1
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/thickness/generate_line_segments_dynamic_thickness.py +10 -9
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/setup.py +1 -1
- rdg_networks-0.3.2/RDG_networks/thickness/functions.py +0 -255
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/LICENSE.txt +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/dependency_links.txt +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/entry_points.txt +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/requires.txt +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_Networks.egg-info/top_level.txt +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/Classes.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/__init__.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/draw_segments.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/generate_line_network.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/generate_line_segments.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/generate_line_segments_dynamic.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/generate_line_segments_static.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/get_intersection_segments.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/sample_in_polygon.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/thickness/Classes.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/thickness/__init__.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/RDG_networks/thickness/sample_in_polygon.py +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/README.md +0 -0
- {rdg_networks-0.3.2 → rdg_networks-0.3.4}/setup.cfg +0 -0
@@ -18,6 +18,5 @@ RDG_networks/get_intersection_segments.py
|
|
18
18
|
RDG_networks/sample_in_polygon.py
|
19
19
|
RDG_networks/thickness/Classes.py
|
20
20
|
RDG_networks/thickness/__init__.py
|
21
|
-
RDG_networks/thickness/functions.py
|
22
21
|
RDG_networks/thickness/generate_line_segments_dynamic_thickness.py
|
23
22
|
RDG_networks/thickness/sample_in_polygon.py
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import math
|
2
2
|
import numpy as np
|
3
|
+
import random
|
3
4
|
from typing import List, Dict, Tuple, Union, Optional
|
4
5
|
|
5
|
-
from .Classes import Line, LineSegment
|
6
|
+
from .Classes import Line, LineSegment, Polygon
|
6
7
|
from .sample_in_polygon import sample_in_polygon, is_inside_polygon
|
7
8
|
|
8
9
|
def doLinesIntersect(line1: Line, line2: Line) -> Tuple[bool, Union[Tuple[float, float], None]]:
|
@@ -40,8 +41,8 @@ def doLinesIntersect(line1: Line, line2: Line) -> Tuple[bool, Union[Tuple[float,
|
|
40
41
|
return False, (None, None)
|
41
42
|
|
42
43
|
def doSegmentsIntersect(
|
43
|
-
segment1:
|
44
|
-
segment2:
|
44
|
+
segment1: LineSegment,
|
45
|
+
segment2: LineSegment
|
45
46
|
) -> Tuple[bool, Tuple[Optional[float], Optional[float]]]:
|
46
47
|
"""
|
47
48
|
Determines if two line segments intersect and returns the intersection point if they do.
|
@@ -255,7 +256,7 @@ def get_polygons(polygon_id, polygon_arr, neighbor1_1, neighbor1_2, vertex_begin
|
|
255
256
|
return cycle0, vertices0, cycle1, vertices1, cycle2, vertices2
|
256
257
|
|
257
258
|
def get_new_segment(
|
258
|
-
line_segments_to_check: List[
|
259
|
+
line_segments_to_check: List[LineSegment],
|
259
260
|
location: Tuple[float, float],
|
260
261
|
direction: Tuple[float, float],
|
261
262
|
id: Optional[int] = None
|
@@ -337,7 +338,7 @@ def update_data(
|
|
337
338
|
vertex_end_2: Tuple[float, float],
|
338
339
|
id_1: int,
|
339
340
|
id_2: int
|
340
|
-
) -> Tuple[Dict[int,
|
341
|
+
) -> Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
|
341
342
|
"""
|
342
343
|
Updates the segments, polygons, and segment thickness dictionaries by adding new data derived
|
343
344
|
from provided vertices and neighbor information.
|
@@ -427,12 +428,12 @@ def update_data(
|
|
427
428
|
return segments_dict, polygon_arr, segment_thickness_dict
|
428
429
|
|
429
430
|
def add_line_segment(
|
430
|
-
segments_dict: Dict[int,
|
431
|
+
segments_dict: Dict[int, LineSegment],
|
431
432
|
polygon_arr: Dict[str, Dict[str, object]],
|
432
|
-
segment_thickness_dict: Dict[int,
|
433
|
+
segment_thickness_dict: Dict[int, Polygon],
|
433
434
|
thickness: float = 0,
|
434
435
|
angles: str = 'uniform'
|
435
|
-
) -> Union[Tuple[Dict[int,
|
436
|
+
) -> Union[Tuple[Dict[int, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]], bool]:
|
436
437
|
"""
|
437
438
|
Adds a new line segment to the segments and polygon data structures, with a given thickness and angle distribution.
|
438
439
|
|
@@ -520,7 +521,7 @@ def generate_line_segments_dynamic_thickness(
|
|
520
521
|
size: int,
|
521
522
|
thickness_arr: List[float],
|
522
523
|
angles: str = 'uniform'
|
523
|
-
) -> Tuple[Dict[str,
|
524
|
+
) -> Tuple[Dict[str, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
|
524
525
|
"""
|
525
526
|
Generates a specified number of line segments and updates the polygon and segment thickness dictionaries.
|
526
527
|
|
@@ -1,255 +0,0 @@
|
|
1
|
-
import numpy as np
|
2
|
-
import random
|
3
|
-
from typing import List, Dict, Tuple, Union, Optional
|
4
|
-
|
5
|
-
from .Classes import Line, LineSegment
|
6
|
-
from .sample_in_polygon import sample_in_polygon, is_inside_polygon
|
7
|
-
|
8
|
-
def doLinesIntersect(line1: Line, line2: Line) -> Tuple[bool, Union[Tuple[float, float], None]]:
|
9
|
-
"""
|
10
|
-
Check if two lines intersect and return the intersection point.
|
11
|
-
|
12
|
-
Args:
|
13
|
-
- line1 (Line): The first line segment.
|
14
|
-
- line2 (Line): The second line segment.
|
15
|
-
|
16
|
-
Returns:
|
17
|
-
- intersect (bool): True if the lines intersect, False otherwise.
|
18
|
-
- intersection_point (tuple or None): The intersection point (x, y) if lines intersect, None otherwise.
|
19
|
-
"""
|
20
|
-
x1, y1 = line1.location
|
21
|
-
v1, w1 = line1.direction
|
22
|
-
|
23
|
-
x2, y2 = line2.location
|
24
|
-
v2, w2 = line2.direction
|
25
|
-
|
26
|
-
determinant = v1 * w2 - v2 * w1
|
27
|
-
|
28
|
-
if determinant == 0:
|
29
|
-
return False, (None, None)
|
30
|
-
|
31
|
-
t1 = ((x2 - x1) * w2 - (y2 - y1) * v2) / determinant
|
32
|
-
t2 = ((x2 - x1) * w1 - (y2 - y1) * v1) / determinant
|
33
|
-
|
34
|
-
intersect_x = x1 + v1 * t1
|
35
|
-
intersect_y = y2 + w2 * t2
|
36
|
-
|
37
|
-
if -1e-6 < intersect_x < 1 + 1e-6 and -1e-6 < intersect_y < 1 + 1e-6:
|
38
|
-
return True, (intersect_x, intersect_y)
|
39
|
-
else:
|
40
|
-
return False, (None, None)
|
41
|
-
|
42
|
-
def doSegmentsIntersect(
|
43
|
-
segment1: 'LineSegment',
|
44
|
-
segment2: 'LineSegment'
|
45
|
-
) -> Tuple[bool, Tuple[Optional[float], Optional[float]]]:
|
46
|
-
"""
|
47
|
-
Determines if two line segments intersect and returns the intersection point if they do.
|
48
|
-
|
49
|
-
Args:
|
50
|
-
segment1 (LineSegment): The first line segment.
|
51
|
-
segment2 (LineSegment): The second line segment.
|
52
|
-
|
53
|
-
Returns:
|
54
|
-
Tuple[bool, Tuple[Optional[float], Optional[float]]]:
|
55
|
-
- A boolean indicating whether the segments intersect.
|
56
|
-
- A tuple of the x and y coordinates of the intersection point if they intersect,
|
57
|
-
otherwise (None, None).
|
58
|
-
"""
|
59
|
-
|
60
|
-
# Create line equations based on the segments' start and end points
|
61
|
-
line1 = Line(location=segment1.start, direction=np.array(segment1.end) - np.array(segment1.start))
|
62
|
-
line2 = Line(location=segment2.start, direction=np.array(segment2.end) - np.array(segment2.start))
|
63
|
-
|
64
|
-
# Check if the infinite extensions of the two lines intersect
|
65
|
-
intersect, (intersect_x, intersect_y) = doLinesIntersect(line1, line2)
|
66
|
-
|
67
|
-
# If no intersection, return False
|
68
|
-
if not intersect:
|
69
|
-
return False, (None, None)
|
70
|
-
|
71
|
-
# Check if the intersection point is within the bounds of both segments in the x-direction
|
72
|
-
xcheck = (
|
73
|
-
(segment1.end[0] <= intersect_x <= segment1.start[0]
|
74
|
-
or segment1.start[0] <= intersect_x <= segment1.end[0]
|
75
|
-
or abs(intersect_x - segment1.end[0]) < 1e-6
|
76
|
-
or abs(intersect_x - segment1.start[0]) < 1e-6)
|
77
|
-
and
|
78
|
-
(segment2.end[0] <= intersect_x <= segment2.start[0]
|
79
|
-
or segment2.start[0] <= intersect_x <= segment2.end[0]
|
80
|
-
or abs(intersect_x - segment2.end[0]) < 1e-6
|
81
|
-
or abs(intersect_x - segment2.start[0]) < 1e-6)
|
82
|
-
)
|
83
|
-
|
84
|
-
# Check if the intersection point is within the bounds of both segments in the y-direction
|
85
|
-
ycheck = (
|
86
|
-
(segment1.end[1] <= intersect_y <= segment1.start[1]
|
87
|
-
or segment1.start[1] <= intersect_y <= segment1.end[1]
|
88
|
-
or abs(intersect_y - segment1.end[1]) < 1e-6
|
89
|
-
or abs(intersect_y - segment1.start[1]) < 1e-6)
|
90
|
-
and
|
91
|
-
(segment2.end[1] <= intersect_y <= segment2.start[1]
|
92
|
-
or segment2.start[1] <= intersect_y <= segment2.end[1]
|
93
|
-
or abs(intersect_y - segment2.end[1]) < 1e-6
|
94
|
-
or abs(intersect_y - segment2.start[1]) < 1e-6)
|
95
|
-
)
|
96
|
-
|
97
|
-
# If the intersection point lies within the bounds of both segments, return True with the intersection point
|
98
|
-
if xcheck and ycheck:
|
99
|
-
return True, (intersect_x, intersect_y)
|
100
|
-
|
101
|
-
# Otherwise, return False and no intersection point
|
102
|
-
return False, (None, None)
|
103
|
-
|
104
|
-
def pick_item_with_probability(
|
105
|
-
polygon_arr: Dict[str, Dict[str, object]]
|
106
|
-
) -> Tuple[str, Dict[str, object]]:
|
107
|
-
"""
|
108
|
-
Randomly selects an item from the polygon array with a probability proportional to the area of the polygons.
|
109
|
-
|
110
|
-
Args:
|
111
|
-
polygon_arr (Dict[str, Dict[str, object]]):
|
112
|
-
A dictionary where keys are polygon identifiers (e.g., 'p1', 'p2') and values are dictionaries containing polygon properties,
|
113
|
-
including an 'area' key that stores the area of the polygon.
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
Tuple[str, Dict[str, object]]:
|
117
|
-
- The identifier of the selected polygon.
|
118
|
-
- The corresponding polygon data (dictionary) containing its properties.
|
119
|
-
"""
|
120
|
-
|
121
|
-
# Calculate the total weight (sum of areas of all polygons)
|
122
|
-
max_weight = sum(pol['area'] for pol in polygon_arr.values())
|
123
|
-
|
124
|
-
# Generate a random threshold between 0 and the total weight
|
125
|
-
threshold = random.uniform(0, max_weight)
|
126
|
-
cumulative_weight = 0
|
127
|
-
|
128
|
-
# Iterate through the polygons, accumulating weights
|
129
|
-
for item, pol in polygon_arr.items():
|
130
|
-
weight = pol['area']
|
131
|
-
cumulative_weight += weight
|
132
|
-
|
133
|
-
# Return the polygon when the cumulative weight surpasses the threshold
|
134
|
-
if cumulative_weight >= threshold:
|
135
|
-
return item, pol
|
136
|
-
|
137
|
-
def get_location_and_direction(
|
138
|
-
polygon_arr: Dict[str, Dict[str, object]],
|
139
|
-
thickness: float,
|
140
|
-
max_attempts: int = 1000,
|
141
|
-
angles: Union[str, List[float]] = 'uniform'
|
142
|
-
) -> Union[Tuple[str, Dict[str, object], Tuple[float, float], np.ndarray, np.ndarray], bool]:
|
143
|
-
"""
|
144
|
-
Attempts to find a valid location and direction within a polygon for placing a new segment. The direction can either be randomly
|
145
|
-
chosen (uniformly) or from a specified list of angles. It ensures that the segment lies within the polygon's bounds given the
|
146
|
-
specified thickness.
|
147
|
-
|
148
|
-
Args:
|
149
|
-
polygon_arr (Dict[str, Dict[str, object]]):
|
150
|
-
A dictionary where the keys are polygon identifiers and the values are dictionaries containing polygon properties, including 'vertices'.
|
151
|
-
thickness (float):
|
152
|
-
The thickness of the segment that needs to fit inside the polygon.
|
153
|
-
max_attempts (int, optional):
|
154
|
-
The maximum number of attempts to find a valid location and direction. Defaults to 1000.
|
155
|
-
angles (Union[str, List[float]], optional):
|
156
|
-
A string ('uniform' for random directions) or a list of angles (in radians) to choose the direction from. Defaults to 'uniform'.
|
157
|
-
|
158
|
-
Returns:
|
159
|
-
Union[Tuple[str, Dict[str, object], Tuple[float, float], np.ndarray, np.ndarray], bool]:
|
160
|
-
- If a valid location and direction are found, returns a tuple containing:
|
161
|
-
- The polygon ID (`str`).
|
162
|
-
- The polygon data (`Dict[str, object]`).
|
163
|
-
- The new location as a tuple of floats (`Tuple[float, float]`).
|
164
|
-
- The direction vector as a numpy array (`np.ndarray`).
|
165
|
-
- The perpendicular vector to the direction as a numpy array (`np.ndarray`).
|
166
|
-
- Returns `False` if no valid location and direction are found after the maximum attempts.
|
167
|
-
"""
|
168
|
-
|
169
|
-
# Generate a new direction based on the angles parameter
|
170
|
-
if angles == 'uniform':
|
171
|
-
direction = np.array([random.uniform(-1, 1), random.uniform(-1, 1)])
|
172
|
-
direction = direction / np.linalg.norm(direction) # Normalize the direction vector
|
173
|
-
else:
|
174
|
-
directions = [ (np.cos(angle), np.sin(angle)) for angle in angles ]
|
175
|
-
direction = random.choice(directions)
|
176
|
-
direction = np.array(direction) / np.linalg.norm(direction) # Normalize the chosen direction
|
177
|
-
|
178
|
-
# Try to find a valid location and direction up to max_attempts
|
179
|
-
attempt = 0
|
180
|
-
while attempt < max_attempts:
|
181
|
-
polygon_id, polygon = pick_item_with_probability(polygon_arr)
|
182
|
-
|
183
|
-
# Sample a location within the polygon
|
184
|
-
location_new = sample_in_polygon(polygon['vertices'])
|
185
|
-
|
186
|
-
# Compute the perpendicular vector to the direction
|
187
|
-
perpendicular = np.array([direction[1], -direction[0]])
|
188
|
-
perpendicular = perpendicular / np.linalg.norm(perpendicular)
|
189
|
-
|
190
|
-
# Ensure the perpendicular vector is oriented consistently (y-component is non-negative)
|
191
|
-
if perpendicular[1] < 0:
|
192
|
-
perpendicular = -perpendicular
|
193
|
-
|
194
|
-
# Compute the positions for the segment with thickness, shifted by half-thickness along the perpendicular direction
|
195
|
-
p1 = np.array(location_new) + thickness / 2 * perpendicular
|
196
|
-
p2 = np.array(location_new) - thickness / 2 * perpendicular
|
197
|
-
|
198
|
-
# Check if both endpoints of the segment are inside the polygon
|
199
|
-
if is_inside_polygon(polygon['vertices'], p1) and is_inside_polygon(polygon['vertices'], p2):
|
200
|
-
return polygon_id, polygon, location_new, direction, perpendicular
|
201
|
-
|
202
|
-
attempt += 1
|
203
|
-
|
204
|
-
# If no valid location and direction is found, return False
|
205
|
-
return False
|
206
|
-
|
207
|
-
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):
|
208
|
-
# Extract vertices and cycle (faces) of the original polygon
|
209
|
-
vertices = polygon_arr[polygon_id]['vertices']
|
210
|
-
cycle = polygon_arr[polygon_id]['faces']
|
211
|
-
|
212
|
-
# Get first cycle and vertices
|
213
|
-
index_start_1, index_end_1 = (cycle.index(neighbor1_1), cycle.index(neighbor1_2))
|
214
|
-
if index_start_1 < index_end_1:
|
215
|
-
cycle1 = [segment_new_id_1] + cycle[index_start_1:index_end_1+1]
|
216
|
-
vertices1 = [vertex_begin_1] + vertices[index_start_1:index_end_1] + [vertex_end_1]
|
217
|
-
else:
|
218
|
-
cycle1 = [segment_new_id_1] + cycle[index_start_1:] + cycle[:index_end_1+1]
|
219
|
-
vertices1 = [vertex_begin_1] + vertices[index_start_1:] + vertices[:index_end_1] + [vertex_end_1]
|
220
|
-
|
221
|
-
# Get second cycle and vertices
|
222
|
-
index_start_2, index_end_2 = (cycle.index(neighbor2_2), cycle.index(neighbor2_1))
|
223
|
-
if index_start_2 < index_end_2:
|
224
|
-
cycle2 = [segment_new_id_2] + cycle[index_start_2:index_end_2+1]
|
225
|
-
vertices2 = [vertex_end_2] + vertices[index_start_2:index_end_2] + [vertex_begin_2]
|
226
|
-
else:
|
227
|
-
cycle2 = [segment_new_id_2] + cycle[index_start_2:] + cycle[:index_end_2+1]
|
228
|
-
vertices2 = [vertex_end_2] + vertices[index_start_2:] + vertices[:index_end_2] + [vertex_begin_2]
|
229
|
-
|
230
|
-
# Get middle cycle and vertices
|
231
|
-
cycle0 = [neighbor1_1, segment_new_id_1, neighbor1_2]
|
232
|
-
vertices0 = [vertex_begin_1, vertex_end_1]
|
233
|
-
|
234
|
-
index_start_0, index_end_0 = (cycle.index(neighbor1_2), cycle.index(neighbor2_2))
|
235
|
-
if index_start_0 < index_end_0:
|
236
|
-
cycle0 = cycle0 + cycle[index_start_0:index_end_0+1]
|
237
|
-
vertices0 = vertices0 + vertices[index_start_0:index_end_0]
|
238
|
-
|
239
|
-
elif index_start_0 > index_end_0:
|
240
|
-
cycle0 = cycle0 + cycle[index_start_0:] + cycle[:index_end_0+1]
|
241
|
-
vertices0 = vertices0 + vertices[index_start_0:] + vertices[:index_end_0]
|
242
|
-
|
243
|
-
cycle0 = cycle0 + [segment_new_id_2]
|
244
|
-
vertices0 = vertices0 + [vertex_end_2] + [vertex_begin_2]
|
245
|
-
|
246
|
-
index_start_0, index_end_0 = (cycle.index(neighbor2_1), cycle.index(neighbor1_1))
|
247
|
-
if index_start_0 < index_end_0:
|
248
|
-
cycle0 = cycle0 + cycle[index_start_0:index_end_0+1]
|
249
|
-
vertices0 = vertices0 + vertices[index_start_0:index_end_0]
|
250
|
-
|
251
|
-
elif index_start_0 > index_end_0:
|
252
|
-
cycle0 = cycle0 + cycle[index_start_0:] + cycle[:index_end_0+1]
|
253
|
-
vertices0 = vertices0 + vertices[index_start_0:] + vertices[:index_end_0]
|
254
|
-
|
255
|
-
return cycle0, vertices0, cycle1, vertices1, cycle2, vertices2
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|