Skip to content

Commit

Permalink
Merge pull request #1348 from compas-dev/tolerance-singleton
Browse files Browse the repository at this point in the history
Make the tolerance class a singleton
  • Loading branch information
tomvanmele authored May 13, 2024
2 parents 9675b9c + 89b8b7c commit 8fc776f
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `compas.colors.Color.contrast`.
* Added `compas.geometry.Brep.from_plane`.
* Added `compas.tolerance.Tolerance.angulardeflection`.
* Added `compas.tolerance.Tolerance.update_from_dict`.
* Added `compas.scene.SceneObject.scene` attribute.

### Changed
Expand All @@ -35,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Changed use of `compas.geometry.allclose` to `compas.tolerance.TOL.is_allclose`.
* Changed use of `compas.geometry.close` to `compas.tolerance.TOL.is_close`.
* Changed imports of itertools to `compas.itertools` instead of `compas.utilities`.
* Changed `compas.tolerance.Tolerance` to a singleton, to ensure having only library-wide tolerance values.
* Updated `compas_rhino.conversions.point_to_compas` to allow for `Rhino.Geometry.Point` as input.
* Changed `compas.datastructures.Tree.print_hierarchy` to `compas.datastructures.Tree.__str__`.
* Fixed `compas.geometry.bbox_numpy.minimum_volume_box` to avoid `numpy.linalg.LinAlgError`.
Expand Down
79 changes: 61 additions & 18 deletions src/compas/tolerance.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class Tolerance(Data):
This value is called the "true value".
By convention, the second value is considered the "true value" by the comparison functions of this class.
The :class:`compas.tolerance.Tolerance` class is implemented using a "singleton" pattern and can therefore have only 1 (one) instance per context.
Usage of :attr:`compas.tolerance.TOL` outside of :mod:`compas` internals is therefore deprecated.
Examples
--------
>>> tol = Tolerance()
Expand All @@ -67,6 +70,16 @@ class Tolerance(Data):
"""

_instance = None
_is_inited = False

SUPPORTED_UNITS = ["M", "MM"]
"""{"M", "MM"}: Default tolerances are defined in relation to length units.
Currently, only meters ("M") and millimeters ("MM") are supported.
"""

ABSOLUTE = 1e-9
"""float: Determines when a number is small enough to be considered zero.
"""
Expand Down Expand Up @@ -108,8 +121,9 @@ class Tolerance(Data):
"""

def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(Tolerance, cls).__new__(cls)
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kwargs)
cls._is_inited = False
return cls._instance

@property
Expand Down Expand Up @@ -151,22 +165,34 @@ def __init__(
name=None,
):
super(Tolerance, self).__init__(name=name)
self._unit = None
self._absolute = None
self._relative = None
self._angular = None
self._approximation = None
self._precision = None
self._lineardeflection = None
self._angulardeflection = None
self.unit = unit
self.absolute = absolute
self.relative = relative
self.angular = angular
self.approximation = approximation
self.precision = precision
self.lineardeflection = lineardflection
self.angulardeflection = angulardflection
if not self._is_inited:
self._unit = None
self._absolute = None
self._relative = None
self._angular = None
self._approximation = None
self._precision = None
self._lineardeflection = None
self._angulardeflection = None

self._is_inited = True

if unit is not None:
self.unit = unit
if absolute is not None:
self.absolute = absolute
if relative is not None:
self.relative = relative
if angular is not None:
self.angular = angular
if approximation is not None:
self.approximation = approximation
if precision is not None:
self.precision = precision
if lineardflection is not None:
self.lineardeflection = lineardflection
if angulardflection is not None:
self.angulardeflection = angulardflection

# this can be autogenerated if we use slots
# __repr__: return f"{__class__.__name__}({', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())})}"
Expand All @@ -193,6 +219,23 @@ def reset(self):
self._lineardeflection = None
self._angulardeflection = None

def update_from_dict(self, tolerance):
"""Update the tolerance singleton from the key-value pairs found in a dict.
Parameters
----------
tolerance : dict
A dictionary containing named tolerance values.
Returns
-------
None
"""
for name in tolerance:
if hasattr(self, name):
setattr(self, name, tolerance[name])

@property
def units(self):
return self._unit
Expand Down

0 comments on commit 8fc776f

Please sign in to comment.