Skip to content

Commit 645dc74

Browse files
authored
Merge pull request #1420 from compas-dev/fix-comparisons
Fix comparisons point and frame
2 parents 7bbe6ac + 61ae095 commit 645dc74

File tree

10 files changed

+115
-11
lines changed

10 files changed

+115
-11
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
* Fixed `NotImplementedError` when calling `compas_rhino.conversions.surface_to_compas` on NURBS Surface.
1515
* Fixed `NotImplementedError` when calling `compas_rhino.conversions.surface_to_compas` on Surface.
16+
* Changed point comparison (`compas.geometry.Point.__eq__`) to use `TOL.is_allclose` instead of raw coordinate comparison.
17+
* Changed vector comparison (`compas.geometry.Vector.__eq__`) to use `TOL.is_allclose` instead of raw coordinate comparison.
18+
* Fixed bug in frame comparison (`compas.geometry.Frame.__eq__`).
19+
* Fixed bug in `compas.geometry.oriented_bounding_box_numpy`.
1620

1721
### Removed
1822

src/compas/geometry/bbox_numpy.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ def oriented_bounding_box_numpy(points, tol=None):
9595
# also compute the axis aligned bounding box
9696
# and compare the areas of the two
9797

98-
rect1, area1 = minimum_area_rectangle_xy(points, return_size=True)
99-
10098
points = world_to_local_coordinates_numpy(frame, points)
99+
rect1, area1 = minimum_area_rectangle_xy(points, return_size=True)
101100
rect2 = bounding_box(points)[:4]
102101
area2 = (rect2[1][0] - rect2[0][0]) * (rect2[3][1] - rect2[0][1])
103102

104103
if area1 < area2:
105104
rect = [[pt[0], pt[1], 0.0] for pt in rect1]
106-
bbox = rect + rect
105+
bbox = local_to_world_coordinates_numpy(frame, rect)
106+
bbox = vstack((bbox, bbox)).tolist()
107107
else:
108108
rect = [[pt[0], pt[1], 0.0] for pt in rect2]
109109
bbox = local_to_world_coordinates_numpy(frame, rect)
@@ -260,11 +260,12 @@ def minimum_area_rectangle_xy(points, return_size=False):
260260
p0 = points[simplex[0]]
261261
p1 = points[simplex[1]]
262262

263+
vn = xy - p0
264+
263265
# s direction
264266
s = p1 - p0
265267
sl = sum(s**2) ** 0.5
266268
su = s / sl
267-
vn = xy - p0
268269
sc = (sum(vn * s, axis=1) / sl).reshape((-1, 1))
269270
scmax = argmax(sc)
270271
scmin = argmin(sc)
@@ -277,7 +278,6 @@ def minimum_area_rectangle_xy(points, return_size=False):
277278
t = array([-s[1], s[0]])
278279
tl = sum(t**2) ** 0.5
279280
tu = t / tl
280-
vn = xy - p0
281281
tc = (sum(vn * t, axis=1) / tl).reshape((-1, 1))
282282
tcmax = argmax(tc)
283283
tcmin = argmin(tc)
@@ -287,7 +287,7 @@ def minimum_area_rectangle_xy(points, return_size=False):
287287
h = tc[tcmax] - tc[tcmin]
288288
a = w * h
289289

290-
# box corners
290+
# other box corners
291291
if dot(t, mean - p0) < 0:
292292
b3 = b0 - h * tu
293293
b2 = b1 - h * tu

src/compas/geometry/frame.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ def __setitem__(self, key, value):
142142
def __iter__(self):
143143
return iter([self.point, self.xaxis, self.yaxis])
144144

145-
def __eq__(self, other, tol=None):
145+
def __eq__(self, other):
146146
if not hasattr(other, "__iter__") or not hasattr(other, "__len__") or len(self) != len(other):
147147
return False
148-
return TOL.is_allclose(self, other, atol=tol)
148+
return self.point == other[0] and self.xaxis == other[1] and self.yaxis == other[2]
149149

150150
# ==========================================================================
151151
# Properties

src/compas/geometry/point.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def __iter__(self):
181181
return iter([self.x, self.y, self.z])
182182

183183
def __eq__(self, other):
184-
return self.x == other[0] and self.y == other[1] and self.z == other[2]
184+
return TOL.is_allclose(self, other)
185185

186186
def __add__(self, other):
187187
return Point(self.x + other[0], self.y + other[1], self.z + other[2])

src/compas/geometry/shapes/box.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from compas.geometry import Frame
66
from compas.geometry import Line
7+
from compas.geometry import Point # noqa: F401
78
from compas.geometry import Transformation
89
from compas.geometry import Vector
910
from compas.geometry import centroid_points
@@ -478,7 +479,7 @@ def from_points(cls, points): # type: (...) -> Box
478479
# Discretisation
479480
# ==========================================================================
480481

481-
def compute_vertices(self): # type: () -> list[list[float]]
482+
def compute_vertices(self): # type: () -> list[Point]
482483
"""Compute the vertices of the discrete representation of the box."""
483484
point = self.frame.point
484485
xaxis = self.frame.xaxis

src/compas/geometry/vector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def __iter__(self):
150150
return iter([self.x, self.y, self.z])
151151

152152
def __eq__(self, other):
153-
return self.x == other[0] and self.y == other[1] and self.z == other[2]
153+
return TOL.is_allclose(self, other)
154154

155155
def __add__(self, other):
156156
return Vector(self.x + other[0], self.y + other[1], self.z + other[2])

tests/compas/geometry/test_bbox.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import pytest
22
import os
33
import compas
4+
from random import random
45
from compas.tolerance import TOL
6+
from compas.geometry import Box
57
from compas.geometry import bounding_box
68
from compas.geometry import bounding_box_xy
79

