diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 2989dcb44a..50d63c1190 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -41,8 +41,8 @@ class Line(TipableVMobject): def __init__( self, - start: Point3D = LEFT, - end: Point3D = RIGHT, + start: Point3D | Mobject = LEFT, + end: Point3D | Mobject = RIGHT, buff: float = 0, path_arc: float | None = None, **kwargs, @@ -63,16 +63,32 @@ def generate_points(self) -> None: def set_points_by_ends( self, - start: Point3D, - end: Point3D, + start: Point3D | Mobject, + end: Point3D | Mobject, buff: float = 0, path_arc: float = 0, ) -> None: + """Sets the points of the line based on its start and end points. + Unlike :meth:`put_start_and_end_on`, this method respects `self.buff` and + Mobject bounding boxes. + + Parameters + ---------- + start + The start point or Mobject of the line. + end + The end point or Mobject of the line. + buff + The empty space between the start and end of the line, by default 0. + path_arc + The angle of a circle spanned by this arc, by default 0 which is a straight line. + """ + self._set_start_and_end_attrs(start, end) if path_arc: arc = ArcBetweenPoints(self.start, self.end, angle=self.path_arc) self.set_points(arc.points) else: - self.set_points_as_corners([start, end]) + self.set_points_as_corners([self.start, self.end]) self._account_for_buff(buff) @@ -93,7 +109,9 @@ def _account_for_buff(self, buff: float) -> Self: self.pointwise_become_partial(self, buff_proportion, 1 - buff_proportion) return self - def _set_start_and_end_attrs(self, start: Point3D, end: Point3D) -> None: + def _set_start_and_end_attrs( + self, start: Point3D | Mobject, end: Point3D | Mobject + ) -> None: # If either start or end are Mobjects, this # gives their centers rough_start = self._pointify(start) diff --git a/manim/mobject/graph.py b/manim/mobject/graph.py index d54c1e0457..72a26d27db 100644 --- a/manim/mobject/graph.py +++ b/manim/mobject/graph.py @@ -561,6 +561,7 @@ class GenericGraph(VMobject, metaclass=ConvertToOpenGL): all other configuration options for a vertex. edge_type The mobject class used for displaying edges in the scene. + Must be a subclass of :class:`~.Line` for default updaters to work. edge_config Either a dictionary containing keyword arguments to be passed to the class specified via ``edge_type``, or a dictionary whose @@ -1559,7 +1560,12 @@ def _populate_edge_dict( def update_edges(self, graph): for (u, v), edge in graph.edges.items(): # Undirected graph has a Line edge - edge.put_start_and_end_on(graph[u].get_center(), graph[v].get_center()) + edge.set_points_by_ends( + graph[u].get_center(), + graph[v].get_center(), + buff=self._edge_config.get("buff", 0), + path_arc=self._edge_config.get("path_arc", 0), + ) def __repr__(self: Graph) -> str: return f"Undirected graph on {len(self.vertices)} vertices and {len(self.edges)} edges" @@ -1768,10 +1774,15 @@ def update_edges(self, graph): deformed. """ for (u, v), edge in graph.edges.items(): - edge_type = type(edge) tip = edge.pop_tips()[0] - new_edge = edge_type(self[u], self[v], **self._edge_config[(u, v)]) - edge.become(new_edge) + # Passing the Mobject instead of the vertex makes the tip + # stop on the bounding box of the vertex. + edge.set_points_by_ends( + graph[u], + graph[v], + buff=self._edge_config.get("buff", 0), + path_arc=self._edge_config.get("path_arc", 0), + ) edge.add_tip(tip) def __repr__(self: DiGraph) -> str: