hub/venv/lib/python3.7/site-packages/trimesh/units.py

124 lines
3.6 KiB
Python
Raw Normal View History

"""
units.py
--------------
Deal with physical unit systems (i.e. inches, mm)
Very basic conversions, and no requirement for
sympy.physics.units or pint.
"""
import json
from .constants import log
from . import resources
# scaling factors from various unit systems to inches
TO_INCH = json.loads(resources.get('units_to_inches.json'))
def unit_conversion(current, desired):
"""
Calculate the conversion from one set of units to another.
Parameters
---------
current : str
Unit system values are in now (eg 'millimeters')
desired : str
Unit system we'd like values in (eg 'inches')
Returns
---------
conversion : float
Number to multiply by to put values into desired units
"""
current = str(current).strip().lower()
desired = str(desired).strip().lower()
conversion = TO_INCH[current] / TO_INCH[desired]
return conversion
def units_from_metadata(obj, guess=True):
"""
Try to extract hints from metadata and if that fails
guess based on the object scale.
Parameters
------------
obj: object
Has attributes 'metadata' (dict) and 'scale' (float)
guess : bool
If metadata doesn't indicate units, guess from scale
Returns
------------
units: str
A guess of what the units might be
"""
# try to guess from metadata
for key in ['file_name', 'name']:
if key not in obj.metadata:
continue
# get the string which might contain unit hints
hints = obj.metadata[key].lower()
if 'unit' in hints:
# replace all delimiter options with white space
for delim in '_-.':
hints = hints.replace(delim, ' ')
# loop through each hint
for hint in hints.strip().split():
# key word is "unit" or "units"
if 'unit' not in hint:
continue
# get rid of keyword and whitespace
hint = hint.replace(
'units', '').replace(
'unit', '').strip()
# if the hint is a valid unit return it
if hint in TO_INCH:
return hint
if not guess:
raise ValueError('no units and not allowed to guess')
# we made it to the wild ass guess section
# if the scale is larger than 100 mystery units
# declare the model to be millimeters, otherwise inches
log.warning('no units: guessing from scale')
if float(obj.scale) > 100.0:
return 'millimeters'
else:
return 'inches'
def _convert_units(obj, desired, guess=False):
"""
Given an object with scale and units try to scale
to different units via the object's `apply_scale`.
Parameters
---------
obj : object
With apply_scale method (i.e. Trimesh, Path2D, etc)
desired : str
Units desired (eg 'inches')
guess: bool
Whether we are allowed to guess the units
if they are not specified.
"""
if obj.units is None:
# try to extract units from metadata
# if nothing specified in metadata and not allowed
# to guess will raise a ValueError
obj.units = units_from_metadata(obj, guess=guess)
log.info('converting units from %s to %s', obj.units, desired)
# float, conversion factor
conversion = unit_conversion(obj.units, desired)
# apply scale uses transforms which preserve
# cached properties (rather than just multiplying vertices)
obj.apply_scale(conversion)
# units are now desired units
obj.units = desired