RDG-Networks 0.3.2__tar.gz → 0.3.4__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {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
|