Skip to content

Commit

Permalink
Merge pull request #2201 from mikedh/fix/prim
Browse files Browse the repository at this point in the history
Fix: escape none in primitives to avoid warning
  • Loading branch information
mikedh committed Mar 31, 2024
2 parents f00f271 + 58b259e commit e1979b9
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 11 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
[project]
name = "trimesh"
requires-python = ">=3.7"
version = "4.2.3"
version = "4.2.4"
authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}]
license = {file = "LICENSE.md"}
description = "Import, export, process, analyze and view triangular meshes."
Expand Down
23 changes: 23 additions & 0 deletions tests/test_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,29 @@ def test_copy(self):
assert g.np.allclose(box.center_mass, box_copy.center_mass)
assert box.metadata["foo"] == box_copy.metadata["foo"]

def test_sphere_subdivisions(self):
# make sure we don't subdivide when asked not to
a = g.trimesh.creation.icosphere(subdivisions=0)
assert a.faces.shape == g.trimesh.creation.icosahedron().faces.shape

# now apply the subdivisions ourself
a = a.subdivide().subdivide()

# should have the same subdivisions as manually doing this
b = g.trimesh.primitives.Sphere(subdivisions=2)

assert a.faces.shape == b.faces.shape

def test_sphere_subdivisions_radius(self):
tf = list(g.random_transforms(4))
for r in [1e-4, 1.1, 3, 1213.22]:
for subd in range(4):
s = g.trimesh.primitives.Sphere(
radius=r, transform=tf[subd], subdivisions=subd
)
rc = g.np.linalg.norm(s.vertices - s.center_mass, axis=1)
assert g.np.isclose(rc.mean(), r)


if __name__ == "__main__":
g.trimesh.util.attach_to_log()
Expand Down
5 changes: 3 additions & 2 deletions trimesh/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1937,8 +1937,9 @@ def compute_stable_poses(

def subdivide(self, face_index: Optional[ArrayLike] = None) -> "Trimesh":
"""
Subdivide a mesh, with each subdivided face replaced
with four smaller faces.
Subdivide a mesh with each subdivided face replaced
with four smaller faces. Will return a copy of current
mesh with subdivided faces.
Parameters
------------
Expand Down
10 changes: 10 additions & 0 deletions trimesh/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,16 +855,26 @@ def icosphere(subdivisions: Integer = 3, radius: Number = 1.0, **kwargs):
ico : trimesh.Trimesh
Meshed sphere
"""
radius = float(radius)
subdivisions = int(subdivisions)

ico = icosahedron()
ico._validate = False

for _ in range(subdivisions):
ico = ico.subdivide()
vectors = ico.vertices
scalar = np.sqrt(np.dot(vectors**2, [1, 1, 1]))
unit = vectors / scalar.reshape((-1, 1))
ico.vertices += unit * (radius - scalar).reshape((-1, 1))

# if we didn't subdivide we still need to refine the radius
if subdivisions <= 0:
vectors = ico.vertices
scalar = np.sqrt(np.dot(vectors**2, [1, 1, 1]))
unit = vectors / scalar.reshape((-1, 1))
ico.vertices += unit * (radius - scalar).reshape((-1, 1))

if "color" in kwargs:
warnings.warn(
"`icosphere(color=...)` is deprecated and will "
Expand Down
25 changes: 17 additions & 8 deletions trimesh/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from . import transformations as tf
from .base import Trimesh
from .constants import log, tol
from .typed import ArrayLike, Integer, Number, Optional

# immutable identity matrix for checks
_IDENTITY = np.eye(4)
Expand Down Expand Up @@ -57,7 +58,8 @@ def faces(self):

@faces.setter
def faces(self, values):
log.warning("primitive faces are immutable: not setting!")
if values is not None:
raise ValueError("primitive faces are immutable: not setting!")

@property
def vertices(self):
Expand All @@ -71,7 +73,7 @@ def vertices(self):
@vertices.setter
def vertices(self, values):
if values is not None:
log.warning("primitive vertices are immutable: not setting!")
raise ValueError("primitive vertices are immutable: not setting!")

@property
def face_normals(self):
Expand Down Expand Up @@ -550,28 +552,32 @@ def _create_mesh(self):

class Sphere(Primitive):
def __init__(
self, radius=1.0, center=None, transform=None, subdivisions=3, mutable=True
self,
radius: Number = 1.0,
center: Optional[ArrayLike] = None,
transform: Optional[ArrayLike] = None,
subdivisions: Integer = 3,
mutable: bool = True,
):
"""
Create a Sphere Primitive, a subclass of Trimesh.
Parameters
----------
radius : float
radius
Radius of sphere
center : None or (3,) float
Center of sphere.
transform : None or (4, 4) float
Full homogeneous transform. Pass `center` OR `transform.
subdivisions : int
subdivisions
Number of subdivisions for icosphere.
mutable : bool
mutable
Are extents and transform mutable after creation.
"""

super().__init__()

defaults = {"radius": 1.0, "transform": np.eye(4), "subdivisions": 3}
constructor = {"radius": float(radius), "subdivisions": int(subdivisions)}
# center is a helper method for "transform"
# since a sphere is rotationally symmetric
Expand All @@ -586,7 +592,10 @@ def __init__(

# create the attributes object
self.primitive = PrimitiveAttributes(
self, defaults=defaults, kwargs=constructor, mutable=mutable
self,
defaults={"radius": 1.0, "transform": np.eye(4), "subdivisions": 3},
kwargs=constructor,
mutable=mutable,
)

@property
Expand Down

0 comments on commit e1979b9

Please sign in to comment.