RDG-Networks 0.3.6__py3-none-any.whl → 0.3.8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: RDG-Networks
3
- Version: 0.3.6
3
+ Version: 0.3.8
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
@@ -1,5 +1,5 @@
1
1
  RDG_networks/Classes.py,sha256=_9X3JPHFAYYlaC8IZ_H9__sfz99G5l9UfPl65lL60_4,7977
2
- RDG_networks/__init__.py,sha256=SmpD26lMaZ3wPz2Hs2Z-24AJiEU5DbNldhQt1fZxI0U,1607
2
+ RDG_networks/__init__.py,sha256=8cc-h5ifS7RP1-N4b1Ow-4bA6MxgFETaS6SD0of54Fk,1575
3
3
  RDG_networks/draw_segments.py,sha256=U53N5GXmQHWKdM1Q1faP_EGKjc6enOu2mcsunzSFpP0,984
4
4
  RDG_networks/generate_line_network.py,sha256=lJ4rhObim3WcEQoebomewRQKWNJC5phFyFYRW7qjXIg,1127
5
5
  RDG_networks/generate_line_segments.py,sha256=QV8_k7q6TD5c7Hcb2Ms_apEdWYw4XdLr7rdJgh49v4Q,9004
@@ -7,16 +7,16 @@ RDG_networks/generate_line_segments_dynamic.py,sha256=GoIhGXYbcvjqR5BJCnkvAGp8QB
7
7
  RDG_networks/generate_line_segments_static.py,sha256=7KvHZi3krv-tAGydJR_gbMMmHKZ5azzrKcQe3fuWzCE,9265
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
- RDG_networks/save_to_stl.py,sha256=xHwuoG39cbemggoIjT44DlsMlhjlV3uxTWo6gcHEePA,3414
10
+ RDG_networks/save_to_stl.py,sha256=St8kGw6wl8uOGx8KhrZhBfe89-mOfp5JKhz0dEDBvc0,3894
11
11
  RDG_networks/thickness/Classes.py,sha256=gVe_q5Rh_1DBiJoZ8H0FyJ4xG-IAcespjUpUirxFfAA,8125
12
- RDG_networks/thickness/__init__.py,sha256=87hNJsP1c-4y5QqZVM0bDcVn2cWoNd23Da3_Dvy7Fno,745
13
- RDG_networks/thickness/generate_line_segments_thickness.py,sha256=4SJn2_ScMKNSbHWFCSQCInCWRTo08AUiobAFxasFEKI,29190
14
- RDG_networks/thickness/generate_line_segments_thickness_orientation backup.py,sha256=5gcStrs4SNLp17tFb9XsN4TLWpOaeu0cHteEedISs5E,8204
15
- RDG_networks/thickness/generate_line_segments_thickness_orientation.py,sha256=oTEwQkXRBuoHvEdIGU30p21e2QHW1UlmApzRO1s5c64,16821
12
+ RDG_networks/thickness/__init__.py,sha256=DzH-mmdrk5e1LL7oq5kg0xaDjtWR7DiCeKKchArHSIs,703
13
+ RDG_networks/thickness/generate_line_segments_thickness.py,sha256=rvvqEMGYX7imosKedyXHyTkBV4C2_24K8UxthXDTe7Q,28627
14
+ RDG_networks/thickness/generate_line_segments_thickness_static.py,sha256=6-2p4GOQFU-dP5Q9nYuaVqeb7wvxk2Fqld3A7cV2pY8,8964
15
+ RDG_networks/thickness/orientate_network.py,sha256=hSUVftAC_1GO2K9WMyDsNt_NZHQHf6Ubtu7fXnmz03A,15397
16
16
  RDG_networks/thickness/sample_in_polygon.py,sha256=nJ-yqfoCCGfC6_EpGL3L1t1LOYdqWZd-7v5bxy6th34,1849
17
- RDG_Networks-0.3.6.dist-info/LICENSE.txt,sha256=BHUkX2GsdTr30sKmVZ1MLGR1njnx17EX_oUuuSVZZPE,598
18
- RDG_Networks-0.3.6.dist-info/METADATA,sha256=wGZdZ1ZiKAB4gHxXv3WosChSNoaZ2FFKjbfAIog92Dw,2422
19
- RDG_Networks-0.3.6.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
20
- RDG_Networks-0.3.6.dist-info/entry_points.txt,sha256=g8LC0VSpouLfaeL08Wqn31Pm3K74h4DfkD39C9Fr120,938
21
- RDG_Networks-0.3.6.dist-info/top_level.txt,sha256=4gUUYafD5Al9V8ZSiViVGYHpRMMCsCBcGgCNodk9Syg,13
22
- RDG_Networks-0.3.6.dist-info/RECORD,,
17
+ RDG_Networks-0.3.8.dist-info/LICENSE.txt,sha256=BHUkX2GsdTr30sKmVZ1MLGR1njnx17EX_oUuuSVZZPE,598
18
+ RDG_Networks-0.3.8.dist-info/METADATA,sha256=fHQBJCaoAA6ybZbW5-z3Vrglx1qHnmof7iE-p8tAmic,2422
19
+ RDG_Networks-0.3.8.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
20
+ RDG_Networks-0.3.8.dist-info/entry_points.txt,sha256=coqOWe9rYYuz9VQvJGFomTzvEP7JY5T9V9gauMhSb_0,986
21
+ RDG_Networks-0.3.8.dist-info/top_level.txt,sha256=4gUUYafD5Al9V8ZSiViVGYHpRMMCsCBcGgCNodk9Syg,13
22
+ RDG_Networks-0.3.8.dist-info/RECORD,,
@@ -6,9 +6,10 @@ generate_line_segments = RDG_networks.generate_line_segments:main
6
6
  generate_line_segments_dynamic = RDG_networks.generate_line_segments_dynamic:main
