Skip to content

Commit

Permalink
feature(offset): Add methods to support Polygon2D offset
Browse files Browse the repository at this point in the history
* feature(polygon): First draft for method for offset.

* feat(polygon2d): Updating offset method.

* feat(offset): adding methods for polygon offset

* feat(offset): offset polygon method done

* chore(gitignore): deleting build, dist dir, adding to .gitignore.

* feat(Polygon2D): Add Thermal Zone, and Offset methods.

* chore(polyskel): Remove methods associated with polyskel.

* style(geometry2d): Fixing style for Sphinx documentation.
  • Loading branch information
chriswmackey committed Mar 5, 2020
1 parent 77b15bb commit 7dd7eff
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 9 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ tox.ini
.eggs
*.code-workspace
/.vscode/settings.json
/.devcontainer
/.devcontainer
/build
/dist
2 changes: 1 addition & 1 deletion ladybug_geometry/geometry2d/_2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __hash__(self):

def __eq__(self, other):
return isinstance(other, Base2DIn2D) and self.__key() == other.__key()

def __ne__(self, other):
return not self.__eq__(other)

Expand Down
19 changes: 17 additions & 2 deletions ladybug_geometry/geometry2d/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ def from_sdl(cls, s, d, length):
"""
return cls(s, d * length / d.magnitude)

@classmethod
def from_array(cls, line_array):
""" Create a LineSegment2D from a nested array of two endpoint coordinates.
Args:
line_arry: Nested tuples ((pt1.x, pt1.y), (pt2.x, pt2.y)), where
pt1 and pt2 represent the endpoints of the line segment.
"""
return LineSegment2D.from_end_points(*tuple(Point2D(*pt) for pt in line_array))

@property
def p1(self):
"""First point (same as p)."""
Expand All @@ -59,6 +69,11 @@ def p2(self):
"""Second point."""
return Point2D(self.p.x + self.v.x, self.p.y + self.v.y)

@property
def endpoints(self):
""" Tuple of endpoints """
return (self.p1, self.p2)

@property
def midpoint(self):
"""Midpoint."""
Expand All @@ -71,7 +86,7 @@ def length(self):

def to_array(self):
""" A nested list representing the two line endpoint coordinates.
Returns:
Returns:
Nested tuples ((pt1.x, pt1.y), (pt2.x, pt2.y)), where
pt1 and pt2 represent the endpoints of the line segment.
"""
Expand Down Expand Up @@ -232,4 +247,4 @@ def __eq__(self, other):

def __repr__(self):
return 'LineSegment2D (<%.2f, %.2f> to <%.2f, %.2f>)' % \
(self.p.x, self.p.y, self.p.x + self.v.x, self.p.y + self.v.y)
(self.p.x, self.p.y, self.p.x + self.v.x, self.p.y + self.v.y)
9 changes: 5 additions & 4 deletions ladybug_geometry/geometry2d/pointvector.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ def from_array(cls, array):
"""
return cls(array[0], array[1])

def to_array(self):
"""Get Vector2D/Point2D as a tuple of two numbers"""
return (self.x, self.y)

@property
def x(self):
"""Get the X coordinate."""
Expand Down Expand Up @@ -160,10 +164,6 @@ def to_dict(self):
'x': self.x,
'y': self.y}

def to_array(self):
"""Get Vector2D/Point2D as a tuple of two numbers"""
return (self.x, self.y)

def _cast_to_float(self, value):
"""Ensure that an input coordinate value is a float."""
try:
Expand Down Expand Up @@ -426,3 +426,4 @@ def __gt__(self, other):
"""
if isinstance(other, Vector2D):
return self.x > other.x

52 changes: 51 additions & 1 deletion ladybug_geometry/geometry2d/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,60 @@ def is_valid(self):
"""
return not self.area == 0

