-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added ConvexHull
, ConvexHull3D
, Label
and LabeledPolygram
#3933
Conversation
fixed added utils (i.e., Incomplete ordering and Explicit returns mixed with implicit), added :quality: high to docstrings, made ConvexHullExample determined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your changes!
It is weird that the ReadTheDocs pipeline failed, even when you (and me) successfully ran make html
locally. It sometimes fails randomly. Maybe if you push another commit it will run successfully.
I've taken a look at some of the code and left some suggestions. It's mainly about typing in polylabel.py
and qhull.py
.
7393423
to
3d2ee4a
Compare
3d2ee4a
to
03cc46c
Compare
manim/utils/polylabel.py
Outdated
|
||
Parameters | ||
---------- | ||
rings : list[np.ndarray] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before: the parameters should not be typed again in docstrings.
rings : list[np.ndarray] | |
rings |
manim/utils/polylabel.py
Outdated
return self.d >= other.d | ||
|
||
|
||
def PolyLabel(rings: list[list[Point3D]], precision: float = 0.01) -> Cell: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PascalCase
is reserved for class definitions. For functions, use snake_case
instead.
rings
could be a Sequence[Point3D_Array]
instead.
def PolyLabel(rings: list[list[Point3D]], precision: float = 0.01) -> Cell: | |
def polylabel(rings: Sequence[Point3D_Array], precision: float = 0.01) -> Cell: |
manim/utils/qhull.py
Outdated
self.outside: dict[Facet, tuple[np.ndarray, np.ndarray | None]] = {} | ||
self.neighbors: dict[SubFacet, set[Facet]] = {} | ||
self.unclaimed: np.ndarray | None = None | ||
self.internal: np.ndarray | None = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.outside: dict[Facet, tuple[np.ndarray, np.ndarray | None]] = {} | |
self.neighbors: dict[SubFacet, set[Facet]] = {} | |
self.unclaimed: np.ndarray | None = None | |
self.internal: np.ndarray | None = None | |
self.outside: dict[Facet, tuple[PointND_Array, PointND | None]] = {} | |
self.neighbors: dict[SubFacet, set[Facet]] = {} | |
self.unclaimed: PointND_Array | None = None | |
self.internal: PointND | None = None |
manim/utils/qhull.py
Outdated
self.outside[facet] = (outside, eye) | ||
self.unclaimed = self.unclaimed[~mask] | ||
|
||
def compute_horizon(self, eye: np.ndarray, start_facet: Facet) -> Horizon: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def compute_horizon(self, eye: np.ndarray, start_facet: Facet) -> Horizon: | |
def compute_horizon(self, eye: PointND, start_facet: Facet) -> Horizon: |
manim/utils/qhull.py
Outdated
return horizon | ||
|
||
def _recursive_horizon( | ||
self, eye: np.ndarray, facet: Facet, horizon: Horizon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self, eye: np.ndarray, facet: Facet, horizon: Horizon | |
self, eye: PointND, facet: Facet, horizon: Horizon |
manim/utils/qhull.py
Outdated
horizon.boundary.append(subfacet) | ||
return True | ||
|
||
def build(self, points: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def build(self, points: np.ndarray): | |
def build(self, points: PointND_Array) -> None: |
manim/utils/polylabel.py
Outdated
cy = np.sum((y + yr) * factor) / (6.0 * self.area) | ||
self.centroid = np.array([cx, cy]) | ||
|
||
def compute_distance(self, point: np.ndarray) -> float: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def compute_distance(self, point: np.ndarray) -> float: | |
def compute_distance(self, point: PointND) -> float: |
manim/utils/polylabel.py
Outdated
d = np.min(np.linalg.norm(self.start + self.diff * clips - point, axis=1)) | ||
return d if self.inside(point) else -d | ||
|
||
def inside(self, point: np.ndarray) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def inside(self, point: np.ndarray) -> bool: | |
def inside(self, point: PointND) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello! Sorry for the delay on reviewing this PR. Here are the changes I propose this time. Thanks for publishing this PR!
On a second thought, I feel that implementing PointND
and PointND_Array
becomes more and more necessary for us as I continue reviewing this PR, so, if possible, I would like to ask you to implement them. Otherwise, in order to have a separate PR making that change instead, I could add them in another PR.
manim/utils/qhull.py
Outdated
import numpy as np | ||
|
||
|
||
class Point: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There already exists a Point
mobject in Manim: it's manim.mobject.types.point_cloud_mobject.Point
. Whether we should actually keep this Point
in Manim or not is pretty debatable, but, in the meantime, let's change this class' name to something else to avoid name clashes.
Since this is merely an auxiliar class which is only used in this file, maybe it could be prefixed with an underscore, or be called QuickHullPoint
.
class Point: | |
class QuickHullPoint: |
Hello there! I just added the |
added `label_config` and `box_config` and `frame_config` for additional configuration options and cleaner interface. added `InternalPointND` and `PointND ` and `InternalPointND_Array` and `PointND_Array` for typing. updated docstring.
for more information, see https://pre-commit.ci
Hello there! Apologies for the delay here. Do let me know if any additional changes are needed. Also, not sure how to handle the pre-commit typing issue with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your time! There's a small batch of comments I left, but they should be the last ones before we ship this!
manim/mobject/geometry/labeled.py
Outdated
label_config: dict | None = None, | ||
box_config: dict | None = None, | ||
frame_config: dict | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using dict[str, Any]
instead of just dict
is preferable here for two reasons:
- The keys of
dict
can be any immutable object, but here we require that these config dictionaries havestr
keys. - Even if we had
dict[Any, Any]
, we would prefer to be explicit anyways.
label_config: dict | None = None, | |
box_config: dict | None = None, | |
frame_config: dict | None = None, | |
label_config: dict[str, Any] | None = None, | |
box_config: dict[str, Any] | None = None, | |
frame_config: dict[str, Any] | None = None, |
manim/mobject/geometry/labeled.py
Outdated
label_config: dict | None = None, | ||
box_config: dict | None = None, | ||
frame_config: dict | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
label_config: dict | None = None, | |
box_config: dict | None = None, | |
frame_config: dict | None = None, | |
label_config: dict[str, Any] | None = None, | |
box_config: dict[str, Any] | None = None, | |
frame_config: dict[str, Any] | None = None, |
manim/mobject/geometry/labeled.py
Outdated
Label that will be displayed. | ||
label_config | ||
A dictionary containing the configuration for the label. | ||
This is only applied if `label` is of type `str`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only applied if `label` is of type `str`. | |
This is only applied if ``label`` is of type ``str``. |
manim/mobject/geometry/labeled.py
Outdated
:class:`LabeledArrow` | ||
label_config | ||
A dictionary containing the configuration for the label. | ||
This is only applied if `label` is of type `str`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only applied if `label` is of type `str`. | |
This is only applied if ``label`` is of type ``str``. |
manim/mobject/geometry/labeled.py
Outdated
Determine the opacity of the label box by passing a value in the range [0-1], where 0 indicates complete transparency and 1 means full opacity. | ||
label_config | ||
A dictionary containing the configuration for the label. | ||
This is only applied if `label` is of type `str`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only applied if `label` is of type `str`. | |
This is only applied if ``label`` is of type ``str``. |
manim/mobject/geometry/labeled.py
Outdated
Parameters | ||
---------- | ||
vertex_groups | ||
Vertices passed to Polygram constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A reference to the Polygram
superclass would be great for our documentation:
Vertices passed to Polygram constructor. | |
Vertices passed to the :class:`~.Polygram` constructor. |
@@ -122,6 +122,7 @@ def __init__( | |||
buff=buff, | |||
**kwargs, | |||
) | |||
self.color: ManimColor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry about this shape_matchers
issue: it was introduced in a different PR, and it would be solved in another one.
self.color: ManimColor |
manim/utils/qhull.py
Outdated
from manim.typing import PointND, PointND_Array | ||
|
||
|
||
class Point: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, don't forget about this one!
class Point: | |
class QuickHullPoint: |
Co-authored-by: Francisco Manríquez Novoa <[email protected]>
Co-authored-by: Francisco Manríquez Novoa <[email protected]>
ConvexHull
, ConvexHull3D
, Label
and LabeledPolygram
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thank you for your time.
Overview: What does this pull request change?
This PR introduces four additional features and two utilities.
manim.mobject.geometry.polygram.ConvexHull
which constructs a ConvexHull through a set of points.manim.mobject.three\_d.polyhedra.ConvexHull3D
which constructs a ConvexHull through a set of points.manim.mobject.geometry.labeled.Label
which constructs a boxed label.manim.mobject.geometry.labeled.LabeledPolygram
which constructs a polygram containing a label box at its pole of inaccessibility. This is the point inside a polygon that is farthest from its edges.manim.utilities.qhull
which constructs a ConvexHull through a set of points. It extends to arbitrary dimensions.manim.utilities.polylabel
which computes the pole of inaccessibility for any complex polygon to a given precision.Notably, none of these introduce breaking changes nor require additional dependencies.
Motivation and Explanation: Why and how do your changes improve the library?
The first two are useful in scenarios where the user has a collection of points but does not know what order they should be plotted. In 2D this reduces to sorting by angle bit in 3D the task is more complex and can be handled automagically. The fourth is useful for labeling polygons.
Links to added or changed documentation pages
I am not sure how to format this, but here is what the doc pages look like locally:
Further Information and Comments
Reviewer Checklist