7
7
  generate_line_segments_static = RDG_networks.generate_line_segments_static:main
8
8
  generate_line_segments_thickness = RDG_networks.thickness.generate_line_segments_thickness:main
9
- generate_line_segments_thickness_orientation = RDG_networks.thickness.generate_line_segments_dynamic_orientation:main
9
+ generate_line_segments_thickness_static = RDG_networks.generate_line_segments_thickness_static:main
10
10
  get_alignment_mean = RDG_networks.thickness.get_alignment_mean:main
11
11
  get_intersection_segments = RDG_networks.get_intersection_segments:main
12
+ orientate_network = RDG_networks.thickness.orientate_network:main
12
13
  rotate_network = RDG_networks.thickness.rotate_network:main
13
14
  save_to_stl = RDG_networks.save_to_stl:main
14
15
  translate_network = RDG_networks.thickness.translate_network:main
RDG_networks/__init__.py CHANGED
@@ -8,22 +8,24 @@ from .generate_line_segments_dynamic import generate_line_segments_dynamic
8
8
  from .generate_line_segments_static import generate_line_segments_static
9
9
  from .draw_segments import draw_segments
10
10
  from .thickness.generate_line_segments_thickness import generate_line_segments_thickness
11
- from .thickness.generate_line_segments_thickness_orientation import generate_line_segments_thickness_orientation
12
- from .thickness.generate_line_segments_thickness_orientation import translate_network
13
- from .thickness.generate_line_segments_thickness_orientation import clip_network
14
- from .thickness.generate_line_segments_thickness_orientation import rotate_network
15
- from .thickness.generate_line_segments_thickness_orientation import get_alignment_mean
11
+ from .thickness.orientate_network import orientate_network
12
+ from .thickness.generate_line_segments_thickness_static import generate_line_segments_thickness_static
13
+ from .thickness.orientate_network import translate_network
14
+ from .thickness.orientate_network import clip_network
15
+ from .thickness.orientate_network import rotate_network
16
+ from .thickness.orientate_network import get_alignment_mean
16
17
  from .save_to_stl import save_to_stl
17
18
 
