Skip to content

Commit b46f1fe

Browse files
committed
Fixed relative angle bugs, corrected ROC/symmetry constraint canvas item update
1 parent 7dd5f2b commit b46f1fe

File tree

4 files changed

+109
-122
lines changed

4 files changed

+109
-122
lines changed

pymead/core/gcs2.py

Lines changed: 104 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def add_constraint(self, constraint: GeoCon):
3434
if not isinstance(constraint, DistanceConstraint):
3535
raise ValueError("The first constraint in a constraint cluster must be a distance constraint")
3636
constraint.child_nodes[0].root = True
37+
constraint.child_nodes[1].rotation_handle = True
3738

3839
if constraint.param() is not None:
3940
constraint.param().gcs = self
@@ -95,10 +96,10 @@ def add_constraint(self, constraint: GeoCon):
9596
# if edge_data_p12:
9697
# networkx.set_edge_attributes(self, {(constraint.start_point, constraint.vertex): constraint}, name="angle")
9798
# return
98-
if edge_data_p21 and not angle_in_p21 and not (constraint.vertex.root and "distance" in edge_data_p21.keys()):
99+
if edge_data_p21 and not angle_in_p21 and not (constraint.vertex.root and "distance" in edge_data_p21.keys() and constraint.start_point.rotation_handle):
99100
networkx.set_edge_attributes(self, {(constraint.vertex, constraint.start_point): constraint}, name="angle")
100101
return
101-
if edge_data_p23 and not angle_in_p23 and not (constraint.vertex.root and "distance" in edge_data_p23.keys()):
102+
if edge_data_p23 and not angle_in_p23 and not (constraint.vertex.root and "distance" in edge_data_p23.keys() and constraint.end_point.rotation_handle):
102103
networkx.set_edge_attributes(self, {(constraint.vertex, constraint.end_point): constraint}, name="angle")
103104
return
104105
# if edge_data_p32:
@@ -107,38 +108,48 @@ def add_constraint(self, constraint: GeoCon):
107108

108109
if len(in_edges_p1) > 0:
109110
# if angle_in_p12 or angle_in_p21:
110-
if angle_in_p21:
111+
if angle_in_p21 and not constraint.end_point.rotation_handle:
111112
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
112113
return
113114
# if angle_in_p23 or angle_in_p32:
114115
if angle_in_p23:
115116
raise ValueError("Cannot create a valid angle constraint from this case")
116-
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
117-
return
117+
if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]:
118+
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
119+
return
118120
if len(in_edges_p2) > 0:
119121
# if angle_in_p12 or angle_in_p21:
120-
if angle_in_p21:
122+
if angle_in_p21 and not constraint.end_point.rotation_handle:
121123
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
122124
return
123125
# if angle_in_p23 or angle_in_p32:
124-
if angle_in_p23:
126+
if angle_in_p23 and not constraint.start_point.rotation_handle:
125127
self.add_edge(constraint.vertex, constraint.start_point, angle=constraint)
126128
return
127-
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
128-
return
129+
if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]:
130+
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
131+
return
129132
if len(in_edges_p3) > 0:
130133
# if angle_in_p12 or angle_in_p21:
131134
if angle_in_p21:
132135
raise ValueError("Cannot create a valid angle constraint from this case")
133136
# if angle_in_p23 or angle_in_p32:
134-
if angle_in_p23:
137+
if angle_in_p23 and not constraint.start_point.rotation_handle:
135138
self.add_edge(constraint.vertex, constraint.start_point, angle=constraint)
136139
return
140+
if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.start_point)]:
141+
self.add_edge(constraint.vertex, constraint.start_point, angle=constraint)
142+
return
143+
144+
if not constraint.end_point.rotation_handle and constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]:
145+
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
146+
return
147+
if not constraint.start_point.rotation_handle and constraint.vertex not in [nbr for nbr in self.neighbors(constraint.start_point)]:
137148
self.add_edge(constraint.vertex, constraint.start_point, angle=constraint)
138149
return
139150

