Skip to content

Commit 8fc776f

Browse files
authored
Merge pull request #1348 from compas-dev/tolerance-singleton
Make the tolerance class a singleton
2 parents 9675b9c + 89b8b7c commit 8fc776f

File tree

2 files changed

+63
-18
lines changed

2 files changed

+63
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
* Added `compas.colors.Color.contrast`.
1616
* Added `compas.geometry.Brep.from_plane`.
1717
* Added `compas.tolerance.Tolerance.angulardeflection`.
18+
* Added `compas.tolerance.Tolerance.update_from_dict`.
1819
* Added `compas.scene.SceneObject.scene` attribute.
1920

2021
### Changed
@@ -35,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3536
* Changed use of `compas.geometry.allclose` to `compas.tolerance.TOL.is_allclose`.
3637
* Changed use of `compas.geometry.close` to `compas.tolerance.TOL.is_close`.
3738
* Changed imports of itertools to `compas.itertools` instead of `compas.utilities`.
39+
* Changed `compas.tolerance.Tolerance` to a singleton, to ensure having only library-wide tolerance values.
3840
* Updated `compas_rhino.conversions.point_to_compas` to allow for `Rhino.Geometry.Point` as input.
3941
* Changed `compas.datastructures.Tree.print_hierarchy` to `compas.datastructures.Tree.__str__`.
4042
* Fixed `compas.geometry.bbox_numpy.minimum_volume_box` to avoid `numpy.linalg.LinAlgError`.

src/compas/tolerance.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class Tolerance(Data):
5353
This value is called the "true value".
5454
By convention, the second value is considered the "true value" by the comparison functions of this class.
5555
56+
The :class:`compas.tolerance.Tolerance` class is implemented using a "singleton" pattern and can therefore have only 1 (one) instance per context.
57+
Usage of :attr:`compas.tolerance.TOL` outside of :mod:`compas` internals is therefore deprecated.
58+
5659
Examples
5760
--------
5861
>>> tol = Tolerance()
@@ -67,6 +70,16 @@ class Tolerance(Data):
6770
6871
"""
6972

73+
_instance = None
74+
_is_inited = False
75+
76+
SUPPORTED_UNITS = ["M", "MM"]
77+
"""{"M", "MM"}: Default tolerances are defined in relation to length units.
78+
79+
Currently, only meters ("M") and millimeters ("MM") are supported.
80+
81+
"""
82+
7083
ABSOLUTE = 1e-9
7184
"""float: Determines when a number is small enough to be considered zero.
7285
"""
@@ -108,8 +121,9 @@ class Tolerance(Data):
108121
"""
109122

110123
def __new__(cls, *args, **kwargs):
111-
if not hasattr(cls, "_instance"):
112-
cls._instance = super(Tolerance, cls).__new__(cls)
124+
if not cls._instance:
125+
cls._instance = object.__new__(cls, *args, **kwargs)
126+
cls._is_inited = False
113127
return cls._instance
114128

115129
@property
@@ -151,22 +165,34 @@ def __init__(
151165
name=None,
152166
):
153167
super(Tolerance, self).__init__(name=name)
154-
self._unit = None
155-
self._absolute = None
156-
self._relative = None
157-
self._angular = None
158-
self._approximation = None
159-
self._precision = None
160-
self._lineardeflection = None
161-
self._angulardeflection = None
162-
self.unit = unit
163-
self.absolute = absolute
164-
self.relative = relative
165-
self.angular = angular
166-
self.approximation = approximation
167-
self.precision = precision
168-
self.lineardeflection = lineardflection
169-
self.angulardeflection = angulardflection
168+
if not self._is_inited:
169+
self._unit = None
170+
self._absolute = None
171+
self._relative = None
172+
self._angular = None
173+
self._approximation = None
174+
self._precision = None
175+
self._lineardeflection = None
176+
self._angulardeflection = None
177+
178+
self._is_inited = True
179+
180+
if unit is not None:
181+
self.unit = unit
182+
if absolute is not None:
183+
self.absolute = absolute
184+
if relative is not None:
185+
self.relative = relative
186+
if angular is not None:
187+
self.angular = angular
188+
if approximation is not None:
189+
self.approximation = approximation
190+
if precision is not None:
191+
self.precision = precision
192+
if lineardflection is not None:
193+
self.lineardeflection = lineardflection
194+
if angulardflection is not None:
195+
self.angulardeflection = angulardflection
170196

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

222+
def update_from_dict(self, tolerance):
223+
"""Update the tolerance singleton from the key-value pairs found in a dict.
224+
225+
Parameters
226+
----------
227+
tolerance : dict
228+
A dictionary containing named tolerance values.
229+
230+
Returns
231+
-------
232+
None
233+
234+
"""
235+
for name in tolerance:
236+
if hasattr(self, name):
237+
setattr(self, name, tolerance[name])
238+
196239
@property
197240
def units(self):
198241
return self._unit

0 commit comments

Comments
 (0)