Skip to content

Commit

Permalink
Merge pull request #231 from mabrains/main
Browse files Browse the repository at this point in the history
Adding perimeter calculation for polygons
  • Loading branch information
joamatab authored Jan 18, 2024
2 parents c23297b + ac3c577 commit f510bb8
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 0 deletions.
1 change: 1 addition & 0 deletions gdstk/gdstk.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ class Polygon:
): ...
def apply_repetition(self) -> list[Self]: ...
def area(self) -> float: ...
def perimeter(self) -> float: ...
def bounding_box(self) -> tuple[tuple[float, float], tuple[float, float]]: ...
def contain(self, *points: tuple[float, float] | complex) -> bool | tuple[bool, ...]: ...
def contain_all(self, *points: tuple[float, float] | complex) -> bool: ...
Expand Down
3 changes: 3 additions & 0 deletions include/gdstk/polygon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ struct Polygon {
// Polygon area excluding repetitions with sign indicating orientation
// (positive for counter clockwise)
double signed_area() const;

// Total polygon perimeter including any repetitions
double perimeter() const;

// Check if the points are inside this polygon (points lying on the edges
// or coinciding with a vertex of the polygon are considered inside).
Expand Down
7 changes: 7 additions & 0 deletions python/docstrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,13 @@ Polygon area.
Returns:
Area of the polygon.)!");

PyDoc_STRVAR(polygon_object_perimeter_doc, R"!(perimeter() -> float
Polygon perimeter.
Returns:
Perimeter of the polygon.)!");

PyDoc_STRVAR(polygon_object_bounding_box_doc, R"!(bounding_box() -> tuple
Calculate the polygon bounding box.
Expand Down
6 changes: 6 additions & 0 deletions python/polygon_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ static PyObject* polygon_object_area(PolygonObject* self, PyObject*) {
return PyFloat_FromDouble(area);
}

static PyObject* polygon_object_perimeter(PolygonObject* self, PyObject*) {
const double perimeter = self->polygon->perimeter();
return PyFloat_FromDouble(perimeter);
}

static PyObject* polygon_object_bounding_box(PolygonObject* self, PyObject*) {
Vec2 min, max;
self->polygon->bounding_box(min, max);
Expand Down Expand Up @@ -427,6 +432,7 @@ static PyMethodDef polygon_object_methods[] = {
{"copy", (PyCFunction)polygon_object_copy, METH_NOARGS, polygon_object_copy_doc},
{"__deepcopy__", (PyCFunction)polygon_object_deepcopy, METH_VARARGS | METH_KEYWORDS, polygon_object_deepcopy_doc},
{"area", (PyCFunction)polygon_object_area, METH_NOARGS, polygon_object_area_doc},
{"perimeter", (PyCFunction)polygon_object_perimeter, METH_NOARGS, polygon_object_perimeter_doc},
{"bounding_box", (PyCFunction)polygon_object_bounding_box, METH_NOARGS,
polygon_object_bounding_box_doc},
{"contain", (PyCFunction)polygon_object_contain, METH_VARARGS, polygon_object_contain_doc},
Expand Down
18 changes: 18 additions & 0 deletions src/polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ double Polygon::signed_area() const {
return 0.5 * result;
}

double Polygon::perimeter() const {
if (point_array.count < 3) return 0;
double result = 0;
Vec2* p = point_array.items;
Vec2 v0 = *p++;

for (uint64_t num = point_array.count - 1; num > 0; num--) {
Vec2 v1 = *p++ - v0;
result += v1.length();
v0 += v1;
}
result += (point_array.items[0] - point_array.items[point_array.count-1]).length();
if (repetition.type != RepetitionType::None) result *= repetition.get_count();
return result;
}



// Based on algorithm 7 from: Kai Hormann, Alexander Agathos, “The point in
// polygon problem for arbitrary polygons,” Computational Geometry, Volume 20,
// Issue 3, 2001, Pages 131-144, ISSN 0925-7721.
Expand Down
22 changes: 22 additions & 0 deletions tests/polygon_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ def test_area_size():
numpy.testing.assert_array_equal(poly.points, [[0, 0], [1, 0], [1, 1], [0, 1]])


def test_perimeter_size():
poly1 = gdstk.Polygon([(0, 0), (2, 0), 2 + 2j, 2j])
assert poly1.layer == 0
assert poly1.datatype == 0
assert poly1.size == 4
assert poly1.perimeter() == 8.0
numpy.testing.assert_array_equal(poly1.points, [[0, 0], [2, 0], [2, 2], [0, 2]])

poly2 = gdstk.Polygon([(0, 0), (1, 0), 1 + 1j, 1j], 1, 2)
assert poly2.layer == 1
assert poly2.datatype == 2
assert poly2.size == 4
assert poly2.perimeter() == 4.0
numpy.testing.assert_array_equal(poly2.points, [[0, 0], [1, 0], [1, 1], [0, 1]])

poly3 = gdstk.Polygon([(0, 0), (1, 0), 1 + 1j, 1j])
assert poly3.size == 4
assert poly3.perimeter() == 4.0
numpy.testing.assert_array_equal(poly3.points, [[0, 0], [1, 0], [1, 1], [0, 1]])


def test_bounding_box():
poly = gdstk.Polygon([-1 + 0j, -2j, 3 + 0j, 4j])
assert poly.bounding_box() == ((-1, -2), (3, 4))
Expand Down Expand Up @@ -71,6 +92,7 @@ def test_copy():
numpy.testing.assert_array_equal(p1.points, points)
numpy.testing.assert_array_equal(p2.points, points)


def test_deepcopy():
points = [[-1, 0], [0, -2], [3, 0], [0, 4]]
p1 = gdstk.Polygon(points, 5, 6)
Expand Down

0 comments on commit f510bb8

Please sign in to comment.