140-
self.add_edge(constraint.vertex, constraint.end_point, angle=constraint)
141-
return
151+
raise ValueError("Relative angle constraint could not be created")
152+
142153
elif isinstance(constraint, AntiParallel3Constraint) or isinstance(constraint, Perp3Constraint):
143154
in_edges_p1 = tuple([edge for edge in self.in_edges(nbunch=constraint.p1, data=True)])
144155
in_edges_p2 = tuple([edge for edge in self.in_edges(nbunch=constraint.p2, data=True)])
@@ -162,10 +173,10 @@ def add_constraint(self, constraint: GeoCon):
162173
# if edge_data_p12:
163174
# networkx.set_edge_attributes(self, {(constraint.p1, constraint.p2): constraint}, name="angle")
164175
# return
165-
if edge_data_p21 and not angle_in_p21 and not (constraint.p2.root and "distance" in edge_data_p21.keys()):
176+
if edge_data_p21 and not angle_in_p21 and not (constraint.p2.root and "distance" in edge_data_p21.keys() and constraint.p1.rotation_handle):
166177
networkx.set_edge_attributes(self, {(constraint.p2, constraint.p1): constraint}, name="angle")
167178
return
168-
if edge_data_p23 and not angle_in_p23 and not (constraint.p2.root and "distance" in edge_data_p23.keys()):
179+
if edge_data_p23 and not angle_in_p23 and not (constraint.p2.root and "distance" in edge_data_p23.keys() and constraint.p3.rotation_handle):
169180
networkx.set_edge_attributes(self, {(constraint.p2, constraint.p3): constraint}, name="angle")
170181
return
171182
# if edge_data_p32:
@@ -174,44 +185,51 @@ def add_constraint(self, constraint: GeoCon):
174185

175186
if len(in_edges_p1) > 0:
176187
# if angle_in_p12 or angle_in_p21:
177-
if angle_in_p21:
188+
if angle_in_p21 and not constraint.p3.rotation_handle:
178189
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
179190
return
180191
# if angle_in_p23 or angle_in_p32:
181192
if angle_in_p23:
182193
raise ValueError("Cannot create a valid angle constraint from this case")
183-
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
184-
return
194+
if not constraint.p3.rotation_handle:
195+
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
196+
return
185197
if len(in_edges_p2) > 0:
186198
# if angle_in_p12 or angle_in_p21:
187-
if angle_in_p21:
199+
if angle_in_p21 and not constraint.p3.rotation_handle:
188200
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
189201
return
190202
# if angle_in_p23 or angle_in_p32:
191-
if angle_in_p23:
203+
if angle_in_p23 and not constraint.p1.rotation_handle:
192204
self.add_edge(constraint.p2, constraint.p1, angle=constraint)
193205
return
194-
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
195-
return
206+
if not constraint.p3.rotation_handle:
207+
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
208+
return
196209
if len(in_edges_p3) > 0:
197210
# if angle_in_p12 or angle_in_p21:
198211
if angle_in_p21:
199212
raise ValueError("Cannot create a valid angle constraint from this case")
200213
# if angle_in_p23 or angle_in_p32:
201-
if angle_in_p23:
214+
if angle_in_p23 and not constraint.p1.rotation_handle:
202215
self.add_edge(constraint.p2, constraint.p1, angle=constraint)
203216
return
204-
self.add_edge(constraint.p2, constraint.p1, angle=constraint)
217+
if not constraint.p1.rotation_handle:
218+
self.add_edge(constraint.p2, constraint.p1, angle=constraint)
219+
return
220+
221+
if constraint.p1.rotation_handle:
222+
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
205223
return
224+
if constraint.p3.rotation_handle:
225+
self.add_edge(constraint.p2, constraint.p1, angle=constraint)
206226

207-
self.add_edge(constraint.p2, constraint.p3, angle=constraint)
208-
return
209227
elif isinstance(constraint, SymmetryConstraint):
210-
self.solve_symmetry_constraint(constraint)
211-
self.update_canvas_items(constraint)
228+
points_solved = self.solve_symmetry_constraint(constraint)
229+
self.update_canvas_items(points_solved)
212230
elif isinstance(constraint, ROCurvatureConstraint):
213-
self.solve_roc_constraint(constraint)
214-
self.update_canvas_items(constraint)
231+
points_solved = self.solve_roc_constraint(constraint)
232+
self.update_canvas_items(points_solved)
215233

216234
def remove_constraint(self, constraint: GeoCon):
217235
raise NotImplementedError("Constraint removal not yet implemented")
@@ -221,6 +239,8 @@ def make_point_copies(self):
221239

222240
def solve(self, source: GeoCon):
223241
points_solved = []
242+
symmetry_points_solved = []
243+
roc_points_solved = []
224244
if isinstance(source, DistanceConstraint):
225245
edge_data_p12 = self.get_edge_data(source.p1, source.p2)
226246
if edge_data_p12 and edge_data_p12["distance"] is source:
@@ -280,18 +300,31 @@ def solve(self, source: GeoCon):
280300
rotation_point = source.vertex
281301

282302
if edge_data_p21 and "angle" in edge_data_p21 and edge_data_p21["angle"] is source:
283-
pass
303+
start = source.start_point if not source.vertex.root else source.vertex
284304
elif edge_data_p23 and "angle" in edge_data_p23 and edge_data_p23["angle"] is source:
285-
pass
305+
start = source.end_point if not source.vertex.root else source.vertex
286306
d_angle *= -1
287307
else:
288308
raise ValueError("Somehow no angle constraint found between the three points")
289309