def is_equivalent(self, other, tolerance):
"""Boolean noting equivalence (within tolerance) between this polygon and another.
The order of the polygon vertices do not have to start from the
same vertex for equivalence to be true, but must be in the same counterclockwise
or clockwise order.
Args:
other: Polygon2D for comparison.
tolerance: float representing point equivalence.
Returns:
True if equivalent else False
"""

# Check number of points
if len(self.vertices) != len(other.vertices):
return False

vertices = self.vertices

# Check order
if not vertices[0].is_equivalent(other.vertices[0], tolerance):
self_idx = None
other_pt = other.vertices[0]
for i, pt in enumerate(self.vertices):
if pt.is_equivalent(other_pt, tolerance):
self_idx = i
break

if self_idx is None:
return False

# Re-order polygon vertices to match other
vertices = vertices[self_idx:] + vertices[:self_idx]

is_equivalent = True
for pt, other_pt in zip(vertices[1:], other.vertices[1:]):
is_equivalent = is_equivalent and pt.is_equivalent(other_pt, tolerance)
return is_equivalent

def to_array(self):
"""Get a list of lists whenre each sub-list represents a Point2D vetex."""
return tuple(pt.to_array() for pt in self.vertices)

@classmethod
def from_array(cls, point_array):
"""Creates a Polygon2D from a nested array of endpoint coordinates.
Args:
point_array: nested list of point lists
"""
return Polygon2D(Point2D(*point) for point in point_array)

def remove_colinear_vertices(self, tolerance):
"""Get a version of this polygon without colinear or duplicate vertices.
Expand Down Expand Up @@ -842,4 +892,4 @@ def __eq__(self, other):
return isinstance(other, Polygon2D) and self.__key() == other.__key()

def __repr__(self):
return 'Polygon2D ({} vertices)'.format(len(self))
return 'Polygon2D ({} vertices)'.format(len(self))
18 changes: 18 additions & 0 deletions tests/line2d_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,21 @@ def test_closest_points_between_line():

assert seg_1.distance_to_line(seg_2) == 1
assert seg_1.distance_to_line(seg_3) == pytest.approx(1.41421, rel=1e-3)


def test_from_array():
"""Test from array method"""

test_line = LineSegment2D.from_end_points(Point2D(2, 0), Point2D(2, 2))
line_array = ((2, 0), (2, 2))

assert test_line == LineSegment2D.from_array(line_array)


def test_to_array():
"""Test to array method"""

line_array = ((2, 0), (2, 2))
test_line = LineSegment2D.from_end_points(Point2D(2, 0), Point2D(2, 2))

assert test_line.to_array() == line_array
27 changes: 27 additions & 0 deletions tests/polygon2d_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,3 +631,30 @@ def test_intersect_polygon_segments_with_3_angled_rectangles():

assert len(polygon1.segments) == 4 # No extra vertex added
assert len(polygon2.segments) == 4 # No extra vertex added


def test_polygon_is_equivalent():
""" Test if polygons are equivalent based on point equivalence"""

tol = 1e-10
p1 = Polygon2D.from_array([[0, 0], [6, 0], [7, 3], [0, 4]])

# Test no points are the same
p2 = Polygon2D.from_array([[0, 1], [6, 1], [7, 4]])
assert not p1.is_equivalent(p2, tol)

# Test when length is not same
p2 = Polygon2D.from_array([[0, 0], [6, 0], [7, 3]])
assert not p1.is_equivalent(p2, tol)

# Test equal condition same order
p2 = Polygon2D.from_array([[0, 0], [6, 0], [7, 3], [0, 4]])
assert p1.is_equivalent(p2, tol)

# Test equal condition different order 1
p2 = Polygon2D.from_array([[7, 3], [0, 4], [0, 0], [6, 0]])
assert p1.is_equivalent(p2, tol)

# Test equal condition different order 2
p2 = Polygon2D.from_array([[0, 4], [0, 0], [6, 0], [7, 3]])
assert p1.is_equivalent(p2, tol)

0 comments on commit 7dd7eff

Please sign in to comment.