diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a62e35ae59f..7bd3a253d148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed bug where mimic joints were considered configurable. * Fixed bug where `!=` gave incorrect results in Rhino for some compas objects. * Fixed bug where `compas_rhino.BaseArtist.redraw` did not trigger a redraw. +* Fixed minor bugs in `compas.geometry.Polyline` and `compas.geometry.Polygon`. +* Fixed very minor bugs in `compas.geometry.Frame` and `compas.geometry.Quaternion`. ### Removed diff --git a/src/compas/geometry/primitives/frame.py b/src/compas/geometry/primitives/frame.py index 71d2fec48f69..4b83aef1b9f1 100644 --- a/src/compas/geometry/primitives/frame.py +++ b/src/compas/geometry/primitives/frame.py @@ -1,25 +1,24 @@ from __future__ import print_function -import math - -from compas.geometry import cross_vectors -from compas.geometry import subtract_vectors -from compas.geometry import matrix_from_basis_vectors -from compas.geometry import basis_vectors_from_matrix -from compas.geometry import quaternion_from_matrix -from compas.geometry import matrix_from_quaternion +from compas.geometry import allclose +from compas.geometry import argmax from compas.geometry import axis_angle_vector_from_matrix -from compas.geometry import matrix_from_axis_angle_vector +from compas.geometry import basis_vectors_from_matrix +from compas.geometry import cross_vectors +from compas.geometry import decompose_matrix from compas.geometry import euler_angles_from_matrix +from compas.geometry import matrix_from_axis_angle_vector +from compas.geometry import matrix_from_basis_vectors from compas.geometry import matrix_from_euler_angles -from compas.geometry import decompose_matrix +from compas.geometry import matrix_from_quaternion +from compas.geometry import quaternion_from_matrix +from compas.geometry import subtract_vectors from compas.geometry import Transformation -from compas.geometry import argmax -from compas.geometry.primitives import Primitive from compas.geometry.primitives import Point -from compas.geometry.primitives import Vector +from compas.geometry.primitives import Primitive from compas.geometry.primitives import Quaternion +from compas.geometry.primitives import Vector __all__ = ['Frame'] @@ -180,11 +179,9 @@ def __iter__(self): return iter([self.point, self.xaxis, self.yaxis]) def __eq__(self, other, tol=1e-05): - for v1, v2 in zip(self, other): - for a, b in zip(v1, v2): - if math.fabs(a - b) > tol: - return False - return True + if not hasattr(other, '__iter__') or not hasattr(other, '__len__') or len(self) != len(other): + return False + return allclose(self, other) # ========================================================================== # constructors @@ -742,5 +739,4 @@ def transform(self, T): if __name__ == '__main__': import doctest - from compas.geometry import allclose # noqa: F401 doctest.testmod(globs=globals()) diff --git a/src/compas/geometry/primitives/polygon.py b/src/compas/geometry/primitives/polygon.py index 1422a137cd8b..7f43cfc9d30d 100644 --- a/src/compas/geometry/primitives/polygon.py +++ b/src/compas/geometry/primitives/polygon.py @@ -4,17 +4,18 @@ import math +from compas.geometry import allclose +from compas.geometry import area_polygon from compas.geometry import cross_vectors from compas.geometry import centroid_polygon -from compas.geometry import area_polygon from compas.geometry import is_coplanar from compas.geometry import is_polygon_convex from compas.geometry import transform_points -from compas.geometry.primitives import Primitive +from compas.geometry.primitives import Line from compas.geometry.primitives import Point +from compas.geometry.primitives import Primitive from compas.geometry.primitives import Vector -from compas.geometry.primitives import Line from compas.utilities import pairwise @@ -147,7 +148,7 @@ def area(self): # ========================================================================== def __repr__(self): - return "Polygon({})".format(", ".join(["{}".format(point) for point in self.points])) + return "Polygon([{}])".format(", ".join(["{}".format(point) for point in self.points])) def __len__(self): return len(self.points) @@ -156,13 +157,16 @@ def __getitem__(self, key): return self.points[key] def __setitem__(self, key, value): - self.points[key] = value + self.points[key] = Point(*value) + self._lines = None def __iter__(self): return iter(self.points) def __eq__(self, other): - return all(a == b for a, b in zip(self, other)) + if not hasattr(other, '__iter__') or not hasattr(other, '__len__') or len(self) != len(other): + return False + return allclose(self, other) # ========================================================================== # constructors diff --git a/src/compas/geometry/primitives/polyline.py b/src/compas/geometry/primitives/polyline.py index 726bc2d01447..5c7c5daa990f 100644 --- a/src/compas/geometry/primitives/polyline.py +++ b/src/compas/geometry/primitives/polyline.py @@ -2,12 +2,13 @@ from __future__ import absolute_import from __future__ import division +from compas.geometry import allclose from compas.geometry import transform_points +from compas.geometry.predicates import is_point_on_line +from compas.geometry.primitives import Line from compas.geometry.primitives import Primitive from compas.geometry.primitives import Point -from compas.geometry.primitives import Line -from compas.geometry.predicates import is_point_on_line from compas.utilities import pairwise @@ -109,7 +110,7 @@ def length(self): # ========================================================================== def __repr__(self): - return "Polyline({})".format(", ".join(["{}".format(point) for point in self.points])) + return "Polyline([{}])".format(", ".join(["{}".format(point) for point in self.points])) def __len__(self): return len(self.points) @@ -118,13 +119,16 @@ def __getitem__(self, key): return self.points[key] def __setitem__(self, key, value): - self.points[key] = value + self.points[key] = Point(*value) + self._lines = None def __iter__(self): return iter(self.points) def __eq__(self, other): - return all(a == b for a, b in zip(self, other)) + if not hasattr(other, '__iter__') or not hasattr(other, '__len__') or len(self) != len(other): + return False + return allclose(self, other) # ========================================================================== # constructors diff --git a/src/compas/geometry/primitives/quaternion.py b/src/compas/geometry/primitives/quaternion.py index e00255c974c0..0ab136f0674d 100644 --- a/src/compas/geometry/primitives/quaternion.py +++ b/src/compas/geometry/primitives/quaternion.py @@ -217,6 +217,8 @@ def __setitem__(self, key, value): raise KeyError def __eq__(self, other, tol=1e-05): + if not hasattr(other, '__iter__') or not hasattr(other, '__len__') or len(self) != len(other): + return False for v1, v2 in zip(self, other): if math.fabs(v1 - v2) > tol: return False @@ -225,6 +227,9 @@ def __eq__(self, other, tol=1e-05): def __iter__(self): return iter(self.wxyz) + def __len__(self): + return 4 + def __repr__(self): return 'Quaternion({:.{prec}f}, {:.{prec}f}, {:.{prec}f}, {:.{prec}f})'.format(self.w, self.x, self.y, self.z, prec=3) diff --git a/tests/compas/geometry/test_polygon.py b/tests/compas/geometry/test_polygon.py new file mode 100644 index 000000000000..a30d595d71dc --- /dev/null +++ b/tests/compas/geometry/test_polygon.py @@ -0,0 +1,55 @@ +import pytest + +from compas.geometry import Point +from compas.geometry import Polygon +from compas.utilities import pairwise + + +def test_polygon(): + points = [[0, 0, x] for x in range(5)] + polygon = Polygon(points) + assert polygon.points == points + assert polygon.lines == [(a, b) for a, b in pairwise(points + points[:1])] + + +def test_equality(): + points1 = [[0, 0, x] for x in range(5)] + polygon1 = Polygon(points1) + points2 = [[0, 0, x] for x in range(6)] + polygon2 = Polygon(points2) + points3 = [[0, 0, x] for x in range(5)] + [[0, 0, 0]] + polygon3 = Polygon(points3) + assert polygon1 == polygon1 + assert polygon1 == points1 + assert points1 == polygon1 + assert polygon1 != polygon2 + assert polygon2 != polygon1 + assert polygon1 != points2 + assert points2 != polygon1 + assert polygon1 != 1 + assert polygon1 == polygon3 + + +def test___repr__(): + points = [[0, 0, x] for x in range(5)] + polygon = Polygon(points) + assert polygon == eval(repr(polygon)) + + +def test___getitem__(): + points = [[0, 0, x] for x in range(5)] + polygon = Polygon(points) + for x in range(5): + assert polygon[x] == [0, 0, x] + with pytest.raises(IndexError): + polygon[6] = [0, 0, 6] + + +def test___setitem__(): + points = [[0, 0, x] for x in range(5)] + polygon = Polygon(points) + point = [1, 1, 4] + polygon[4] = point + assert polygon[4] == point + assert isinstance(polygon[4], Point) + assert polygon.lines[-2].end == point \ No newline at end of file diff --git a/tests/compas/geometry/test_polyline.py b/tests/compas/geometry/test_polyline.py index 6ba2410ac5e5..0b9dd306f00f 100644 --- a/tests/compas/geometry/test_polyline.py +++ b/tests/compas/geometry/test_polyline.py @@ -1,7 +1,56 @@ -import compas -import pytest -from compas.geometry import Polyline, Point import math +import pytest + +from compas.geometry import Point +from compas.geometry import Polyline +from compas.utilities import pairwise + + +def test_polyline(): + points = [[0, 0, x] for x in range(5)] + polyline = Polyline(points) + assert polyline.points == points + assert polyline.lines == [(a, b) for a, b in pairwise(points)] + + +def test_equality(): + points1 = [[0, 0, x] for x in range(5)] + polyline1 = Polyline(points1) + points2 = [[0, 0, x] for x in range(6)] + polyline2 = Polyline(points2) + assert polyline1 == polyline1 + assert polyline1 == points1 + assert points1 == polyline1 + assert polyline1 != polyline2 + assert polyline2 != polyline1 + assert polyline1 != points2 + assert points2 != polyline1 + assert polyline1 != 1 + + +def test___repr__(): + points = [[0, 0, x] for x in range(5)] + polyline = Polyline(points) + assert polyline == eval(repr(polyline)) + + +def test___getitem__(): + points = [[0, 0, x] for x in range(5)] + polyline = Polyline(points) + for x in range(5): + assert polyline[x] == [0, 0, x] + with pytest.raises(IndexError): + polyline[6] = [0, 0, 6] + + +def test___setitem__(): + points = [[0, 0, x] for x in range(5)] + polyline = Polyline(points) + point = [1, 1, 4] + polyline[4] = point + assert polyline[4] == point + assert isinstance(polyline[4], Point) + assert polyline.lines[-1].end == point @pytest.mark.parametrize('coords,expected', [