Skip to content

Commit

Permalink
Merge pull request #2098 from mikedh/release/units
Browse files Browse the repository at this point in the history
Release: Scene Units
  • Loading branch information
mikedh authored Dec 19, 2023
2 parents 31ea046 + cbcb5fb commit 7c90a94
Show file tree
Hide file tree
Showing 18 changed files with 50 additions and 43 deletions.
6 changes: 2 additions & 4 deletions docs/content/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ if __name__ == '__main__':
When you remove the embed and see the profile result you can then tweak the lines that are slow before finishing the function.

### Automatic Formatting
Trimesh uses `ruff` and `black` configured in `pyproject.toml`, you can run with:
Trimesh uses `ruff` for both linting and formatting which is configured in `pyproject.toml`, you can run with:
```
ruff . --fix
black .
ruff format .
```
It can fix a lot of formatting issues automatically. We also periodically run `black` to autoformat the codebase.


## Docstrings

Expand Down
3 changes: 1 addition & 2 deletions docs/content/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ Trimesh has a lot of soft-required upstream packages, and we try to make sure th
|`scikit-image`| Used in voxel ops | | `recommend`|
|`mapbox-earcut`| Triangulate 2D polygons | `triangle` which has an unusual license | `easy`|
|`psutil`| Get current memory usage, useful for checking to see if we're going to run out of memory instantiating a giant array | | `recommend`|
|`ruff`| A static code analyzer that replaces `flake8`. | `flake8` | `test`|
|`black`| A code formatter which fixes whitespace issues automatically. | | `test`|
|`ruff`| A static code analyzer and formatter that replaces `flake8` and `black`. | `flake8` | `test`|
|`pytest`| A test runner. | | `test`|
|`pytest-cov`| A plugin to calculate test coverage. | | `test`|
|`pyinstrument`| A sampling based profiler for performance tweaking. | | `test`|
Expand Down
9 changes: 2 additions & 7 deletions 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.0.6"
version = "4.0.7"
authors = [{name = "Michael Dawson-Haggerty", email = "[email protected]"}]
license = {file = "LICENSE.md"}
description = "Import, export, process, analyze and view triangular meshes."
Expand Down Expand Up @@ -103,8 +103,7 @@ test = [
"pymeshlab",
"pyinstrument",
"matplotlib",
"ruff",
"black",
"ruff"
]

# requires pip >= 21.2
Expand Down Expand Up @@ -140,7 +139,3 @@ ignore = [
]
line-length = 90


[tool.black]
line-length = 90
target-version = ['py37']
16 changes: 16 additions & 0 deletions tests/test_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,22 @@ def test_scaling_3D(self):

assert g.np.allclose(scaled.extents / extents, factor)

def test_mixed_units(self):
# create two boxes in a scene
a = g.trimesh.creation.box()
a.units = "in"

b = g.trimesh.creation.box()
b.units = "m"

# mixed units should be None
s = g.trimesh.Scene([a, b])
assert s.units is None

# now all units should be meters and scene should report that
a.units = "m"
assert s.units == "m"

