Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@
- Eric Gozzi <<eric.gozzi@arch.ethz.ch>> [@ericgozzi](https://github.com/ericgozzi)
- Daniel Nunes Locatelli <<nuneslocatelli@arch.ethz.ch>> [@daniel-locatelli](https://github.com/daniel-locatelli)
- Mengxi He <<m.he@lekolabs.com>> [@mengxihex](https://github.com/mengxihex)
- Arian Moeini <<arianmoeini11@gmail.com>> [@ArianMoeini](https://github.com/ArianMoeini)
15 changes: 5 additions & 10 deletions src/compas/geometry/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from compas.geometry import earclip_polygon
from compas.geometry import is_coplanar
from compas.geometry import is_polygon_convex
from compas.geometry import normal_triangle
from compas.geometry import normal_polygon
from compas.geometry import transform_points
from compas.itertools import pairwise
from compas.tolerance import TOL
Expand Down Expand Up @@ -180,15 +180,10 @@ def normal(self):

@property
def plane(self):
# by just taking the bestfit plane,
# the normal might not be aligned with the winding direciton of the polygon
# this can be solved by comparing the plane normal with the normal of one of the triangles of the polygon
# for convex polygons this is always correct
# in the case of concave polygons it may not be
# to be entirely correct, the check should be done with one of the polygon ears after earclipping
# however, this is costly
# and even then it is only correct if we assume th polygon is plat enough to have a consistent direction
normal = normal_triangle([self.centroid] + self.points[:2])
# Align the best-fit plane with the winding of the full boundary.
# A triangle formed from the centroid and first edge can point the
# wrong way when that edge lies on a concave part of the polygon.
normal = normal_polygon(self.points)
plane = Plane.from_points(self.points)
if plane.normal.dot(normal) < 0:
plane.normal.flip()
Expand Down
9 changes: 9 additions & 0 deletions tests/compas/geometry/test_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ def test_polygon_normal_direction():
assert polygon.normal.dot([0, 0, 1]) < 0


def test_concave_polygon_normal_follows_winding_for_any_starting_vertex():
points = [[3, 1, 0], [1, 1, 0], [1, 4, 0], [0, 4, 0], [0, 0, 0], [4, 0, 0], [4, 4, 0], [3, 4, 0]]

for index in range(len(points)):
rotated = points[index:] + points[:index]
assert Polygon(rotated).normal.dot([0, 0, 1]) > 0
assert Polygon(list(reversed(rotated))).normal.dot([0, 0, 1]) < 0


@pytest.mark.parametrize(
"points",
[
Expand Down