Repository: compas-dev/compas (language: python)

Issue:
Polygon modifies the inputs in-place
**Describe the bug**
The constructor of `compas.geometry.Polygon` seems to modify the list of points it takes as input if the first and the last point are identical, e.g. when creating a `Polygon` from a closed `Polyline` . Hence it effectively modifies the input polyline or the input list. This is undesirable.

**To Reproduce**
using compas  1.17.4

```
from compas.geometry import Polyline
from compas.geometry import Polygon

pts = [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 0]]

# Example with Polyline --> Polygon
polyline = Polyline(pts)
print("n pts:", len(polyline.points))  # >>> 5
print("closed:", polyline.is_closed())  # >>> True

polygon = Polygon(polyline.points)
print("n pts:", len(polyline.points))  # >>> 4
print("closed:", polyline.is_closed())  # >>> False

# Example with a list only
print("n pts:", len(pts))  # >>> 5
polygon = Polygon(pts)
print("n pts:", len(pts))  # >>> 4
```

**Expected behavior**
The input object should not be modified, e.g. `Polygon` should copy the list before removing items.





Discussion / hints:
Yep, something's off there, I'll take a look at it!

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6229fd504c1..cf30d331870 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Updated workflows to v2.
 * Changed deepcopy of `RhinoBrep` to use the native `Rhino.Geometry` mechanism.
 * The normal of the cutting plane is no longer flipped in `compas_rhino.geometry.RhinoBrep`.
+* Fixed `Polygon` constructor to not modify the input list of points.
 
 ### Removed
 
diff --git a/src/compas/geometry/primitives/polygon.py b/src/compas/geometry/primitives/polygon.py
index 1c1cc1e61cf..79e163668fe 100644
--- a/src/compas/geometry/primitives/polygon.py
+++ b/src/compas/geometry/primitives/polygon.py
@@ -132,7 +132,7 @@ def points(self):
     @points.setter
     def points(self, points):
         if points[-1] == points[0]:
-            del points[-1]
+            points = points[:-1]
         self._points = [Point(*xyz) for xyz in points]
         self._lines = None
 


Test patch:
diff --git a/tests/compas/geometry/test_polygon.py b/tests/compas/geometry/test_polygon.py
index faca266b007..db621bdbe28 100644
--- a/tests/compas/geometry/test_polygon.py
+++ b/tests/compas/geometry/test_polygon.py
@@ -25,6 +25,14 @@ def test_polygon():
     assert polygon.lines == [(a, b) for a, b in pairwise(points + points[:1])]
 
 
+def test_ctor_does_not_modify_input_params():
+    pts = [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 0]]
+
+    polygon = Polygon(pts)
+    assert len(pts) == 5
+    assert len(polygon.points) == 4, "The last point (matching the first) should have been removed"
+
+
 def test_equality():
     points1 = [[0, 0, x] for x in range(5)]
     polygon1 = Polygon(points1)