def test_scaling_3D_mixed(self):
# same as test_scaling_3D but input scene contains 2D and 3D geometry
scene = g.get_mesh("scenes.zip", mixed=True)
Expand Down
4 changes: 2 additions & 2 deletions trimesh/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1935,7 +1935,7 @@ def compute_stable_poses(
This method returns the 4x4 homogeneous transform matrices that place
the shape against the planar surface with the z-axis pointing upwards
and a list of the probabilities for each pose.
The transforms and probabilties that are returned are sorted, with the
The transforms and probabilities that are returned are sorted, with the
most probable pose first.
Parameters
Expand Down Expand Up @@ -2121,7 +2121,7 @@ def smoothed(self, **kwargs):
DEPRECATED: use `mesh.smooth_shaded` or `trimesh.graph.smooth_shade(mesh)`
"""
warnings.warn(
"`mesh.smoothed()` is deprected and will be removed in March 2024: "
"`mesh.smoothed()` is deprecated and will be removed in March 2024: "
+ "use `mesh.smooth_shaded` or `trimesh.graph.smooth_shade(mesh)`",
category=DeprecationWarning,
stacklevel=2,
Expand Down
2 changes: 1 addition & 1 deletion trimesh/bounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def oriented_bounds_coplanar(points):
# matrices which will rotate each hull normal to [0,0,1]
if normal is None:
# convert face normals to spherical coordinates on the upper hemisphere
# the vector_hemisphere call effectivly merges negative but otherwise
# the vector_hemisphere call effectively merges negative but otherwise
# identical vectors
spherical_coords = util.vector_to_spherical(util.vector_hemisphere(hull_normals))
# the unique_rows call on merge angles gets unique spherical directions to check
Expand Down
2 changes: 1 addition & 1 deletion trimesh/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def identifier_simple(mesh):
Return a basic identifier for a mesh consisting of
properties that have been hand tuned to be somewhat
robust to rigid transformations and different
tesselations.
tessellations.
Parameters
------------
Expand Down
2 changes: 1 addition & 1 deletion trimesh/exchange/ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ def _parse_header(file_obj):
# a property is a member of an element
elif "property" in line[0]:
# is the property a simple single value, like:
# `propert float x`
# `property float x`
if len(line) == 3:
dtype, field = line[1:]
elements[name]["properties"][str(field)] = endian + _dtypes[dtype]
Expand Down
2 changes: 1 addition & 1 deletion trimesh/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def weighted_vertex_normals(
):
"""
Compute vertex normals from the faces that contain that vertex.
The contibution of a face's normal to a vertex normal is the
The contribution of a face's normal to a vertex normal is the
ratio of the corner-angle in which the vertex is, with respect
to the sum of all corner-angles surrounding the vertex.
Expand Down
2 changes: 1 addition & 1 deletion trimesh/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ def smoothed(*args, **kwargs):
DEPRECATED: use `trimesh.graph.smooth_shade(mesh, ...)`
"""
warnings.warn(
"`trimesh.graph.smoothed` is deprected and will be removed in March 2024: "
"`trimesh.graph.smoothed` is deprecated and will be removed in March 2024: "
+ "use `trimesh.graph.smooth_shade(mesh, ...)`",
category=DeprecationWarning,
stacklevel=2,
Expand Down
4 changes: 2 additions & 2 deletions trimesh/path/segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,12 @@ def clean(segments: NDArray[float64], digits: int = 10) -> NDArray[float64]:
# find the groups of values with identical origins and vectors
groups = group_rows(np.column_stack((origins, vectors)), digits=digits)

# get the union of every interval range for colinear segements
# get the union of every interval range for colinear segments
unions = [union(param[g][param[g][:, 0].argsort()], sort=False) for g in groups]
# reconstruct indexes for the origins and vectors
indexes = np.concatenate([g[: len(u)] for g, u in zip(groups, unions)])

# conver parametric form back into vertex-segment form
# convert parametric form back into vertex-segment form
return parameters_to_segments(
origins=origins[indexes], vectors=vectors[indexes], parameters=np.vstack(unions)
)
Expand Down
2 changes: 1 addition & 1 deletion trimesh/path/traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def sample(self, distances):
offsets = np.append(0, self._cum_norm)[positions]
# the distance past the reference vertex we need to travel
projection = distances - offsets
# find out which dirction we need to project
# find out which direction we need to project
direction = self._unit_vec[positions]
# find out which vertex we're offset from
origin = self._points[positions]
Expand Down
2 changes: 1 addition & 1 deletion trimesh/poses.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def compute_stable_poses(mesh, center_mass=None, sigma=0.0, n_samples=1, thresho
the shape against the planar surface with the z-axis pointing upwards
and a list of the probabilities for each pose.
The transforms and probabilties that are returned are sorted, with the
The transforms and probabilities that are returned are sorted, with the
most probable pose first.
Parameters
Expand Down
2 changes: 1 addition & 1 deletion trimesh/ray/ray_triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def ray_bounds(ray_origins, ray_directions, bounds, buffer_dist=1e-5):
t_a = t[:, 0].reshape((-1, 1))
t_b = t[:, 1].reshape((-1, 1))

# the cartesion point for where the line hits the plane defined by
# the cartesian point for where the line hits the plane defined by
# axis
on_a = (ray_directions * t_a) + ray_origins
on_b = (ray_directions * t_b) + ray_origins
Expand Down
2 changes: 1 addition & 1 deletion trimesh/scene/cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def look_at(points, fov, rotation=None, distance=None, center=None, pad=None):
points_c -= center_c

# Find the minimum distance for the camera from the origin
# so that all points fit in the view frustrum
# so that all points fit in the view frustum
tfov = np.tan(np.radians(fov) / 2.0)

if distance is None:
Expand Down
27 changes: 13 additions & 14 deletions trimesh/scene/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .. import caching, convex, grouping, inertia, transformations, units, util
from ..exchange import export
from ..parent import Geometry3D
from ..typed import Optional
from ..util import unique_name
from . import cameras, lighting
from .transforms import SceneGraph
Expand Down Expand Up @@ -955,24 +956,22 @@ def save_image(self, resolution=None, **kwargs):
return png

@property
def units(self) -> str:
def units(self) -> Optional[str]:
"""
Get the units for every model in the scene, and
raise a ValueError if there are mixed units.
Get the units for every model in the scene. If the scene has
mixed units or no units this will return None.
Returns
-----------
units : str
Units for every model in the scene
"""
existing = [i.units for i in self.geometry.values()]

if any(existing[0] != e for e in existing):
# if all of our geometry doesn't have the same units already
# this function will only do some hot nonsense
raise ValueError("models in scene have inconsistent units!")

return existing[0]
units
Units for every model in the scene or None
if there are no units or mixed units
"""
# get a set of the units of every geometry
existing = {i.units for i in self.geometry.values()}
if len(existing) == 1:
return existing.pop()
return None

@units.setter
def units(self, value: str):
Expand Down
4 changes: 2 additions & 2 deletions trimesh/smoothing.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def filter_mut_dif_laplacian(
):
"""
Smooth a mesh in-place using laplacian smoothing using a
mutable difusion laplacian.
mutable diffusion laplacian.
Articles
Barroqueiro, B., Andrade-Campos, A., Dias-de-Oliveira,
Expand Down Expand Up @@ -224,7 +224,7 @@ def filter_mut_dif_laplacian(

# Number of passes
for _index in range(iterations):
# Mutable difusion
# Mutable diffusion
normals = get_vertices_normals(mesh)
qi = laplacian_operator.dot(vertices)
pi_qi = vertices - qi
Expand Down
2 changes: 1 addition & 1 deletion trimesh/visual/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def unmerge_faces(faces, *args, **kwargs):
# and then median before converting back to int: could also do this as
# a column diff and sort but this seemed easier and is fast enough
# turn default attribute value of -1 to nan before median computation
# and use nanmedian to compute the median igoring the nan values
# and use nanmedian to compute the median ignoring the nan values
masks_nan = np.where(masks != -1, masks, np.NaN)
result.append(np.nanmedian(masks_nan, axis=0).astype(np.int64))

Expand Down

0 comments on commit 7c90a94

Please sign in to comment.