18
19
  __all__ = ['generate_line_segments',
19
20
  'generate_line_segments_thickness',
20
- 'generate_line_segments_thickness_orientation',
21
+ 'orientate_network',
21
22
  'translate_network',
22
23
  'clip_network',
23
24
  'rotate_network',
24
25
  'get_alignment_mean',
25
- 'generate_line_segments_dynamic',
26
26
  'generate_line_segments_static',
27
+ 'generate_line_segments_thickness_static',
28
+ 'generate_line_segments_dynamic',
27
29
  'generate_line_network',
28
30
  'get_intersection_segments',
29
31
  'draw_segments',
@@ -87,7 +87,7 @@ def merge_3d_meshes(mesh_list):
87
87
 
88
88
  return merged_mesh
89
89
 
90
- def save_to_stl(seg_thick_dict, thickness, name):
90
+ def save_to_stl(seg_thick_dict, thickness, name, frame_thickness = None):
91
91
  mesh_list = []
92
92
  for k,v in seg_thick_dict.items():
93
93
  p = []
@@ -98,6 +98,18 @@ def save_to_stl(seg_thick_dict, thickness, name):
98
98
  None
99
99
 
100
100
  mesh_list.append(polygon_to_3d_mesh(Polygon(p), thickness=thickness))
101
+
102
+ if frame_thickness != None:
103
+ t = frame_thickness
104
+ bottom = Polygon([ (0,0-t), (0,0),(1,0),(1,0-t)])
105
+ top = Polygon([(0,1),(0,1+t), (1,1+t), (1,1)])
106
+ right = Polygon([(1,0-t), (1,1+t), (1+t,1+t), (1+t,0-t)])
107
+ left = Polygon([(0-t,0-t),(0-t,1+t), (0,1+t), (0,0-t)])
108
+
109
+ f = [bottom,top, right, left]
110
+
111
+ for f_ in f:
112
+ mesh_list.append(polygon_to_3d_mesh(f_, thickness=thickness))
101
113
 
102
114
  merged_mesh = merge_3d_meshes(mesh_list)
103
115
 
@@ -1,15 +1,17 @@
1
1
  # __init__.py
2
2
 
3
3
  from .generate_line_segments_thickness import generate_line_segments_thickness
4
- from .generate_line_segments_thickness_orientation import generate_line_segments_thickness_orientation
5
- from .generate_line_segments_thickness_orientation import translate_network
6
- from .generate_line_segments_thickness_orientation import clip_network
7
- from .generate_line_segments_thickness_orientation import rotate_network
8
- from .generate_line_segments_thickness_orientation import get_alignment_mean
4
+ from .orientate_network import orientate_network
5
+ from .generate_line_segments_thickness_static import generate_line_segments_thickness_static
6
+ from .orientate_network import translate_network
7
+ from .orientate_network import clip_network
8
+ from .orientate_network import rotate_network
9
+ from .orientate_network import get_alignment_mean
9
10
 
10
11
  __all__ = [
11
12
  'generate_line_segments_thickness',
12
- 'generate_line_segments_thickness_orientation',
13
+ 'orientate_network',
14
+ 'generate_line_segments_thickness_static',
13
15
  'translate_network',
14
16
  'clip_network',
15
17
  'rotate_network',
@@ -142,10 +142,10 @@ def pick_item_with_probability(
142
142
  def get_location_and_direction(
143
143
  polygon_arr: Dict[str, Dict[str, object]],
144
144
  thickness: float,
145
+ angle: float,
145
146
  nucleation_point: Tuple[float, float] = None,
146
147
  min_distance: float = 0,
147
- max_attempts: int = 1000,
148
- angles: Union[str, List[float]] = 'uniform'
148
+ max_attempts: int = 1000
149
149
  ) -> Union[Tuple[str, Dict[str, object], Tuple[float, float], np.ndarray, np.ndarray], bool]:
150
150
  """
151
151
  Attempts to find a valid location and direction within a polygon for placing a new segment. The direction can either be randomly
@@ -159,8 +159,8 @@ def get_location_and_direction(
159
159
  The thickness of the segment that needs to fit inside the polygon.
160
160
  max_attempts (int, optional):
161
161
  The maximum number of attempts to find a valid location and direction. Defaults to 1000.
162
- angles (Union[str, List[float]], optional):
163
- A string ('uniform' for random directions) or a list of angles (in radians) to choose the direction from. Defaults to 'uniform'.
162
+ angle (float):
163
+ A float indicating the angle of the new segment.
164
164
  nucleation_point (Tuple[float, float], optional):
165
165
  predified nucleation point for the segment. Defaults to None.
166
166
  min_distance (float, optional):
@@ -178,16 +178,8 @@ def get_location_and_direction(
178
178
  - The angle of the segment.
179
179
  - Returns `False` if no valid location and direction are found after the maximum attempts.
180
180
  """
181
-
182
- # Generate a new direction based on the angles parameter
183
- if angles == 'uniform':
184
- angle_new = random.uniform(-np.pi, np.pi)
185
- direction = (np.cos(angle_new), np.sin(angle_new))
186
- direction = direction / np.linalg.norm(direction) # Normalize the direction vector
187
- else:
188
- angle_new = random.choice(angles)
189
- direction = (np.cos(angle_new), np.sin(angle_new))
190
- direction = np.array(direction) / np.linalg.norm(direction)
181
+ direction = (np.cos(angle), np.sin(angle))
182
+ direction = np.array(direction) / np.linalg.norm(direction)
191
183
 
192
184
  # Try to find a valid location and direction up to max_attempts
193
185
  attempt = 0
@@ -215,7 +207,7 @@ def get_location_and_direction(
215
207
 
216
208
  # Check if both endpoints of the segment are inside the polygon
217
209
  if is_inside_polygon(polygon['vertices'], p1) and is_inside_polygon(polygon['vertices'], p2):
218
- return polygon_id, polygon, location_new, direction, perpendicular, angle_new
210
+ return polygon_id, polygon, location_new, direction, perpendicular, angle
219
211
 
220
212
  attempt += 1
221
213
 
@@ -451,7 +443,7 @@ def add_line_segment(
451
443
  segments_dict: Dict[int, LineSegment],
452
444
  polygon_arr: Dict[str, Dict[str, object]],
453
445
  segment_thickness_dict: Dict[int, Polygon],
454
- angles: str = 'uniform',
446
+ angle: float,
455
447
  thickness: float = 0,
456
448
  nucleation_point: Tuple[float, float] = None,
457
449
  min_distance: float = 0,
@@ -480,7 +472,7 @@ def add_line_segment(
480
472
  """
481
473
 
482
474
  # Get a valid location and direction, or return False if none is found
483
- loc = get_location_and_direction(polygon_arr, thickness, nucleation_point, min_distance, max_attempts=max_attempts, angles=angles)
475
+ loc = get_location_and_direction(polygon_arr, angle=angle, thickness=thickness, nucleation_point=nucleation_point, min_distance=min_distance, max_attempts=max_attempts)
484
476
  if loc:
485
477
  polygon_id, polygon, location_new, direction_new, perpendicular, angle_new = loc
486
478
  else:
@@ -560,8 +552,7 @@ def generate_line_segments_thickness(
560
552
  Args:
561
553
  size (int): The number of line segments to generate.
562
554
  thickness_arr (List[float]): A list containing the thickness values for each segment to be generated.
563
- angles (str): The angle distribution method for generating segments. Defaults to 'uniform'.
564
- List[float]: list of angles in radians.
555
+ angles (str): Angle used in the generation of the segments.
565
556
  config (List[List[float]]): A list of configurations for the nucleation points and angles.
566
557
  epsilon (float): the minimum distance between two line.
567
558
  box_size (float): the size of the box.
@@ -606,8 +597,8 @@ def generate_line_segments_thickness(
606
597
  angles = [config[i]['angle']]
607
598
  else:
608
599
  nucleation_point = None
609
- if angles != 'uniform':
610
- angles=[angles[i]]
600
+ # if angles != 'uniform':
601
+ # angles=[angles[i]]
611
602
 
612
603
  output = add_line_segment(segments_dict,
613
604
  polygon_arr,
@@ -615,7 +606,7 @@ def generate_line_segments_thickness(
615
606
  thickness=thickness_arr[i],
616
607
  min_distance = epsilon,
617
608
  nucleation_point = nucleation_point,
618
- angles=angles,
609
+ angle=angles[i],
619
610
  box_size=box_size)
620
611
  if output:
621
612
  segments_dict, polygon_arr, segment_thickness_dict, location, angle = output
@@ -0,0 +1,240 @@
1
+ import numpy as np
2
+ import random
3
+ from typing import List, Dict, Tuple, Union, Optional
4
+ from shapely.geometry import Polygon as Polygon_Shapely, LineString
5
+
6
+ from .Classes import Line, LineSegment, Polygon
7
+
8
+ def minDistance_line_point(A, B, E):
9
+ # vector AB
10
+ AB = np.array(B) - np.array(A)
11
+ EB = np.array(B) - np.array(E)
12
+ AE = np.array(E) - np.array(A)
13
+
14
+ # Calculating the dot product
15
+ AB_BE = np.dot(AB, EB)
16
+ AB_AE = np.dot(AB, AE)
17
+
18
+ # Case 1
19
+ if (AB_BE > 0):
20
+ # Finding the magnitude
21
+ y = E[1] - B[1]
22
+ x = E[0] - B[0]
23
+ reqAns = np.sqrt(x * x + y * y)
24
+
25
+ # Case 2
26
+ elif (AB_AE < 0):
27
+ y = E[1] - A[1]
28
+ x = E[0] - A[0]
29
+ reqAns = np.sqrt(x * x + y * y)
30
+
31
+ # Case 3
32
+ else:
33
+ reqAns = np.linalg.outer(AB, AE) / np.linalg.norm(AB)
34
+
35
+ return reqAns
36
+
37
+ def doLinesIntersect(line1, line2):
38
+ """
39
+ Check if two lines intersect and return the intersection point.
40
+
41
+ Args:
42
+ - line1 (Line): The first line segment.
43
+ - line2 (Line): The second line segment.
44
+
45
+ Returns:
46
+ - intersect (bool): True if the lines intersect, False otherwise.
47
+ - intersection_point (tuple or None): The intersection point (x, y) if lines intersect, None otherwise.
48
+ """
49
+
50
+ x1, y1 = line1[0]
51
+ v1, w1 = (np.cos(line1[1]), np.sin(line1[1]))
52
+
53
+ x2, y2 = line2[0]
54
+ v2, w2 = (np.cos(line2[1]), np.sin(line2[1]))
55
+
56
+ determinant = v1 * w2 - v2 * w1
57
+
58
+ if determinant == 0:
59
+ return False, (None, None)
60
+
61
+ t1 = ((x2 - x1) * w2 - (y2 - y1) * v2) / determinant
62
+ t2 = ((x2 - x1) * w1 - (y2 - y1) * v1) / determinant
63
+
64
+ intersect_x = x1 + v1 * t1
65
+ intersect_y = y2 + w2 * t2
66
+
67
+ if -1e-6 < intersect_x < 1 + 1e-6 and -1e-6 < intersect_y < 1 + 1e-6:
68
+ return True, (intersect_x, intersect_y)
69
+ else:
70
+ return False, (None, None)
71
+
72
+ def seeds(number_of_lines, radius = 0.015, number_of_trials = 10000):
73
+ Line = {}
74
+ line_id = 0
75
+
76
+ nucleation_points = [(0,0), (1,0), (1,1), (0,1)]
77
+ angle = [0,np.pi/2, np.pi, 3*np.pi/2]
78
+
79
+ Line = {'b1':[ (0,0), 0], 'b2':[ (1,0), np.pi/2], 'b3':[ (1,1), np.pi], 'b4':[ (0,1), 3*np.pi/2] }
80
+
81
+ for i in range(number_of_lines):
82
+ new_points = (random.uniform(0,1), random.uniform(0,1))
83
+
84
+ line_new_point = []
85
+ for j in range(len(nucleation_points)):
86
+ start = (np.cos(angle[i])*10+nucleation_points[i][0], np.sin(angle[i])*10+nucleation_points[i][1])
87
+ end = (-np.cos(angle[i])*10+nucleation_points[i][0], -np.sin(angle[i])*10+nucleation_points[i][1])
88
+ line_new_point += [minDistance_line_point(start, end, new_points)]
89
+
90
+ trial = 0
91
+ while sum(np.array(line_new_point) < radius) != 0 or np.sum( np.sqrt(np.sum((np.array(nucleation_points) - np.array(new_points))**2, axis = 1)) < radius) != 0:
92
+ new_points = (random.uniform(0,1), random.uniform(0,1))
93
+
94
+ line_new_point = []
95
+ for j in range(len(nucleation_points)):
96
+ start = (np.cos(angle[i])*10+nucleation_points[i][0], np.sin(angle[i])*10+nucleation_points[i][1])
97
+ end = (-np.cos(angle[i])*10+nucleation_points[i][0], -np.sin(angle[i])*10+nucleation_points[i][1])
98
+ line_new_point += [minDistance_line_point(start, end, new_points)]
99
+
100
+ trial += 1
101
+
102
+ if trial > number_of_trials:
103
+ break
104
+
105
+ if trial <= number_of_trials:
106
+ nucleation_points += [new_points]
107
+ angles = [0, np.pi/4, np.pi/2, 3*np.pi/4]
108
+ angle_new = random.uniform(0, 2*np.pi)
109
+ angle += [angle_new]
110
+ Line[line_id] = [ new_points ,angle_new]
111
+ line_id += 1
112
+ else:
113
+ print('jammed')
114
+ break
115
+
116
+ return Line
117
+
118
+ def all_intersection(Line):
119
+ intersections_dict = {}
120
+
121
+ for k,v in Line.items():
122
+ #intersections_dict[k] = {}
123
+ intersections_dict[k] = {'back':{}, 'front':{}}
124
+
125
+ for kk,vv in Line.items():
126
+ intersect, (intersect_x, intersect_y) = doLinesIntersect(v ,vv)
127
+
128
+ if intersect:
129
+ segment_length = np.sqrt( (v[0][0] - intersect_x)**2 + (v[0][1] - intersect_y)**2)
130
+
131
+ if intersect_x < v[0][0]:
132
+ intersections_dict[k]['back'][kk] = [(intersect_x, intersect_y), segment_length]
133
+ else:
134
+ if intersect_x == v[0][0] and intersect_y < v[0][1]:
135
+ intersections_dict[k]['back'][kk] = [(intersect_x, intersect_y), segment_length]
136
+ else:
137
+ intersections_dict[k]['front'][kk] = [(intersect_x, intersect_y), segment_length]
138
+ intersections_dict[k]['back'] = dict(sorted(intersections_dict[k]['back'].items(), key=lambda e:e[1], reverse = True))
139
+ intersections_dict[k]['front'] = dict(sorted(intersections_dict[k]['front'].items(), key=lambda e:e[1]))
140
+
141
+ return intersections_dict
142
+
143
+ def transform_to_standard_lines(segments):
144
+ data = []
145
+ for s in segments:
146
+ start = (s[3], s[4])
147
+ end = (s[5], s[6])
148
+ line = LineSegment(start=start, end=end, id=s[0], neighbors_initial=[s[1], s[2]], neighbors=None)
149
+ data.append(line)
150
+
151
+ return data
152
+
153
+ def static_line_graph_generation(seed_loc, intersections_dict):
154
+ borders = ['b1', 'b2', 'b3', 'b4']
155
+ segments = []
156
+ edges = []
157
+
158
+ for k,v in seed_loc.items():
159
+ if k not in borders:
160
+ #front
161
+ for kk_f, vv_f in intersections_dict[k]['front'].items():
162
+ try:
163
+ d_k_kk = intersections_dict[kk_f]['back'][k][1]
164
+ front_coordinate = intersections_dict[kk_f]['back'][k][0]
165
+ front_id = kk_f
166
+ where = 'back'
167
+ except:
168
+ d_k_kk = intersections_dict[kk_f]['front'][k][1]
169
+ front_coordinate = intersections_dict[kk_f]['front'][k][0]
170
+ front_id = kk_f
171
+ where = 'front'
172
+
173
+ if vv_f[1] > d_k_kk:
174
+ #check kk neighbors
175
+ boolean = []
176
+ for kkk, vvv in intersections_dict[kk_f][where].items():
177
+ if vvv[1] < d_k_kk:
178
+ try:
179
+ d_kk_kkk = intersections_dict[kkk]['back'][kk_f][1]
180
+ except:
181
+ d_kk_kkk = intersections_dict[kkk]['front'][kk_f][1]
182
+
183
+ if d_kk_kkk > vvv[1]:
184
+ boolean += [0]
185
+ else:
186
+ boolean += [1]
187
+
188
+ #print(k,kk, boolean)
189
+
190
+ if sum(boolean) == 0:
191
+ #print(k, kk, front_coordinate)
192
+ break
193
+
194
+ #back
195
+ for kk_b, vv_b in intersections_dict[k]['back'].items():
196
+ try:
197
+ d_k_kk = intersections_dict[kk_b]['back'][k][1]
198
+ back_coordinate = intersections_dict[kk_b]['back'][k][0]
199
+ back_id = kk_b
200
+ where = 'back'
201
+ except:
202
+ d_k_kk = intersections_dict[kk_b]['front'][k][1]
203
+ back_coordinate = intersections_dict[kk_b]['front'][k][0]
204
+ back_id = kk_b
205
+ where = 'front'
206
+
207
+ if vv_b[1] > d_k_kk:
208
+ boolean = []
209
+ for kkk, vvv in intersections_dict[kk_b][where].items():
210
+ if vvv[1] < d_k_kk:
211
+ try:
212
+ d_kk_kkk = intersections_dict[kkk]['back'][kk_b][1]
213
+ except:
214
+ d_kk_kkk = intersections_dict[kkk]['front'][kk_b][1]
215
+
216
+ if d_kk_kkk > vvv[1]:
217
+ boolean += [0]
218
+ else:
219
+ boolean += [1]
220
+
221
+ if sum(boolean) == 0:
222
+ break
223
+
224
+ try:
225
+ if k!= kk_f and k!= kk_b and kk_f != kk_b and (k, kk_f) not in edges and (kk_f, k) not in edges and (k, kk_b) not in edges and (kk_b, k) not in edges:
226
+ segments+= [[k, kk_f, kk_b, front_coordinate[0], front_coordinate[1], back_coordinate[0], back_coordinate[1]]]
227
+ edges += [(k,kk_f)]
228
+ edges += [(k,kk_b)]
229
+ except:
230
+ None
231
+
232
+ return segments
233
+
234
+ def generate_line_segments_thickness_static(size, seed_loc=None):
235
+ if seed_loc is None:
236
+ seed_loc = seeds(size, 0.0)
237
+ segments = static_line_graph_generation(seed_loc, all_intersection(seed_loc))
238
+ segments = transform_to_standard_lines(segments)
239
+
240
+ return segments
@@ -1,8 +1,8 @@
1
1
  import numpy as np
2
+ import math
2
3
  from typing import List, Dict, Tuple
3
4
  from shapely.geometry import Polygon as Polygon_Shapely
4
5
  from shapely.geometry import LineString, box
5
- from concurrent.futures import ProcessPoolExecutor
6
6
  from .Classes import LineSegment, Polygon
7
7
 
8
8
  def rotate(point, center, rotation_matrix):
@@ -13,7 +13,9 @@ def rotate(point, center, rotation_matrix):
13
13
  rotation_matrix: 2x2 numpy array representing the rotation matrix
14
14
  """
15
15
  translated_point = point - center
16
- rotated_point = np.dot(rotation_matrix, translated_point)
16
+
17
+ # rotated_point = np.dot(rotation_matrix, translated_point)
18
+ rotated_point = rotation_matrix@translated_point
17
19
  final_point = rotated_point + center
18
20
 
19
21
  return final_point
@@ -30,16 +32,22 @@ def angle_between(v1, v2):
30
32
 
31
33
  def get_alignment_mean(line_vector_arr, director):
32
34
  """Get the mean alignment."""
33
- S_all = []
35
+ S_all = 0
36
+ total_mass = 0
34
37
  for item in line_vector_arr:
35
38
  line_vector = item['line_vector']
39
+ vector_diff = np.array(line_vector[1]) - np.array(line_vector[0])
40
+
36
41
  area = item['area']
37
- P2 = 0.5*(3*(np.cos(angle_between(line_vector, director)))**2-1)
38
- S_all.append(P2*area)
42
+ align = math.cos(angle_between(vector_diff, director))**2
43
+ S_all += align*area
44
+ total_mass += area
39
45
 
40
- return float(np.mean(S_all))
46
+ output = S_all / total_mass
41
47
 
42
- def compute_alignment_for_angle(
48
+ return output
49
+
50
+ def compute_alignment(
43
51
  angle: float,
44
52
  segment_thickness_dict: dict[str, Polygon],
45
53
  director: np.ndarray,
@@ -69,7 +77,7 @@ def compute_alignment_for_angle(
69
77
  tuple[float, float]
70
78
  A tuple where the first element is the input angle and the second element is the computed alignment value.
71
79
  """
72
- box_center = (np.array(box_measurements[0]) + np.array(box_measurements[2])) / 2
80
+ box_center = np.array((box_measurements[0]) + np.array(box_measurements[2])) / 2
73
81
 
74
82
  # Rotate network
75
83
  segment_thickness_dict_new = rotate_network(segment_thickness_dict, rotate_angle=angle, box_center=box_center)
@@ -79,13 +87,38 @@ def compute_alignment_for_angle(
79
87
 
80
88
  line_vectors = [
81
89
  {'line_vector': [seg.middle_segment.start, seg.middle_segment.end], 'area': seg.area()}
82
- for seg in segment_thickness_dict_new.values()
90
+ for seg in segment_thickness_dict_new.values() if seg.middle_segment is not None
83
91
  ]
84
92
 
85
93
  alignment = get_alignment_mean(line_vectors, director)
86
-
94
+
87
95
  return angle, alignment
88
96
 
97
+ def get_max_alignment(
98
+ segment_thickness_dict: dict,
99
+ director: np.ndarray,
100
+ box_measurements: list[float],
101
+ grid_points: int = 360
102
+ ) -> float:
103
+ """Find the angle with the maximum alignment using parallel processing."""
104
+ # Create a list of angles to evaluate
105
+ angles = np.linspace(0, np.pi, grid_points)
106
+
107
+ results = []
108
+ for a in angles:
109
+ result = compute_alignment(a, segment_thickness_dict, director, box_measurements)
110
+ results.append(result)
111
+
112
+ # Find the angle with the maximum alignment
113
+ max_alignment = 0
114
+ max_angle = None
115
+ for angle, alignment in results:
116
+ if alignment > max_alignment:
117
+ max_alignment = alignment
118
+ max_angle = angle
119
+
120
+ return max_angle
121
+
89
122
  def rotate_network(
90
123
  segment_thickness_dict: dict[str, Polygon],
91
124
  rotate_angle: float,
@@ -256,74 +289,12 @@ def translate_network(
256
289
 
257
290
  return segment_thickness_dict_new
258
291
 
259
- def get_alignment_mean(line_vector_arr, director):
260
- """Get the mean alignment."""
261
- S_all = []
262
- for item in line_vector_arr:
263
- line_vector = item['line_vector']
264
- area = item['area']
265
- P2 = 0.5*(3*(np.cos(angle_between(line_vector, director)))**2-1)
266
- S_all.append(P2*area)
267
-
268
- return float(np.mean(S_all))
269
-
270
- def compute_alignment_for_angle(
271
- segment_thickness_dict: dict,
272
- angle: float,
273
- box_center,
274
- director: np.ndarray,
275
- ) -> tuple[float, float]:
276
- """Compute the alignment for a given angle."""
277
-
278
- # Rotate the segment network for the given angle
279
- segment_thickness_dict_rotated = rotate_network(segment_thickness_dict, rotate_angle=angle, box_center=box_center)
280
-
281
- # Create line vectors from the rotated segments
282
- line_vectors = []
283
- for s in segment_thickness_dict_rotated.values():
284
- line_vectors.append({'line_vector': np.array([s.middle_segment.start, s.middle_segment.end]), 'area': s.area()})
285
-
286
- # Compute the alignment for the current angle
287
- alignment = get_alignment_mean(line_vectors, director)
288
- return angle, alignment
289
-
290
- def get_max_alignment_angle(
291
- segment_thickness_dict: dict,
292
- director: np.ndarray,
293
- box_measurements: list[float],
294
- grid_points: int = 360
295
- ) -> float:
296
- """Find the angle with the maximum alignment using parallel processing."""
297
-
298
- # Create a list of angles to evaluate
299
- angles = np.linspace(0, 2 * np.pi, grid_points)
300
-
301
- # Use ProcessPoolExecutor for parallel computation of alignment
302
- with ProcessPoolExecutor() as executor:
303
- # Submit tasks to the pool for each angle
304
- results = list(executor.map(
305
- compute_alignment_for_angle,
306
- [segment_thickness_dict] * len(angles), # Same segment dictionary for all angles
307
- angles, # Different angles
308
- [box_measurements] * len(angles), # Same box measurements for all angles
309
- [director] * len(angles) # Same director for all angles
310
- ))
311
-
312
- # Find the angle with the maximum alignment
313
- max_alignment = 0
314
- max_angle = 0
315
- for angle, alignment in results:
316
- if alignment > max_alignment:
317
- max_alignment = alignment
318
- max_angle = angle
319
-
320
- return max_angle
321
-
322
- def generate_line_segments_thickness_orientation(
292
+ def orientate_network(
323
293
  data_dict: Dict[str, dict],
324
294
  orientation: List[int],
325
295
  grid_points: int = 360,
326
- box_measurements: List[Tuple[float, float]] = [(0, 0), (0, 1), (1, 1), (1, 0)]
296
+ box_measurements: List[Tuple[float, float]] = [(0, 0), (0, 1), (1, 1), (1, 0)],
297
+ director: np.ndarray = np.array([0, 1])
327
298
  ) -> List[Dict[str, dict]]:
328
299
  """
329
300
  Generates a set of networks of line segments with different thicknesses and orientations, and clips them to fit
@@ -354,36 +325,33 @@ def generate_line_segments_thickness_orientation(
354
325
 
355
326
  # Extract the segment thickness dictionary from the input data
356
327
  segment_thickness_dict = data_dict['segment_thickness_dict']
357
-
358
- # Define the director vector along the y-axis
359
- director = np.array([0, 1])
360
328
 
361
329
  # Find the angle that aligns the network most with the y-axis
362
- max_angle = get_max_alignment_angle(segment_thickness_dict, director, box_measurements, grid_points)
363
-
330
+ max_angle = get_max_alignment(segment_thickness_dict, director, box_measurements, grid_points)
331
+
364
332
  # Store the initial unmodified configuration
365
333
  output = [{'orientation': 'original', 'data_dict': data_dict}]
366
334
 
367
335
  # Loop through each given orientation, rotate, clip, and translate the network
368
336
  for o in orientation:
369
337
  # Compute the rotation angle for the current orientation relative to max alignment
370
- rotate_angle = o - max_angle
338
+ rotate_angle = -max_angle + o
371
339
 
372
340
  # Rotate the network by the computed angle
373
- segment_thickness_dict_new = rotate_network(segment_thickness_dict, rotate_angle=rotate_angle, box_center=box_center)
341
+ segment_thickness_dict_rotated = rotate_network(segment_thickness_dict, rotate_angle=rotate_angle, box_center=box_center)
374
342
 
375
343
  # Clip the rotated network to fit within the bounding box
376
- segment_thickness_dict_new = clip_network(segment_thickness_dict_new, box_measurements=box_measurements)
344
+ segment_thickness_dict_clipped = clip_network(segment_thickness_dict_rotated, box_measurements=box_measurements)
377
345
 
378
346
  # Translate the clipped network to start at the origin (0,0)
379
347
  translation_vector = -np.array(box_measurements[0])
380
- segment_thickness_dict_new = translate_network(segment_thickness_dict_new, translation_vector)
348
+ segment_thickness_dict_translated = translate_network(segment_thickness_dict_clipped, translation_vector)
381
349
 
382
350
  # Prepare a new data dictionary with the transformed segment information
383
351
  data_dict_new = {
384
352
  'segments_dict': None,
385
353
  'polygon_arr': None,
386
- 'segment_thickness_dict': segment_thickness_dict_new,
354
+ 'segment_thickness_dict': segment_thickness_dict_translated,
387
355
  'jammed': None,
388
356
  'generated_config': None
389
357
  }
@@ -1,202 +0,0 @@
1
- import numpy as np
2
- from typing import List, Dict, Tuple, Union, Optional
3
- from shapely.geometry import Polygon as Polygon_Shapely, LineString
4
- from shapely.geometry import Point
5
- import matplotlib.pyplot as plt
6
- from concurrent.futures import ProcessPoolExecutor
7
-
8
- from .Classes import Line, LineSegment, Polygon
9
- from .generate_line_segments_thickness import generate_line_segments_thickness
10
-
11
- def rotate(point, center, rotation_matrix):
12
- """
13
- Rotates a point around the center using the given rotation matrix.
14
- point: numpy array representing the point to rotate
15
- center: numpy array representing the center of rotation
16
- rotation_matrix: 2x2 numpy array representing the rotation matrix
17
- """
18
- translated_point = point - center
19
- rotated_point = np.dot(rotation_matrix, translated_point)
20
- final_point = rotated_point + center
21
-
22
- return final_point
23
-
24
- def unit_vector(v):
25
- """ Returns the unit vector of the vector. """
26
- return v / np.linalg.norm(v)
27
-
28
- def angle_between(v1, v2):
29
- """ Returns the angle in radians between vectors 'v1' and 'v2'."""
30
- v1_u = unit_vector(v1)
31
- v2_u = unit_vector(v2)
32
- return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
33
-
34
- def get_alignment_mean(line_vector_arr, director):
35
- """Get the mean alignment."""
36
- S_all = []
37
- for item in line_vector_arr:
38
- line_vector = item['line_vector']
39
- area = item['area']
40
- P2 = 0.5*(3*(np.cos(angle_between(line_vector, director)))**2-1)
41
- S_all.append(P2*area)
42
-
43
- return float(np.mean(S_all))
44
-
45
- def compute_alignment_for_angle(
46
- angle: float,
47
- segment_thickness_dict: dict,
48
- director: np.ndarray,
49
- box_size: float
50
- ) -> tuple[float, float]:
51
- """Compute the alignment for a given angle."""
52
- rotation_matrix = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])
53
- center = np.array([box_size / 2, box_size / 2])
54
- line_vectors = [
55
- {'line_vector': np.diff(rotate(np.array([seg.middle_segment.start, seg.middle_segment.end]), center, rotation_matrix), axis=0)[0],
56
- 'area': seg.area()}
57
- for seg in segment_thickness_dict.values()
58
- ]
59
-
60
- alignment = get_alignment_mean(line_vectors, director)
61
- return angle, alignment
62
-
63
-
64
- def get_max_alignment_angle(
65
- segment_thickness_dict: dict,
66
- director: np.ndarray,
67
- box_size: float,
68
- grid_points: int = 360
69
- ) -> float:
70
- """Find the angle with the maximum alignment."""
71
- angles = np.linspace(0, 2 * np.pi, grid_points)
72
-
73
- with ProcessPoolExecutor() as executor:
74
- results = executor.map(
75
- compute_alignment_for_angle,
76
- angles,
77
- [segment_thickness_dict] * grid_points,
78
- [director] * grid_points,
79
- [box_size] * grid_points
80
- )
81
-
82
- return max(results, key=lambda x: x[1])[0]
83
-
84
- def orientate_network(
85
- segment_thickness_dict: dict,
86
- config: list[dict],
87
- rotate_angle: float,
88
- box_size: float
89
- ) -> list[dict]:
90
- """
91
- Rotates and clips a network of line segments within a bounding box.
92
-
93
- Parameters:
94
- segment_thickness_dict (dict): Segment data with start and end points.
95
- config (list[dict]): Segment configuration with angle and thickness.
96
- rotate_angle (float): Rotation angle in radians.
97
- box_size (float): Size of the bounding box.
98
-
99
- Returns:
100
- list[dict]: New segment positions, angles, and thicknesses.
101
- """
102
- center = np.array([box_size / 2, box_size / 2])
103
- rotation_matrix = np.array([[np.cos(rotate_angle), -np.sin(rotate_angle)], [np.sin(rotate_angle), np.cos(rotate_angle)]])
104
- box = Polygon_Shapely([(0, 0), (box_size, 0), (box_size, box_size), (0, box_size)])
105
-
106
- segment_thickness_dict_new = {}
107
- # orientated_config = []
108
- for i, segment in enumerate(segment_thickness_dict.values()):
109
- for vertex in segment.vertices:
110
- angle_rotated = config[i]['angle'] - rotate_angle
111
- start_rotated = rotate(np.array(v.middle_segment.start), center, rotation_matrix)
112
- end_rotated = rotate(np.array(v.middle_segment.end), center, rotation_matrix)
113
-
114
- # Find the intersection between the rotated line and the square
115
- line_middle_point = LineString([start_rotated, end_rotated])
116
-
117
- # Calculate the intersection between the box and the line
118
- intersection = box.intersection(line_middle_point)
119
-
120
- # Check if the line intersects the polygon
121
- if intersection.is_empty:
122
- continue
123
- else:
124
- length = intersection.length
125
- # midpoint = intersection.interpolate(1/2, normalized=True)
126
- midpoint = intersection.interpolate(length/2)
127
-
128
- x = midpoint.xy[0][0]
129
- y = midpoint.xy[1][0]
130
-
131
- # orientated_config.append({ 'location': (x,y), 'angle': angle_rotated, 'thickness': config[i]['thickness'] })
132
-
133
- # return orientated_config
134
-
135
- return segment_thickness_dict_new
136
-
137
- def generate_line_segments_thickness_orientation(
138
- size: int,
139
- thickness_arr: List[float],
140
- orientation: List[int],
141
- angles: List[float],
142
- config: List[List[float]] = None,
143
- epsilon: float = 0,
144
- box_size: float = 1,
145
- grid_points: int = 360
146
- ) -> List[Tuple[Dict[str, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon], np.ndarray]]:
147
- """
148
- Generates a specified number of line segments and updates the polygon and segment thickness dictionaries.
149
-
150
- Args:
151
- size (int): The number of line segments to generate.
152
- thickness_arr (List[float]): A list containing the thickness values for each segment to be generated.
153
- angles (str): The angle distribution method for generating segments. Defaults to 'uniform'.
154
- List[float]: list of angles in radians.
155
- orientation (List[int]): the orientation of the model.
156
- config (List[List[float]]): A list of configurations for the nucleation points and angles.
157
- epsilon (float): the minimum distance between two line.
158
- box_size (float): the size of the system.
159
- grid_points (int): the number of points to test for the alignment.
160
-
161
- Returns:
162
- - an array of dictionaries for each orientation containing:
163
- Tuple[Dict[str, LineSegment], Dict[str, Dict[str, object]], Dict[int, Polygon]]:
164
- - Updated dictionary of line segments.
165
- - Updated dictionary of polygons.
166
- - Updated dictionary of segment thicknesses.
167
- - Array of the nucleation points and angles [x,y,theta].
168
- """
169
- # Size of the box
170
- box_size_0 = box_size*np.sqrt(2)
171
-
172
- # Initial structure
173
- data_dict = generate_line_segments_thickness(size = size,
174
- thickness_arr = thickness_arr,
175
- epsilon= epsilon,
176
- config = config,
177
- angles = angles,
178
- box_size= box_size_0)
179
-
180
- segment_thickness_dict = data_dict['segment_thickness_dict']
181
- generated_config = data_dict['generated_config']
182
-
183
- # Calculate alignment with the y axis
184
- director = (0,1)
185
- max_angle = get_max_alignment_angle(segment_thickness_dict, director, box_size, grid_points)
186
-
187
- # Regenerate network for each orientation
188
- output = [{'orientation': 'original', 'data_dict': data_dict}]
189
- for o in orientation:
190
- rotate_angle = o-max_angle
191
- orientated_config = orientate_network(segment_thickness_dict, generated_config, rotate_angle, box_size)
192
-
193
- data_dict_new = generate_line_segments_thickness(size=size,
194
- thickness_arr=thickness_arr,
195
- epsilon=epsilon,
196
- config=orientated_config,
197
- angles=angles,
198
- box_size=box_size)
199
-
200
- output.append({'orientation': o, 'data_dict': data_dict_new})
201
-
202
- return output