@@ -146,3 +148,26 @@ def test_oriented_bounding_box_numpy_from_fixtures():
146148
results = oriented_bounding_box_numpy(coords)
147149
for result, expected_values in zip(results, expected):
148150
assert TOL.is_allclose(result, expected_values)
151+
152+
153+
def test_oriented_bounding_box_numpy_flat():
154+
if compas.IPY:
155+
return
156+
157+
from compas.geometry import oriented_bounding_box_numpy
158+
159+
points = [[10 * random(), 10 * random(), 0] for i in range(100)]
160+
box = Box.from_bounding_box(oriented_bounding_box_numpy(points))
161+
162+
for point in points:
163+
assert box.contains_point(point)
164+
165+
assert not box.contains_point([10 * random(), 10 * random(), 1])
166+
167+
points = [[10 * random(), 10 * random(), 10] for i in range(100)]
168+
box = Box.from_bounding_box(oriented_bounding_box_numpy(points))
169+
170+
for point in points:
171+
assert box.contains_point(point)
172+
173+
assert not box.contains_point([10 * random(), 10 * random(), 11])

tests/compas/geometry/test_frame.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,35 @@ def test_frame_inverted():
124124
assert TOL.is_close(other.xaxis.dot([1, 0, 0]), 1.0)
125125
assert TOL.is_close(other.yaxis.dot([0, -1, 0]), 1.0)
126126
assert TOL.is_close(other.zaxis.dot([0, 0, -1]), 1.0)
127+
128+
129+
def test_frame_comparison_relative():
130+
a = Frame(Point(random(), random(), random()))
131+
132+
b = a.copy()
133+
b.point.x += 0.1 * TOL.relative * b.point.x
134+
assert a == b
135+
136+
c = a.copy()
137+
c.point.x += TOL.relative * c.point.x
138+
assert a == c
139+
140+
d = a.copy()
141+
d.point.x += 10.0 * TOL.relative * d.point.x
142+
assert a != d
143+
144+
145+
def test_frame_comparison_absolute():
146+
a = Frame(Point(0, 0, 0))
147+
148+
b = a.copy()
149+
b.point.x += 0.1 * TOL.absolute
150+
assert a == b
151+
152+
c = a.copy()
153+
c.point.x += TOL.absolute
154+
assert a == c
155+
156+
d = a.copy()
157+
d.point.x += 10.0 * TOL.absolute
158+
assert a != d

tests/compas/geometry/test_point.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import compas
55
from random import random
66
from compas.geometry import Point
7+
from compas.tolerance import TOL
78

89

910
@pytest.mark.parametrize(
@@ -64,6 +65,26 @@ def test_point_equality():
6465
assert not (p1 == p3)
6566

6667

68+
def test_point_comparison_relative():
69+
a = Point(random(), random(), random())
70+
b = Point(a.x + a.x * TOL.relative * 0.1, a.y + a.y * TOL.relative * 0.1, a.z + a.z * TOL.relative * 0.1)
71+
c = Point(a.x + a.x * TOL.relative, a.y + a.y * TOL.relative, a.z + a.z * TOL.relative)
72+
d = Point(a.x + a.x * TOL.relative * 10.0, a.y + a.y * TOL.relative * 10.0, a.z + a.z * TOL.relative * 10.0)
73+
assert a == b
74+
assert a == c
75+
assert a != d
76+
77+
78+
def test_point_comparison_absolute():
79+
a = Point(0, 0, 0)
80+
b = Point(a.x + TOL.absolute * 0.1, a.y + TOL.absolute * 0.1, a.z + TOL.absolute * 0.1)
81+
c = Point(a.x + TOL.absolute, a.y + TOL.absolute, a.z + TOL.absolute)
82+
d = Point(a.x + TOL.absolute * 10.0, a.y + TOL.absolute * 10.0, a.z + TOL.absolute * 10.0)
83+
assert a == b
84+
assert a == c
85+
assert a != d
86+
87+
6788
def test_point_inplace_operators():
6889
pass
6990

tests/compas/geometry/test_vector.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import compas
55
from random import random
66
from compas.geometry import Vector
7+
from compas.tolerance import TOL
78

89

910
@pytest.mark.parametrize(
@@ -95,6 +96,26 @@ def test_vector_equality():
9596
assert not (p1 == p3)
9697

9798

99+
def test_vector_comparison_relative():
100+
a = Vector(random(), random(), random())
101+
b = Vector(a.x + a.x * TOL.relative * 0.1, a.y + a.y * TOL.relative * 0.1, a.z + a.z * TOL.relative * 0.1)
102+
c = Vector(a.x + a.x * TOL.relative, a.y + a.y * TOL.relative, a.z + a.z * TOL.relative)
103+
d = Vector(a.x + a.x * TOL.relative * 10.0, a.y + a.y * TOL.relative * 10.0, a.z + a.z * TOL.relative * 10.0)
104+
assert a == b
105+
assert a == c
106+
assert a != d
107+
108+
109+
def test_vector_comparison_absolute():
110+
a = Vector(0, 0, 0)
111+
b = Vector(a.x + TOL.absolute * 0.1, a.y + TOL.absolute * 0.1, a.z + TOL.absolute * 0.1)
112+
c = Vector(a.x + TOL.absolute, a.y + TOL.absolute, a.z + TOL.absolute)
113+
d = Vector(a.x + TOL.absolute * 10.0, a.y + TOL.absolute * 10.0, a.z + TOL.absolute * 10.0)
114+
assert a == b
115+
assert a == c
116+
assert a != d
117+
118+
98119
def test_vector_inplace_operators():
99120
pass
100121

0 commit comments

Comments
 (0)