290310
rotation_mat = np.array([[np.cos(d_angle), -np.sin(d_angle)], [np.sin(d_angle), np.cos(d_angle)]])
291311
rotation_point_mat = np.array([[rotation_point.x().value()], [rotation_point.y().value()]])
292312

293-
for point in networkx.bfs_tree(self, source=source.vertex):
294-
if point is source.vertex:
313+
# Get all the points that might need to rotate
314+
all_downstream_points = []
315+
rotation_handle = None
316+
for point in networkx.bfs_tree(self, source=start):
317+
all_downstream_points.append(point)
318+
if point.rotation_handle:
319+
rotation_handle = point
320+
321+
# Get the branch to cut, if there is one
322+
root_rotation_branch = []
323+
if source.vertex.root and rotation_handle is not None:
324+
root_rotation_branch = [point for point in networkx.bfs_tree(self, source=rotation_handle)]
325+
326+
for point in all_downstream_points:
327+
if point is source.vertex or point in root_rotation_branch:
295328
continue
296329
dx_dy = np.array([[point.x().value() - rotation_point.x().value()],
297330
[point.y().value() - rotation_point.y().value()]])
@@ -302,16 +335,21 @@ def solve(self, source: GeoCon):
302335
points_solved.append(point)
303336

304337
elif isinstance(source, SymmetryConstraint):
305-
self.solve_symmetry_constraint(source)
338+
symmetry_points_solved = self.solve_symmetry_constraint(source)
306339
elif isinstance(source, ROCurvatureConstraint):
307-
self.solve_roc_constraint(source)
340+
roc_points_solved = self.solve_roc_constraint(source)
308341

309-
self.solve_other_constraints(points_solved)
342+
other_points_solved = self.solve_other_constraints(points_solved)
343+
other_points_solved = list(set(other_points_solved).union(set(symmetry_points_solved)).union(set(roc_points_solved)))
344+
345+
points_solved = list(set(points_solved).union(set(other_points_solved)))
310346

311347
# networkx.draw_circular(self, labels={point: point.name() for point in self.nodes})
312348
# from matplotlib import pyplot as plt
313349
# plt.show()
314350

351+
return points_solved
352+
315353
def move_root(self, root: Point, dx: float, dy: float):
316354
if not root.root:
317355
raise ValueError("Cannot move a point that is not a root of a constraint cluster")
@@ -345,6 +383,8 @@ def solve_symmetry_constraint(constraint: SymmetryConstraint):
345383
y3 + mirror_distance * np.sin(mirror_angle), force=True
346384
)
347385

386+
return constraint.child_nodes
387+
348388
@staticmethod
349389
def solve_roc_constraint(constraint: ROCurvatureConstraint):
350390

@@ -361,47 +401,54 @@ def solve_for_single_curve(p_g1: Point, p_g2: Point, n: int):
361401
solve_for_single_curve(constraint.g1_point_curve_1, constraint.g2_point_curve_1, constraint.curve_1.degree)
362402
solve_for_single_curve(constraint.g1_point_curve_2, constraint.g2_point_curve_2, constraint.curve_2.degree)
363403

404+
return constraint.child_nodes
405+
364406
def solve_symmetry_constraints(self, points: typing.List[Point]):
407+
points_solved = []
365408
symmetry_constraints_solved = []
366409
for point in points:
367410
symmetry_constraints = [geo_con for geo_con in point.geo_cons if isinstance(geo_con, SymmetryConstraint)]
368411
for symmetry_constraint in symmetry_constraints:
369412
if symmetry_constraint in symmetry_constraints_solved:
370413
continue
371-
self.solve_symmetry_constraint(symmetry_constraint)
414+
symmetry_points_solved = self.solve_symmetry_constraint(symmetry_constraint)
372415
symmetry_constraints_solved.append(symmetry_constraint)
416+
for symmetry_point_solved in symmetry_points_solved:
417+
if symmetry_point_solved in points_solved:
418+
continue
419+
420+
points_solved.append(symmetry_point_solved)
421+
422+
return points_solved
373423

374424
def solve_roc_constraints(self, points: typing.List[Point]):
375-
roc_constraints_solved =[]
425+
points_solved = []
426+
roc_constraints_solved = []
376427
for point in points:
377428
roc_constraints = [geo_con for geo_con in point.geo_cons if isinstance(geo_con, ROCurvatureConstraint)]
378429
for roc_constraint in roc_constraints:
379430
if roc_constraint in roc_constraints_solved:
380431
continue
381-
self.solve_roc_constraint(roc_constraint)
432+
roc_points_solved = self.solve_roc_constraint(roc_constraint)
382433
roc_constraints_solved.append(roc_constraint)
434+
for roc_point_solved in roc_points_solved:
435+
if roc_point_solved in points_solved:
436+
continue
383437

