diff --git a/pymead/core/constraint_graph.py b/pymead/core/constraint_graph.py index a76c36ef..e64901e0 100644 --- a/pymead/core/constraint_graph.py +++ b/pymead/core/constraint_graph.py @@ -439,32 +439,32 @@ def analyze(self, constraint: GeoCon): for cnstr in point.geo_cons: if isinstance(cnstr, DistanceConstraint) or isinstance(cnstr, DistanceConstraintWeak): start_point = point - vertex = cnstr.p2 if cnstr.p2 is not point else cnstr.p1 + p2 = cnstr.p2 if cnstr.p2 is not point else cnstr.p1 end_point = None - for sub_cnstr in vertex.geo_cons: + for sub_cnstr in p2.geo_cons: if sub_cnstr is cnstr: continue if isinstance(sub_cnstr, RelAngle3Constraint) or isinstance(sub_cnstr, RelAngle3ConstraintWeak): - end_point = sub_cnstr.start_point + end_point = sub_cnstr.p1 elif (isinstance(sub_cnstr, Perp3Constraint) or isinstance(sub_cnstr, Parallel3Constraint) or isinstance(sub_cnstr, AntiParallel3Constraint)): end_point = sub_cnstr.p1 if end_point is not None: - rel_angle3_constraint_weak = RelAngle3ConstraintWeak(start_point, vertex, end_point, "ra3") + rel_angle3_constraint_weak = RelAngle3ConstraintWeak(start_point, p2, end_point, "ra3") weak_constraints.append(rel_angle3_constraint_weak) dof -= 1 break - for sub_cnstr in vertex.geo_cons: + for sub_cnstr in p2.geo_cons: if sub_cnstr is cnstr: continue if isinstance(sub_cnstr, DistanceConstraint) or isinstance(sub_cnstr, DistanceConstraintWeak): - end_point = sub_cnstr.p1 if sub_cnstr.p1 not in [start_point, vertex] else sub_cnstr.p2 + end_point = sub_cnstr.p1 if sub_cnstr.p1 not in [start_point, p2] else sub_cnstr.p2 if end_point is not None: - rel_angle3_constraint_weak = RelAngle3ConstraintWeak(start_point, vertex, end_point, "ra3") + rel_angle3_constraint_weak = RelAngle3ConstraintWeak(start_point, p2, end_point, "ra3") weak_constraints.append(rel_angle3_constraint_weak) dof -= 1 break @@ -484,7 +484,7 @@ def analyze(self, constraint: GeoCon): end_point = candidate_points[0] abs_angle_constraint = AbsAngleConstraintWeak(start_point, end_point, "aa1") weak_constraints.append(abs_angle_constraint) - # print(f"{abs_angle_constraint = }, {start_point = }, {end_point = }") + # print(f"{abs_angle_constraint = }, {p1 = }, {p3 = }") weak_equations = [] for cnstr in weak_constraints: diff --git a/pymead/core/constraints.py b/pymead/core/constraints.py index 753df5a6..8e410be5 100644 --- a/pymead/core/constraints.py +++ b/pymead/core/constraints.py @@ -221,19 +221,19 @@ class RelAngle3Constraint(GeoCon): default_name = "RelAng3Con-1" - def __init__(self, start_point: Point, vertex: Point, end_point: Point, value: float or AngleParam, name: str = None): - self.start_point = start_point - self.vertex = vertex - self.end_point = end_point + def __init__(self, p1: Point, p2: Point, p3: Point, value: float or AngleParam, name: str = None): + self.p1 = p1 + self.p2 = p2 + self.p3 = p3 param = value if isinstance(value, Param) else AngleParam(value=value, name="unnamed") - super().__init__(param=param, name=name, child_nodes=[self.start_point, self.vertex, self.end_point], kind="a3") + super().__init__(param=param, name=name, child_nodes=[self.p1, self.p2, self.p3], kind="a3") def __repr__(self): return f"{self.__class__.__name__} {self.name()}" def get_dict_rep(self) -> dict: - return {"start_point": self.start_point.name(), "vertex": self.vertex.name(), - "end_point": self.end_point.name(), "value": self.param().name(), + return {"p1": self.p1.name(), "p2": self.p2.name(), + "p3": self.p3.name(), "value": self.param().name(), "constraint_type": self.__class__.__name__} diff --git a/pymead/core/gcs2.py b/pymead/core/gcs2.py index d1f651a1..cc4f80a5 100644 --- a/pymead/core/gcs2.py +++ b/pymead/core/gcs2.py @@ -20,210 +20,180 @@ def remove_point(self, point: Point): self.remove_node(point) self.points.pop(point.name()) - def add_constraint(self, constraint: GeoCon): - + def _check_if_constraint_creates_new_cluster(self, constraint: GeoCon): for point in constraint.child_nodes: # If there is already an edge attached to any of the points in this constraint, do not create a new root if len(self.in_edges(nbunch=point)) > 0 or len(self.out_edges(nbunch=point)) > 0: - first_constraint_in_cluster = False - break - else: - first_constraint_in_cluster = True + return False + return True + + @staticmethod + def _set_distance_constraint_as_root(constraint: DistanceConstraint): + constraint.child_nodes[0].root = True + constraint.child_nodes[1].rotation_handle = True + + def _check_if_constraint_addition_requires_cluster_merge(self, constraint: GeoCon): + """ + Check if the addition of this constraint requires a cluster merge by analyzing how many nodes have incident + edges. Any constraint with more than one incident edge requires a cluster merge. + + Parameters + ---------- + constraint: GeoCon + Constraint to test for cluster merge + + Returns + ------- + bool + ``True`` if there are at least two nodes with incident edges, otherwise ``False`` + """ + nodes_with_in_edge = 0 + for point in constraint.child_nodes: + if len(self.in_edges(nbunch=point)) > 0: + nodes_with_in_edge += 1 + return True if nodes_with_in_edge > 1 else False + + def _check_if_node_has_incident_edge(self, node: Point): + in_edges = [edge for edge in self.in_edges(nbunch=node)] + return True if in_edges else False + + def _check_if_node_reaches_root(self, node: Point): + for node in networkx.dfs_preorder_nodes(self, source=node): + if node.root: + return True + return False + + def _add_distance_constraint_to_directed_edge(self, constraint: DistanceConstraint, + first_constraint_in_cluster: bool): + + def _add_edge_or_append_data(node1: Point, node2: Point): + edge_data = self.get_edge_data(node1, node2) + if edge_data: + if "distance" in edge_data.keys(): + raise ValueError("Cannot add a second distance constraint between the same pair of points") + else: + networkx.set_edge_attributes(self, {(node1, node2): constraint}, name="distance") + else: + self.add_edge(node1, node2, distance=constraint) + + p1_edges = [edge for edge in self.in_edges(nbunch=constraint.p1, data=True)] + p2_edges = [edge for edge in self.in_edges(nbunch=constraint.p2, data=True)] + edge_lists = [p1_edges, p2_edges] + point_pairs = [(constraint.p1, constraint.p2), (constraint.p2, constraint.p1)] if first_constraint_in_cluster: - if not isinstance(constraint, DistanceConstraint): - raise ValueError("The first constraint in a constraint cluster must be a distance constraint") - constraint.child_nodes[0].root = True - constraint.child_nodes[1].rotation_handle = True + _add_edge_or_append_data(constraint.p1, constraint.p2) + return - if constraint.param() is not None: - constraint.param().gcs = self + for edge_list, point_pair in zip(edge_lists, point_pairs): - if isinstance(constraint, DistanceConstraint): - in_edges_p1 = tuple([edge for edge in self.in_edges(nbunch=constraint.p1, data=True) if "distance" in edge[2].keys()]) - in_edges_p2 = tuple([edge for edge in self.in_edges(nbunch=constraint.p2, data=True) if "distance" in edge[2].keys()]) - if len(in_edges_p1) > 0 and len(in_edges_p2) > 0: - raise ConstraintValidationError(f"Failed to draw distance constraint {constraint} due to identified" - f" incident distance constraints on both start and end points") - - if len(in_edges_p1) > 0: - edge_data = self.get_edge_data(constraint.p1, constraint.p2) - if edge_data: - if "distance" in self.get_edge_data(constraint.p1, constraint.p2).keys(): - raise ConstraintValidationError(f"Cannot add a duplicate distance constraint between" - f" {constraint.p1} and {constraint.p2}") - networkx.set_edge_attributes(self, {(constraint.p1, constraint.p2): constraint}, - name="distance") - return - self.add_edge(constraint.p1, constraint.p2, distance=constraint) - return - if len(in_edges_p2) > 0: - edge_data = self.get_edge_data(constraint.p2, constraint.p1) - if edge_data: - if "distance" in self.get_edge_data(constraint.p2, constraint.p1).keys(): - raise ConstraintValidationError(f"Cannot add a duplicate distance constraint between" - f" {constraint.p2} and {constraint.p1}") - networkx.set_edge_attributes(self, {(constraint.p2, constraint.p1): constraint}, - name="distance") - return - self.add_edge(constraint.p2, constraint.p1, distance=constraint) + if len(edge_list) > 1: + raise ValueError("Detected multiple edges for the same pair of points when adding distance constraint") + + if len(edge_list) <= 1: + if (self._check_if_node_has_incident_edge(point_pair[1]) + or self._check_if_node_reaches_root(point_pair[1])): + continue + + _add_edge_or_append_data(point_pair[0], point_pair[1]) return - # Default case - self.add_edge(constraint.p1, constraint.p2, distance=constraint) + raise ValueError("Failed to add distance constraint") + + def _add_angle_constraint_to_directed_edge(self, + constraint: RelAngle3Constraint or AntiParallel3Constraint or Perp3Constraint, + first_constraint_in_cluster: bool): + + if first_constraint_in_cluster: + raise ValueError("First constraint in a cluster must be a distance constraint") + + in_edges_p1 = tuple([edge for edge in self.in_edges(nbunch=constraint.p1, data=True)]) + in_edges_p2 = tuple([edge for edge in self.in_edges(nbunch=constraint.p2, data=True)]) + in_edges_p3 = tuple([edge for edge in self.in_edges(nbunch=constraint.p3, data=True)]) + + edge_data_p21 = self.get_edge_data(constraint.p2, constraint.p1) + edge_data_p23 = self.get_edge_data(constraint.p2, constraint.p3) + + angle_in_p21 = False if not edge_data_p21 else "angle" in edge_data_p21.keys() + angle_in_p23 = False if not edge_data_p23 else "angle" in edge_data_p23.keys() + + if angle_in_p21 and angle_in_p23: + raise ConstraintValidationError(f"{constraint} already has angle constraints associated with both" + f" pairs of points") + + 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): + networkx.set_edge_attributes(self, {(constraint.p2, constraint.p1): constraint}, name="angle") + return + 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): + networkx.set_edge_attributes(self, {(constraint.p2, constraint.p3): constraint}, name="angle") return - elif isinstance(constraint, RelAngle3Constraint): - in_edges_p1 = tuple([edge for edge in self.in_edges(nbunch=constraint.start_point, data=True)]) - in_edges_p2 = tuple([edge for edge in self.in_edges(nbunch=constraint.vertex, data=True)]) - in_edges_p3 = tuple([edge for edge in self.in_edges(nbunch=constraint.end_point, data=True)]) - - # edge_data_p12 = self.get_edge_data(constraint.start_point, constraint.vertex) - edge_data_p21 = self.get_edge_data(constraint.vertex, constraint.start_point) - edge_data_p23 = self.get_edge_data(constraint.vertex, constraint.end_point) - # edge_data_p32 = self.get_edge_data(constraint.end_point, constraint.vertex) - - # angle_in_p12 = False if not edge_data_p12 else "angle" in edge_data_p12.keys() - angle_in_p21 = False if not edge_data_p21 else "angle" in edge_data_p21.keys() - angle_in_p23 = False if not edge_data_p23 else "angle" in edge_data_p23.keys() - # angle_in_p32 = False if not edge_data_p32 else "angle" in edge_data_p32.keys() - - # if (angle_in_p12 or angle_in_p21) and (angle_in_p23 or angle_in_p32): - if angle_in_p21 and angle_in_p23: - raise ConstraintValidationError(f"{constraint} already has angle constraints associated with both" - f" pairs of points") - - # if edge_data_p12: - # networkx.set_edge_attributes(self, {(constraint.start_point, constraint.vertex): constraint}, name="angle") - # return - 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): - networkx.set_edge_attributes(self, {(constraint.vertex, constraint.start_point): constraint}, name="angle") - return - 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): - networkx.set_edge_attributes(self, {(constraint.vertex, constraint.end_point): constraint}, name="angle") - return - # if edge_data_p32: - # networkx.set_edge_attributes(self, {(constraint.end_point, constraint.vertex): constraint}, name="angle") - # return - - if len(in_edges_p1) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21 and not constraint.end_point.rotation_handle: - self.add_edge(constraint.vertex, constraint.end_point, angle=constraint) - return - # if angle_in_p23 or angle_in_p32: - if angle_in_p23: - raise ValueError("Cannot create a valid angle constraint from this case") - if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]: - self.add_edge(constraint.vertex, constraint.end_point, angle=constraint) - return - if len(in_edges_p2) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21 and not constraint.end_point.rotation_handle: - self.add_edge(constraint.vertex, constraint.end_point, angle=constraint) - return - # if angle_in_p23 or angle_in_p32: - if angle_in_p23 and not constraint.start_point.rotation_handle: - self.add_edge(constraint.vertex, constraint.start_point, angle=constraint) - return - if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]: - self.add_edge(constraint.vertex, constraint.end_point, angle=constraint) - return - if len(in_edges_p3) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21: - raise ValueError("Cannot create a valid angle constraint from this case") - # if angle_in_p23 or angle_in_p32: - if angle_in_p23 and not constraint.start_point.rotation_handle: - self.add_edge(constraint.vertex, constraint.start_point, angle=constraint) - return - if constraint.vertex not in [nbr for nbr in self.neighbors(constraint.start_point)]: - self.add_edge(constraint.vertex, constraint.start_point, angle=constraint) - return - - if not constraint.end_point.rotation_handle and constraint.vertex not in [nbr for nbr in self.neighbors(constraint.end_point)]: - self.add_edge(constraint.vertex, constraint.end_point, angle=constraint) + if len(in_edges_p1) > 0: + # if angle_in_p12 or angle_in_p21: + if angle_in_p21 and not constraint.p3.rotation_handle: + self.add_edge(constraint.p2, constraint.p3, angle=constraint) return - if not constraint.start_point.rotation_handle and constraint.vertex not in [nbr for nbr in self.neighbors(constraint.start_point)]: - self.add_edge(constraint.vertex, constraint.start_point, angle=constraint) + # if angle_in_p23 or angle_in_p32: + if angle_in_p23: + raise ValueError("Cannot create a valid angle constraint from this case") + if constraint.p2 not in [nbr for nbr in self.neighbors(constraint.p3)]: + self.add_edge(constraint.p2, constraint.p3, angle=constraint) return - - raise ValueError("Relative angle constraint could not be created") - - elif isinstance(constraint, AntiParallel3Constraint) or isinstance(constraint, Perp3Constraint): - in_edges_p1 = tuple([edge for edge in self.in_edges(nbunch=constraint.p1, data=True)]) - in_edges_p2 = tuple([edge for edge in self.in_edges(nbunch=constraint.p2, data=True)]) - in_edges_p3 = tuple([edge for edge in self.in_edges(nbunch=constraint.p3, data=True)]) - - # edge_data_p12 = self.get_edge_data(constraint.p1, constraint.p2) - edge_data_p21 = self.get_edge_data(constraint.p2, constraint.p1) - edge_data_p23 = self.get_edge_data(constraint.p2, constraint.p3) - # edge_data_p32 = self.get_edge_data(constraint.p3, constraint.p2) - - # angle_in_p12 = False if not edge_data_p12 else "angle" in edge_data_p12.keys() - angle_in_p21 = False if not edge_data_p21 else "angle" in edge_data_p21.keys() - angle_in_p23 = False if not edge_data_p23 else "angle" in edge_data_p23.keys() - # angle_in_p32 = False if not edge_data_p32 else "angle" in edge_data_p32.keys() - - # if (angle_in_p12 or angle_in_p21) and (angle_in_p23 or angle_in_p32): - if angle_in_p21 and angle_in_p23: - raise ConstraintValidationError(f"{constraint} already has angle constraints associated with both" - f" pairs of points") - - # if edge_data_p12: - # networkx.set_edge_attributes(self, {(constraint.p1, constraint.p2): constraint}, name="angle") - # return - 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): - networkx.set_edge_attributes(self, {(constraint.p2, constraint.p1): constraint}, name="angle") + if len(in_edges_p2) > 0: + # if angle_in_p12 or angle_in_p21: + if angle_in_p21 and not constraint.p3.rotation_handle: + self.add_edge(constraint.p2, constraint.p3, angle=constraint) return - 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): - networkx.set_edge_attributes(self, {(constraint.p2, constraint.p3): constraint}, name="angle") + # if angle_in_p23 or angle_in_p32: + if angle_in_p23 and not constraint.p1.rotation_handle: + self.add_edge(constraint.p2, constraint.p1, angle=constraint) return - # if edge_data_p32: - # networkx.set_edge_attributes(self, {(constraint.p3, constraint.p2): constraint}, name="angle") - # return - - if len(in_edges_p1) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21 and not constraint.p3.rotation_handle: - self.add_edge(constraint.p2, constraint.p3, angle=constraint) - return - # if angle_in_p23 or angle_in_p32: - if angle_in_p23: - raise ValueError("Cannot create a valid angle constraint from this case") - if not constraint.p3.rotation_handle: - self.add_edge(constraint.p2, constraint.p3, angle=constraint) - return - if len(in_edges_p2) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21 and not constraint.p3.rotation_handle: - self.add_edge(constraint.p2, constraint.p3, angle=constraint) - return - # if angle_in_p23 or angle_in_p32: - if angle_in_p23 and not constraint.p1.rotation_handle: - self.add_edge(constraint.p2, constraint.p1, angle=constraint) - return - if not constraint.p3.rotation_handle: - self.add_edge(constraint.p2, constraint.p3, angle=constraint) - return - if len(in_edges_p3) > 0: - # if angle_in_p12 or angle_in_p21: - if angle_in_p21: - raise ValueError("Cannot create a valid angle constraint from this case") - # if angle_in_p23 or angle_in_p32: - if angle_in_p23 and not constraint.p1.rotation_handle: - self.add_edge(constraint.p2, constraint.p1, angle=constraint) - return - if not constraint.p1.rotation_handle: - self.add_edge(constraint.p2, constraint.p1, angle=constraint) - return - - if constraint.p1.rotation_handle: + if constraint.p2 not in [nbr for nbr in self.neighbors(constraint.p3)]: self.add_edge(constraint.p2, constraint.p3, angle=constraint) return - if constraint.p3.rotation_handle: + if len(in_edges_p3) > 0: + # if angle_in_p12 or angle_in_p21: + if angle_in_p21: + raise ValueError("Cannot create a valid angle constraint from this case") + # if angle_in_p23 or angle_in_p32: + if angle_in_p23 and not constraint.p1.rotation_handle: + self.add_edge(constraint.p2, constraint.p1, angle=constraint) + return + if constraint.p2 not in [nbr for nbr in self.neighbors(constraint.p1)]: self.add_edge(constraint.p2, constraint.p1, angle=constraint) + return + if not constraint.p3.rotation_handle and constraint.p2 not in [nbr for nbr in self.neighbors(constraint.p3)]: + self.add_edge(constraint.p2, constraint.p3, angle=constraint) + return + if not constraint.p1.rotation_handle and constraint.p2 not in [nbr for nbr in self.neighbors(constraint.p1)]: + self.add_edge(constraint.p2, constraint.p1, angle=constraint) + return + + raise ValueError("Relative angle constraint could not be created") + + def add_constraint(self, constraint: GeoCon): + + # Check if this constraint creates a new cluster + first_constraint_in_cluster = self._check_if_constraint_creates_new_cluster(constraint) + + # If it does, make sure it is a distance constraint and set it as the root constraint + if first_constraint_in_cluster: + if not isinstance(constraint, DistanceConstraint): + raise ValueError("The first constraint in a constraint cluster must be a distance constraint") + self._set_distance_constraint_as_root(constraint) + + # If the constraint has a Param associated with it, pass the GCS reference to this parameter + if constraint.param() is not None: + constraint.param().gcs = self + + if isinstance(constraint, DistanceConstraint): + self._add_distance_constraint_to_directed_edge(constraint, first_constraint_in_cluster) + elif isinstance(constraint, RelAngle3Constraint) or isinstance( + constraint, AntiParallel3Constraint) or isinstance(constraint, Perp3Constraint): + self._add_angle_constraint_to_directed_edge(constraint, first_constraint_in_cluster) elif isinstance(constraint, SymmetryConstraint): points_solved = self.solve_symmetry_constraint(constraint) self.update_canvas_items(points_solved) @@ -290,19 +260,19 @@ def solve(self, source: GeoCon): points_solved.append(point) elif isinstance(source, RelAngle3Constraint): - edge_data_p21 = self.get_edge_data(source.vertex, source.start_point) - edge_data_p23 = self.get_edge_data(source.vertex, source.end_point) + edge_data_p21 = self.get_edge_data(source.p2, source.p1) + edge_data_p23 = self.get_edge_data(source.p2, source.p3) - old_angle = (source.vertex.measure_angle(source.start_point) - - source.vertex.measure_angle(source.end_point)) % (2 * np.pi) + old_angle = (source.p2.measure_angle(source.p1) - + source.p2.measure_angle(source.p3)) % (2 * np.pi) new_angle = source.param().rad() d_angle = new_angle - old_angle - rotation_point = source.vertex + rotation_point = source.p2 if edge_data_p21 and "angle" in edge_data_p21 and edge_data_p21["angle"] is source: - start = source.start_point if not source.vertex.root else source.vertex + start = source.p1 if not source.p2.root else source.p2 elif edge_data_p23 and "angle" in edge_data_p23 and edge_data_p23["angle"] is source: - start = source.end_point if not source.vertex.root else source.vertex + start = source.p3 if not source.p2.root else source.p2 d_angle *= -1 else: raise ValueError("Somehow no angle constraint found between the three points") @@ -320,11 +290,11 @@ def solve(self, source: GeoCon): # Get the branch to cut, if there is one root_rotation_branch = [] - if source.vertex.root and rotation_handle is not None: + if source.p2.root and rotation_handle is not None: root_rotation_branch = [point for point in networkx.bfs_tree(self, source=rotation_handle)] for point in all_downstream_points: - if point is source.vertex or point in root_rotation_branch: + if point is source.p2 or point in root_rotation_branch: continue dx_dy = np.array([[point.x().value() - rotation_point.x().value()], [point.y().value() - rotation_point.y().value()]]) diff --git a/pymead/gui/constraint_items.py b/pymead/gui/constraint_items.py index 5a882843..8a211095 100644 --- a/pymead/gui/constraint_items.py +++ b/pymead/gui/constraint_items.py @@ -212,24 +212,24 @@ def __init__(self, constraint: RelAngle3Constraint): self.update() def update(self): - dist1 = self.constraint.vertex.measure_distance(self.constraint.start_point) - dist2 = self.constraint.vertex.measure_distance(self.constraint.end_point) - angle1 = self.constraint.vertex.measure_angle(self.constraint.start_point) + dist1 = self.constraint.p2.measure_distance(self.constraint.p1) + dist2 = self.constraint.p2.measure_distance(self.constraint.p3) + angle1 = self.constraint.p2.measure_angle(self.constraint.p1) angle2 = angle1 - self.constraint.param().rad() mean_angle = np.mean([angle1, angle2]) text_distance = 0.15 * np.mean([dist1, dist2]) - text_x = self.constraint.vertex.x().value() + text_distance * np.cos(mean_angle) - text_y = self.constraint.vertex.y().value() + text_distance * np.sin(mean_angle) + text_x = self.constraint.p2.x().value() + text_distance * np.cos(mean_angle) + text_y = self.constraint.p2.y().value() + text_distance * np.sin(mean_angle) theta = np.linspace(angle1, angle2, 30) - x = self.constraint.vertex.x().value() + np.mean([dist1, dist2]) * 0.1 * np.cos(theta) - y = self.constraint.vertex.y().value() + np.mean([dist1, dist2]) * 0.1 * np.sin(theta) + x = self.constraint.p2.x().value() + np.mean([dist1, dist2]) * 0.1 * np.cos(theta) + y = self.constraint.p2.y().value() + np.mean([dist1, dist2]) * 0.1 * np.sin(theta) - line1_x = [self.constraint.vertex.x().value(), self.constraint.start_point.x().value()] - line1_y = [self.constraint.vertex.y().value(), self.constraint.start_point.y().value()] + line1_x = [self.constraint.p2.x().value(), self.constraint.p1.x().value()] + line1_y = [self.constraint.p2.y().value(), self.constraint.p1.y().value()] - line2_x = [self.constraint.vertex.x().value(), self.constraint.end_point.x().value()] - line2_y = [self.constraint.vertex.y().value(), self.constraint.end_point.y().value()] + line2_x = [self.constraint.p2.x().value(), self.constraint.p3.x().value()] + line2_y = [self.constraint.p2.y().value(), self.constraint.p3.y().value()] self.canvas_items[0].setData(x=x, y=y) self.canvas_items[1].setData(x=line1_x, y=line1_y) diff --git a/pymead/gui/parameter_tree.py b/pymead/gui/parameter_tree.py index 42bb91c2..2faa6367 100644 --- a/pymead/gui/parameter_tree.py +++ b/pymead/gui/parameter_tree.py @@ -632,8 +632,8 @@ def modifyDialogInternals(self, dialog: QDialog, layout: QGridLayout) -> None: layout.addWidget(AngleParamButton(self.rel_angle_constraint.param(), self.tree), row_count, 1) labels = ["Start", "Vertex", "End"] - points = [self.rel_angle_constraint.start_point, self.rel_angle_constraint.vertex, - self.rel_angle_constraint.end_point] + points = [self.rel_angle_constraint.p1, self.rel_angle_constraint.p2, + self.rel_angle_constraint.p3] for label, point in zip(labels, points): point_button = PointButton(point, self.tree) point_button.sigNameChanged.connect(self.onPointNameChange) diff --git a/pymead/tests/core_tests/test_geo_col.py b/pymead/tests/core_tests/test_geo_col.py index e0888d07..c767d961 100644 --- a/pymead/tests/core_tests/test_geo_col.py +++ b/pymead/tests/core_tests/test_geo_col.py @@ -289,8 +289,8 @@ def test_angle_dimension(self): # First, test the case where a param is directly specified param = AngleParam(0.25, "AngleDim") - start_point = Point(0.0, 0.0, "start_point", setting_from_geo_col=True) - end_point = Point(0.4, 0.4, "end_point", setting_from_geo_col=True) + start_point = Point(0.0, 0.0, "p1", setting_from_geo_col=True) + end_point = Point(0.4, 0.4, "p3", setting_from_geo_col=True) AngleDimension(tool_point=start_point, target_point=end_point, angle_param=param) # Make sure that the param angle value gets changed to 45 degrees @@ -304,8 +304,8 @@ def test_angle_dimension(self): self.assertAlmostEqual(135.0, dimension.param().value()) def test_units(self): - start_point = Point(0.0, 0.0, "start_point", setting_from_geo_col=True) - end_point = Point(0.3, 0.4, "end_point", setting_from_geo_col=True) + start_point = Point(0.0, 0.0, "p1", setting_from_geo_col=True) + end_point = Point(0.3, 0.4, "p3", setting_from_geo_col=True) dimension = LengthDimension(tool_point=start_point, target_point=end_point)