Skip to content

Commit

Permalink
feat(geometry): add "Polyline2DGroup" class to polyline.py
Browse files Browse the repository at this point in the history
  • Loading branch information
zhen.chen committed Jul 7, 2021
1 parent 0062b3d commit 5035846
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
3 changes: 2 additions & 1 deletion tensorbay/geometry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .box import Box2D, Box3D
from .keypoint import Keypoint2D, Keypoints2D
from .polygon import Polygon2D
from .polyline import Polyline2D
from .polyline import Polyline2D, Polyline2DGroup
from .transform import Transform3D
from .vector import Vector, Vector2D, Vector3D

Expand All @@ -19,6 +19,7 @@
"Keypoints2D",
"Polygon2D",
"Polyline2D",
"Polyline2DGroup",
"Transform3D",
"Vector",
"Vector2D",
Expand Down
100 changes: 98 additions & 2 deletions tensorbay/geometry/polyline.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@

from itertools import accumulate, count, islice, product
from sys import version_info
from typing import Any, Dict, Iterable, List, Sequence, Tuple, Type, TypeVar
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Type, TypeVar

from ..utility import common_loads
from ..utility import UserMutableSequence, common_loads
from .box import Box2D
from .polygon import PointList2D
from .vector import Vector2D

Expand Down Expand Up @@ -204,3 +205,98 @@ def loads(cls: Type[_P], contents: List[Dict[str, float]]) -> _P:
"""
return common_loads(cls, contents)


class Polyline2DGroup(UserMutableSequence[Polyline2D]):
"""This class defines the concept of Polyline2DGroup.
:class:`Polyline2DGroup` contains the coordinates of the vertexes of the polyline
and provides a series of methods to operate on polyline, such as
:meth:`Polyline2D.uniform_frechet_distance` and :meth:`Polyline2D.similarity`.
Arguments:
polylines: A list of polyline.
Examples:
>>> Polyline2DGroup([[[1, 2], [2, 3]], [[3, 4], [6, 8]]])
Polyline2DGroup [
[
Vector2D(1, 2),
Vector2D(2, 3)
],
[
Vector2D(3, 4),
Vector2D(6, 8)
],
]
"""

_P = TypeVar("_P", bound="Polyline2DGroup")

_ElementType = Polyline2D

def __init__(
self,
polylines: Optional[Iterable[Iterable[Iterable[float]]]] = None,
) -> None:
self._data = [self._ElementType(polyline) for polyline in polylines] if polylines else []

def _loads(self: _P, contents: List[List[Dict[str, float]]]) -> None:
self._data = [self._ElementType.loads(polyline) for polyline in contents]

@classmethod
def loads(cls: Type[_P], contents: List[List[Dict[str, float]]]) -> _P:
"""Load a :class:`Polyline2DGroup` from a list of dict.
Arguments:
contents: A list of dict containing
the coordinates of the vertexes of the polyline group.
Returns:
The loaded :class:`Polyline2DGroup` object.
Examples:
>>> polyline_group = Polyline2DGroup([[[1, 1], [1, 2], [2, 2]], [2, 3], [3, 5]])
>>> polyline_group.dumps()
[
[{'x': 1, 'y': 1}, {'x': 1, 'y': 2}, {'x': 2, 'y': 2}],
[{'x': 2, 'y': 3}, {'x': 3, 'y': 5}
]
"""
return common_loads(cls, contents)

def dumps(self) -> List[List[Dict[str, float]]]:
"""Dumps a :class:`Polyline2DGroup` into a polyline list.
Returns:
A list of dictionaries containing the coordinates of the vertexes
of the polygon within the polyline list.
"""
return [polyline.dumps() for polyline in self._data]

def bounds(self) -> Box2D:
"""Calculate the bounds of polyline list.
Returns:
The bounds of point list.
"""
x_min = x_max = self._data[0][0].x
y_min = y_max = self._data[0][0].y

for polyline in self._data:
box = polyline.bounds()
if box.xmin < x_min:
x_min = box.xmin
elif box.xmax > x_max:
x_max = box.xmax

if box.ymin < y_min:
y_min = box.ymin
elif box.ymax > y_max:
y_max = box.ymax

return Box2D(x_min, y_min, x_max, y_max)
26 changes: 25 additions & 1 deletion tensorbay/geometry/tests/test_polyline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

from math import isclose

from .. import Box2D, Polyline2D, Vector2D
from .. import Box2D, Polyline2D, Polyline2DGroup, Vector2D

_POLYLINE_SEQUENCE_1 = [[1, 1], [2, 2], [4, 4], [5, 5]]
_POLYLINE_SEQUENCE_2 = [[2, 1], [4, 3], [6, 5]]

_POLYLINE_1 = Polyline2D(_POLYLINE_SEQUENCE_1)
_POLYLINE_2 = Polyline2D(_POLYLINE_SEQUENCE_2)

_POLYLINE_GROUP_SEQUENCE = [_POLYLINE_SEQUENCE_1, _POLYLINE_SEQUENCE_2]
_POLYLINE_GROUP = Polyline2DGroup([_POLYLINE_SEQUENCE_1, _POLYLINE_SEQUENCE_2])

_POLYLINE_INFO_1 = (
{
"index": 0,
Expand Down Expand Up @@ -55,6 +58,7 @@

_POLYLINE_CONTENT_1 = [{"x": 1, "y": 1}, {"x": 2, "y": 2}, {"x": 4, "y": 4}, {"x": 5, "y": 5}]
_POLYLINE_CONTENT_2 = [{"x": 2, "y": 1}, {"x": 4, "y": 3}, {"x": 6, "y": 5}]
_POLYLINE_GROUP_CONTENT = [_POLYLINE_CONTENT_1, _POLYLINE_CONTENT_2]


class TestPolyline2D:
Expand Down Expand Up @@ -109,3 +113,23 @@ def test_dumps(self):
def test_bounds(self):
assert _POLYLINE_1.bounds() == Box2D(1, 1, 5, 5)
assert _POLYLINE_2.bounds() == Box2D(2, 1, 6, 5)


class TestPolyline2DGroup:
def test_init(self):
assert Polyline2DGroup() == Polyline2DGroup([])
assert Polyline2DGroup(_POLYLINE_GROUP_SEQUENCE) == Polyline2DGroup(
[
[Vector2D(1, 1), Vector2D(2, 2), Vector2D(4, 4), Vector2D(5, 5)],
[Vector2D(2, 1), Vector2D(4, 3), Vector2D(6, 5)],
]
)

def test_loads(self):
assert Polyline2DGroup.loads(_POLYLINE_GROUP_CONTENT) == _POLYLINE_GROUP

def test_dumps(self):
assert _POLYLINE_GROUP.dumps() == _POLYLINE_GROUP_CONTENT

def test_bounds(self):
assert _POLYLINE_GROUP.bounds() == Box2D(1, 1, 6, 5)

0 comments on commit 5035846

Please sign in to comment.