384-
def solve_other_constraints(self, points: typing.List[Point]):
385-
self.solve_symmetry_constraints(points)
386-
self.solve_roc_constraints(points)
438+
points_solved.append(roc_point_solved)
387439

388-
def update_canvas_items(self, source: GeoCon or Point):
440+
return points_solved
389441

390-
points_to_update = []
391-
if isinstance(source, Point):
392-
starting_points = [source]
393-
elif isinstance(source, GeoCon):
394-
starting_points = source.child_nodes
395-
else:
396-
raise ValueError("source must be of type GeoCon or of type Point")
397-
for starting_point in starting_points:
398-
for point in networkx.dfs_preorder_nodes(self, source=starting_point):
399-
if point in points_to_update:
400-
continue
401-
points_to_update.append(point)
442+
def solve_other_constraints(self, points: typing.List[Point]):
443+
symmetry_points_solved = self.solve_symmetry_constraints(points)
444+
roc_points_solved = self.solve_roc_constraints(points)
445+
return list(set(symmetry_points_solved).union(roc_points_solved))
446+
447+
@staticmethod
448+
def update_canvas_items(points_solved: typing.List[Point]):
402449

403450
curves_to_update = []
404-
for point in points_to_update:
451+
for point in points_solved:
405452
if point.canvas_item is not None:
406453
point.canvas_item.updateCanvasItem(point.x().value(), point.y().value())
407454

@@ -421,7 +468,7 @@ def update_canvas_items(self, source: GeoCon or Point):
421468
airfoil.canvas_item.generatePicture()
422469

423470
constraints_to_update = []
424-
for point in networkx.dfs_preorder_nodes(self, source=source.child_nodes[0]):
471+
for point in points_solved:
425472
for geo_con in point.geo_cons:
426473
if geo_con not in constraints_to_update:
427474
constraints_to_update.append(geo_con)
@@ -433,64 +480,3 @@ def update_canvas_items(self, source: GeoCon or Point):
433480

434481
class ConstraintValidationError(Exception):
435482
pass
436-
437-
438-
439-
def main():
440-
pass
441-
# geo_col = GeometryCollection()
442-
# gcs2 = GCS2()
443-
# points = [
444-
# geo_col.add_point(0.0, 0.0),
445-
# geo_col.add_point(1.1, 0.0),
446-
# geo_col.add_point(0.1, -0.1),
447-
# geo_col.add_point(0.5, 0.2),
448-
# geo_col.add_point(0.2, 0.7),
449-
# geo_col.add_point(0.4, 0.4)
450-
# ]
451-
# for point in points:
452-
# gcs2.add_point(point)
453-
# constraints = [
454-
# DistanceConstraint(points[0], points[1], 0.25),
455-
# DistanceConstraint(points[1], points[2], 0.35),
456-
# DistanceConstraint(points[2], points[3], 0.4),
457-
# DistanceConstraint(points[1], points[4], 0.15),
458-
# DistanceConstraint(points[2], points[5], 0.2),
459-
# AntiParallel3Constraint(points[0], points[1], points[2]),
460-
# AntiParallel3Constraint(points[1], points[2], points[3]),
461-
# Perp3Constraint(points[4], points[1], points[0]),
462-
# Perp3Constraint(points[5], points[2], points[1])
463-
# ]
464-
# for constraint in constraints:
465-
# gcs2.add_constraint(constraint)
466-
# gcs2.solve(constraint)
467-
# print(f"{points[0].measure_distance(points[1]) = }")
468-
# print(f"{points[1].measure_distance(points[2]) = }")
469-
# print(f"{points[2].measure_distance(points[3]) = }")
470-
# print(f"{points[2].measure_distance(points[4]) = }")
471-
# print(f"{points[3].measure_distance(points[5]) = }")
472-
# # plt.plot([p.x().value() for p in points], [p.y().value() for p in points], ls="none", marker="o")
473-
# # plt.show()
474-
#
475-
# constraints[0].param().set_value(0.35)
476-
# gcs2.solve(constraints[0])
477-
# plt.plot([p.x().value() for p in points], [p.y().value() for p in points], ls="none", marker="o")
478-
# plt.show()
479-
#
480-
# networkx.draw_networkx(gcs2)
481-
# plt.show()
482-
#
483-
# for point in points:
484-
# tree = networkx.bfs_tree(gcs2, source=point)
485-
# networkx.draw_networkx(tree)
486-
# plt.show()
487-
#
488-
# plt.plot([p.x().value() for p in points], [p.y().value() for p in points], ls="none", marker="o")
489-
# plt.gca().set_aspect("equal")
490-
# plt.show()
491-
# networkx.draw_networkx(gcs2)
492-
# plt.show()
493-
494-
495-
if __name__ == "__main__":
496-
main()

0 commit comments

Comments
 (0)