From ed70775ee93708f979f8fac970b5255548e5542a Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Mon, 15 Apr 2024 11:28:13 +0100
Subject: [PATCH 01/17] Polygon_repair:: Use move semantics; Add
 Polygon_2::reserve()

---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h   |  2 ++
 Polygon/include/CGAL/Polygon_2.h                   |  7 +++++++
 Polygon/include/CGAL/Polygon_2/Polygon_2_impl.h    |  2 ++
 .../include/CGAL/Polygon_repair/repair.h           | 14 ++++++++------
 4 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 50edf6d592d2..9c81bd955911 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -78,6 +78,8 @@ class Multipolygon_with_holes_2 {
 
   void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); }
 
+  void add_polygon(const Polygon_2&& pgn) { m_polygons.push_back(Polygon_with_holes_2(std::forward(pgn))); }
+
   void add_polygon_with_holes(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 
   void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }
diff --git a/Polygon/include/CGAL/Polygon_2.h b/Polygon/include/CGAL/Polygon_2.h
index b2b7ab7340a8..ff97d3c89932 100644
--- a/Polygon/include/CGAL/Polygon_2.h
+++ b/Polygon/include/CGAL/Polygon_2.h
@@ -34,6 +34,7 @@
 #include <CGAL/enum.h>
 
 #include <CGAL/Aff_transformation_2.h>
+#include <CGAL/Container_helper.h>
 
 #include <CGAL/Polygon_2_algorithms.h>
 #include <CGAL/Polygon_2/Polygon_2_vertex_circulator.h>
@@ -543,6 +544,12 @@ class Polygon_2 {
      container().resize(s);
     }
 
+    /// Calls `container().reserve(s)` if this is available for `Container`.
+    void reserve(std::size_t s)
+    {
+      internal::reserve(container(),s);
+    }
+
     /// @}
 
     bool identical(const Polygon_2<Traits_P,Container_P> &q) const
diff --git a/Polygon/include/CGAL/Polygon_2/Polygon_2_impl.h b/Polygon/include/CGAL/Polygon_2/Polygon_2_impl.h
index 8ba112734283..d2b812f4b349 100644
--- a/Polygon/include/CGAL/Polygon_2/Polygon_2_impl.h
+++ b/Polygon/include/CGAL/Polygon_2/Polygon_2_impl.h
@@ -88,6 +88,7 @@ operator>>(std::istream &is, Polygon_2<Traits_P,Container_P>& p)
 
   if (is) {
     p.erase(p.vertices_begin(),p.vertices_end());
+    p.reserve(n);
     for (int i=0; i<n; i++) {
       if(is >> point){
         p.push_back(point);
@@ -146,6 +147,7 @@ transform(const Transformation& t, const Polygon_2<Traits_P,Container_P>& p)
 {
   typedef typename Polygon_2<Traits_P,Container_P>::Vertex_const_iterator VI;
   Polygon_2<Traits_P,Container_P> result;
+  result.reserve(p.size());
   for (VI i = p.vertices_begin(); i != p.vertices_end(); ++i)
     result.push_back(t(*i));
   return result;
diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
index 0188f1630fb1..8aee2108d2a2 100644
--- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h
+++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
@@ -645,12 +645,14 @@ class Polygon_repair {
         reconstruct_ring(ring, face, opposite_vertex);
 
         // Put ring in polygons
-        Polygon_2<Kernel, Container> polygon(ring.begin(), ring.end());
+        Polygon_2<Kernel, Container> polygon;
+        polygon.reserve(ring.size());
+        polygon.insert(polygon.vertices_end(),ring.begin(), ring.end());
         // std::cout << "Reconstructed ring for polygon " << face->label() << " with ccw? " << (polygon.orientation() == CGAL::COUNTERCLOCKWISE) << std::endl;
         if (polygon.orientation() == CGAL::COUNTERCLOCKWISE) {
-          polygons[face->label()-1] = polygon;
+          polygons[face->label()-1] = std::move(polygon);
         } else {
-          holes[face->label()-1].insert(polygon);
+          holes[face->label()-1].insert(std::move(polygon));
         } break;
       }
     }
@@ -658,11 +660,11 @@ class Polygon_repair {
     // Create polygons with holes and put in multipolygon
     std::set<Polygon_with_holes_2<Kernel, Container>, Polygon_with_holes_less> ordered_polygons;
     for (std::size_t i = 0; i < polygons.size(); ++i) {
-      ordered_polygons.insert(Polygon_with_holes_2<Kernel, Container>(polygons[i], holes[i].begin(), holes[i].end()));
+      ordered_polygons.insert(Polygon_with_holes_2<Kernel, Container>(std::move(polygons[i]), holes[i].begin(), holes[i].end()));
     }
     for (auto const& polygon: ordered_polygons) {
       // std::cout << "Adding polygon " << polygon << std::endl;
-      mp.add_polygon_with_holes(polygon);
+      mp.add_polygon_with_holes(std::move(polygon));
     }
   }
 
@@ -685,7 +687,7 @@ class Polygon_repair {
     return t;
   }
 
-  Multipolygon_with_holes_2<Kernel, Container> multipolygon() {
+  const Multipolygon_with_holes_2<Kernel, Container>& multipolygon() {
     return mp;
   }
 

From 47ef1a271660de4f46e53ce3c3cdec32e523280a Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Mon, 15 Apr 2024 12:06:03 +0100
Subject: [PATCH 02/17] Use std::make_move_iterator()

---
 Polygon_repair/include/CGAL/Polygon_repair/repair.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
index 8aee2108d2a2..6254dc0232ad 100644
--- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h
+++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
@@ -660,7 +660,7 @@ class Polygon_repair {
     // Create polygons with holes and put in multipolygon
     std::set<Polygon_with_holes_2<Kernel, Container>, Polygon_with_holes_less> ordered_polygons;
     for (std::size_t i = 0; i < polygons.size(); ++i) {
-      ordered_polygons.insert(Polygon_with_holes_2<Kernel, Container>(std::move(polygons[i]), holes[i].begin(), holes[i].end()));
+      ordered_polygons.insert(Polygon_with_holes_2<Kernel, Container>(std::move(polygons[i]), std::make_move_iterator(holes[i].begin()), std::make_move_iterator(holes[i].end())));
     }
     for (auto const& polygon: ordered_polygons) {
       // std::cout << "Adding polygon " << polygon << std::endl;

From 92ccdbcc08860913cf3b7c9b848c07b0004789ca Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Mon, 15 Apr 2024 13:07:00 +0100
Subject: [PATCH 03/17] fix forward

---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 9c81bd955911..7ed5313e3efc 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -78,7 +78,7 @@ class Multipolygon_with_holes_2 {
 
   void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); }
 
-  void add_polygon(const Polygon_2&& pgn) { m_polygons.push_back(Polygon_with_holes_2(std::forward(pgn))); }
+  void add_polygon(Polygon_2&& pgn) { m_polygons.push_back(Polygon_with_holes_2(std::forward<Polygon_with_holes_2>(pgn))); }
 
   void add_polygon_with_holes(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 

From 2af58ecea3ade9f400fad4be7b3934557fa22672 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Mon, 15 Apr 2024 18:45:05 +0100
Subject: [PATCH 04/17] Make read_WKT() work with Multipolygon_with_holes

---
 .../include/CGAL/Multipolygon_with_holes_2.h  | 13 +++++++-
 .../Polygon_repair/polygons2multipolygon.cpp  | 32 +++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)
 create mode 100644 Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 7ed5313e3efc..2449b9dd8eef 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -43,7 +43,7 @@ class Multipolygon_with_holes_2 {
 
   /// polygon with holes type
   using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<Kernel, Container>;
-
+  using value_type = Polygon_with_holes_2;
   /// @}
 
   using Polygon_with_holes_container = std::deque<Polygon_with_holes_2>;
@@ -72,10 +72,19 @@ class Multipolygon_with_holes_2 {
 
   Polygon_with_holes_iterator polygons_with_holes_end() { return m_polygons.end(); }
 
+  Polygon_with_holes_iterator begin() { return m_polygons.begin(); }
+
+  Polygon_with_holes_iterator end() { return m_polygons.end(); }
+
   Polygon_with_holes_const_iterator polygons_with_holes_begin() const { return m_polygons.begin(); }
 
   Polygon_with_holes_const_iterator polygons_with_holes_end() const { return m_polygons.end(); }
 
+  Polygon_with_holes_const_iterator begin() const { return m_polygons.begin(); }
+
+  Polygon_with_holes_const_iterator end() const { return m_polygons.end(); }
+
+
   void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); }
 
   void add_polygon(Polygon_2&& pgn) { m_polygons.push_back(Polygon_with_holes_2(std::forward<Polygon_with_holes_2>(pgn))); }
@@ -84,6 +93,8 @@ class Multipolygon_with_holes_2 {
 
   void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }
 
+  void push_back(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
+
   void erase_polygon_with_holes(Polygon_with_holes_iterator pit) { m_polygons.erase(pit); }
 
   void clear() { m_polygons.clear(); }
diff --git a/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp b/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp
new file mode 100644
index 000000000000..6e2289728218
--- /dev/null
+++ b/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp
@@ -0,0 +1,32 @@
+#include <iostream>
+#include <fstream>
+#include <deque>
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Polygon_repair/repair.h>
+#include <CGAL/IO/WKT.h>
+
+using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
+using Point_2 = Kernel::Point_2;
+using Polygon_2 = CGAL::Polygon_2<Kernel>;
+using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<Kernel>;
+using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2<Kernel>;
+
+int main(int argc, char* argv[])
+{
+  std::ifstream in((argc > 1) ? argv[1] : CGAL::data_file_path("wkt/norway-polygons.wkt"));
+
+  typedef std::vector<Point_2> MultiPoint;
+  typedef std::vector<Point_2> LineString;
+  typedef std::deque<LineString> MultiLineString;
+
+  MultiPoint points;
+  MultiLineString polylines;
+  Multipolygon_with_holes_2 polygons;
+  CGAL::IO::read_WKT(in, points,polylines,polygons);
+
+  Multipolygon_with_holes_2 mp = CGAL::Polygon_repair::repair(polygons);
+  CGAL::IO::write_multi_polygon_WKT(std::cout, mp);
+
+  return 0;
+}

From 37740a9a2afd9af4261f782092b27c13932b9904 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 06:41:30 +0100
Subject: [PATCH 05/17] Add smaller data set

---
 Polygon_repair/examples/Polygon_repair/data/flat.wkt          | 4 ++++
 .../examples/Polygon_repair/polygons2multipolygon.cpp         | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 Polygon_repair/examples/Polygon_repair/data/flat.wkt

diff --git a/Polygon_repair/examples/Polygon_repair/data/flat.wkt b/Polygon_repair/examples/Polygon_repair/data/flat.wkt
new file mode 100644
index 000000000000..681cd65d046c
--- /dev/null
+++ b/Polygon_repair/examples/Polygon_repair/data/flat.wkt
@@ -0,0 +1,4 @@
+POLYGON((0 0, 40 0, 40 40, 0 40))
+POLYGON((10 10 , 30 10, 30 30, 0 30))
+POLYGON((1 1, 2 1, 2 2, 1 2))
+POLYGON((11 11, 12 11, 12 12, 11 12))
diff --git a/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp b/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp
index 6e2289728218..5b3d8f59d1c8 100644
--- a/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp
+++ b/Polygon_repair/examples/Polygon_repair/polygons2multipolygon.cpp
@@ -14,7 +14,7 @@ using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2<Kernel>;
 
 int main(int argc, char* argv[])
 {
-  std::ifstream in((argc > 1) ? argv[1] : CGAL::data_file_path("wkt/norway-polygons.wkt"));
+  std::ifstream in((argc > 1) ? argv[1] : "data/flat.wkt");
 
   typedef std::vector<Point_2> MultiPoint;
   typedef std::vector<Point_2> LineString;

From 2408df555a114549dd59081a6a073c1a20f0d1e3 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 07:18:03 +0100
Subject: [PATCH 06/17] Add some using

---
 .../include/CGAL/Polygon_repair/repair.h      | 107 ++++++++++--------
 1 file changed, 58 insertions(+), 49 deletions(-)

diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
index 6254dc0232ad..def03b7dcb00 100644
--- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h
+++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
@@ -298,29 +298,39 @@ bool is_valid(const Multipolygon_with_holes_2<Kernel, Container>& multipolygon)
 template <class Kernel, class Container = std::vector<typename Kernel::Point_2>>
 class Polygon_repair {
 public:
+  using FT = typename Kernel::FT;
+  using Point_2 = typename Kernel::Point_2;
   using Vertex_base = CGAL::Triangulation_vertex_base_2<Kernel>;
   using Face_base = CGAL::Constrained_triangulation_face_base_2<Kernel>;
   using Face_base_with_repair_info = internal::Triangulation_face_base_with_repair_info_2<Kernel, Face_base>;
   using Triangulation_data_structure = CGAL::Triangulation_data_structure_2<Vertex_base, Face_base_with_repair_info>;
-  using Tag = typename std::conditional<std::is_floating_point<typename Kernel::FT>::value,
+  using Tag = typename std::conditional<std::is_floating_point<typename FT>::value,
                                         CGAL::Exact_predicates_tag,
                                         CGAL::Exact_intersections_tag>::type;
   using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2<Kernel, Triangulation_data_structure, Tag>;
   using Triangulation = internal::Triangulation_with_even_odd_constraints_2<Constrained_Delaunay_triangulation>;
-  // TODO: Edge_map and Vertex_map use std::set and set::map with exact kernels since Point_2 can't be hashed otherwise
-  using Edge_map = typename std::conditional<std::is_floating_point<typename Kernel::FT>::value,
-                                             std::unordered_set<std::pair<typename Kernel::Point_2, typename Kernel::Point_2>,
-                                                                boost::hash<std::pair<typename Kernel::Point_2, typename Kernel::Point_2>>>,
-                                             std::set<std::pair<typename Kernel::Point_2, typename Kernel::Point_2>>>::type;
-  using Vertex_map = typename std::conditional<std::is_floating_point<typename Kernel::FT>::value,
-                                               std::unordered_map<typename Kernel::Point_2, typename Triangulation::Vertex_handle>,
-                                               std::map<typename Kernel::Point_2, typename Triangulation::Vertex_handle>>::type;
+  using Vertex_handle = typename Triangulation::Vertex_handle;
+  using Face_handle = typename Triangulation::Face_handle;
+  using Face_circulator = typename Triangulation::Face_circulator;
+  using Edge = typename Triangulation::Edge;
+
+  // TODO: Edge_map and Vertex_map use std::set and std::map with exact kernels since Point_2 can't be hashed otherwise
+  using Edge_map = typename std::conditional<std::is_floating_point<FT>::value,
+                                             std::unordered_set<std::pair<Point_2, Point_2>,
+                                                                boost::hash<std::pair<Point_2, Point_2>>>,
+                                             std::set<std::pair<Point_2, Point_2>>>::type;
+  using Vertex_map = typename std::conditional<std::is_floating_point<FT>::value,
+                                               std::unordered_map<Point_2, Vertex_handle>,
+                                               std::map<Point_2, Vertex_handle>>::type;
 
   using Validation_tag = CGAL::No_constraint_intersection_tag;
   using Validation_triangulation = CGAL::Constrained_triangulation_2<Kernel, Triangulation_data_structure, Validation_tag>;
 
+  using Polygon_2 = CGAL::Polygon_2<Kernel, Container>;
+  using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<Kernel, Container>;
+  using Multipolygon_with_holes_2 = CGAL::Multipolygon_with_holes_2<Kernel, Container>;
+
   struct Polygon_less {
-    using Polygon_2 = CGAL::Polygon_2<Kernel, Container>;
     bool operator()(const Polygon_2& pa, const Polygon_2& pb) const {
       typename Polygon_2::Vertex_iterator va = pa.vertices_begin();
       typename Polygon_2::Vertex_iterator vb = pb.vertices_begin();
@@ -335,7 +345,6 @@ class Polygon_repair {
   };
 
   struct Polygon_with_holes_less {
-    using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<Kernel, Container>;
     Polygon_less pl;
     bool operator()(const Polygon_with_holes_2& pa, const Polygon_with_holes_2& pb) const {
       if (pl(pa.outer_boundary(), pb.outer_boundary())) return true;
@@ -358,12 +367,12 @@ class Polygon_repair {
   /// @{
 
   // Add edges of the polygon to the triangulation
-  void add_to_triangulation_even_odd(const Polygon_2<Kernel, Container>& polygon) {
+  void add_to_triangulation_even_odd(const Polygon_2& polygon) {
 
     // Get unique edges
     for (auto const& edge: polygon.edges()) {
       if (edge.source() == edge.target()) continue;
-      std::pair<typename Kernel::Point_2, typename Kernel::Point_2> pair = (edge.source() < edge.target())?
+      std::pair<Point_2, Point_2> pair = (edge.source() < edge.target())?
       std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source());
       auto inserted = unique_edges.insert(pair);
       if (!inserted.second) unique_edges.erase(inserted.first);
@@ -371,10 +380,10 @@ class Polygon_repair {
 
     // Insert vertices
     Vertex_map vertices;
-    std::vector<std::pair<typename Triangulation::Vertex_handle, typename Triangulation::Vertex_handle>> edges_to_insert;
+    std::vector<std::pair<Vertex_handle, Vertex_handle>> edges_to_insert;
     edges_to_insert.reserve(unique_edges.size());
     for (auto const& edge: unique_edges) {
-      typename Triangulation::Vertex_handle first_vertex, second_vertex;
+      Vertex_handle first_vertex, second_vertex;
       typename Vertex_map::const_iterator found = vertices.find(edge.first);
       if (found == vertices.end()) {
         first_vertex = t.insert(edge.first, search_start);
@@ -399,12 +408,12 @@ class Polygon_repair {
   }
 
   // Add edges of the polygon to the triangulation
-  void add_to_triangulation_even_odd(const Polygon_with_holes_2<Kernel, Container>& polygon) {
+  void add_to_triangulation_even_odd(const Polygon_with_holes_2& polygon) {
 
     // Get unique edges
     for (auto const& edge: polygon.outer_boundary().edges()) {
       if (edge.source() == edge.target()) continue;
-      std::pair<typename Kernel::Point_2, typename Kernel::Point_2> pair = (edge.source() < edge.target())?
+      std::pair<Point_2, Point_2> pair = (edge.source() < edge.target())?
       std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source());
       auto inserted = unique_edges.insert(pair);
       if (!inserted.second) unique_edges.erase(inserted.first);
@@ -412,7 +421,7 @@ class Polygon_repair {
     for (auto const& hole: polygon.holes()) {
       for (auto const& edge: hole.edges()) {
         if (edge.source() == edge.target()) continue;
-        std::pair<typename Kernel::Point_2, typename Kernel::Point_2> pair = (edge.source() < edge.target())?
+        std::pair<Point_2, Point_2> pair = (edge.source() < edge.target())?
         std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source());
         auto inserted = unique_edges.insert(pair);
         if (!inserted.second) unique_edges.erase(inserted.first);
@@ -421,10 +430,10 @@ class Polygon_repair {
 
     // Insert vertices
     Vertex_map vertices;
-    std::vector<std::pair<typename Triangulation::Vertex_handle, typename Triangulation::Vertex_handle>> edges_to_insert;
+    std::vector<std::pair<Vertex_handle, Vertex_handle>> edges_to_insert;
     edges_to_insert.reserve(unique_edges.size());
     for (auto const& edge: unique_edges) {
-      typename Triangulation::Vertex_handle first_vertex, second_vertex;
+      Vertex_handle first_vertex, second_vertex;
       typename Vertex_map::const_iterator found = vertices.find(edge.first);
       if (found == vertices.end()) {
         first_vertex = t.insert(edge.first, search_start);
@@ -449,13 +458,13 @@ class Polygon_repair {
   }
 
   // Add edges of the polygon to the triangulation
-  void add_to_triangulation_even_odd(const Multipolygon_with_holes_2<Kernel, Container>& multipolygon) {
+  void add_to_triangulation_even_odd(const Multipolygon_with_holes_2& multipolygon) {
 
     // Get unique edges
     for (auto const& polygon: multipolygon.polygons_with_holes()) {
       for (auto const& edge: polygon.outer_boundary().edges()) {
         if (edge.source() == edge.target()) continue;
-        std::pair<typename Kernel::Point_2, typename Kernel::Point_2> pair = (edge.source() < edge.target())?
+        std::pair<Point_2, Point_2> pair = (edge.source() < edge.target())?
         std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source());
         auto inserted = unique_edges.insert(pair);
         if (!inserted.second) unique_edges.erase(inserted.first);
@@ -463,7 +472,7 @@ class Polygon_repair {
       for (auto const& hole: polygon.holes()) {
         for (auto const& edge: hole.edges()) {
           if (edge.source() == edge.target()) continue;
-          std::pair<typename Kernel::Point_2, typename Kernel::Point_2> pair = (edge.source() < edge.target())?
+          std::pair<Point_2, Point_2> pair = (edge.source() < edge.target())?
           std::make_pair(edge.source(), edge.target()) : std::make_pair(edge.target(), edge.source());
           auto inserted = unique_edges.insert(pair);
           if (!inserted.second) unique_edges.erase(inserted.first);
@@ -473,10 +482,10 @@ class Polygon_repair {
 
     // Insert vertices
     Vertex_map vertices;
-    std::vector<std::pair<typename Triangulation::Vertex_handle, typename Triangulation::Vertex_handle>> edges_to_insert;
+    std::vector<std::pair<Vertex_handle, Vertex_handle>> edges_to_insert;
     edges_to_insert.reserve(unique_edges.size());
     for (auto const& edge: unique_edges) {
-      typename Triangulation::Vertex_handle first_vertex, second_vertex;
+      Vertex_handle first_vertex, second_vertex;
       typename Vertex_map::const_iterator found = vertices.find(edge.first);
       if (found == vertices.end()) {
         first_vertex = t.insert(edge.first, search_start);
@@ -503,18 +512,18 @@ class Polygon_repair {
   // Label a region of adjacent triangles without passing through constraints
   // adjacent triangles that involve passing through constraints are added to to_check
   template <class T>
-  static void label_region(T& tt, typename T::Face_handle face, int label,
-                           std::list<typename T::Face_handle>& to_check,
+  static void label_region(T& tt, Face_handle face, int label,
+                           std::list<Face_handle>& to_check,
                            std::list<int>& to_check_added_by) {
     // std::cout << "Labelling region with " << label << std::endl;
-    std::list<typename Triangulation::Face_handle> to_check_in_region;
+    std::list<Face_handle> to_check_in_region;
     face->label() = label;
     to_check_in_region.push_back(face);
     face->processed() = true; // processed means added to a list (to ensure elements are only added once)
 
     while (!to_check_in_region.empty()) {
       for (int neighbour = 0; neighbour < 3; ++neighbour) {
-        if (!tt.is_constrained(typename Triangulation::Edge(to_check_in_region.front(), neighbour))) {
+        if (!tt.is_constrained(Edge(to_check_in_region.front(), neighbour))) {
           if (to_check_in_region.front()->neighbor(neighbour)->label() == 0) { // unlabeled
             to_check_in_region.front()->neighbor(neighbour)->label() = label;
             to_check_in_region.push_back(to_check_in_region.front()->neighbor(neighbour));
@@ -538,15 +547,15 @@ class Polygon_repair {
     for (auto vertex: t.all_vertex_handles()) {
       typename Triangulation::Edge_circulator first_edge = t.incident_edges(vertex);
       typename Triangulation::Edge_circulator current_edge = first_edge;
-      std::vector<typename Triangulation::Edge> incident_constrained_edges;
+      std::vector<Edge> incident_constrained_edges;
       do {
         if (t.is_constrained(*current_edge)) {
           incident_constrained_edges.push_back(*current_edge);
         } ++current_edge;
       } while (current_edge != first_edge);
       if (incident_constrained_edges.size() == 2) {
-        typename Kernel::Point_2 v1 = incident_constrained_edges.front().first->vertex(incident_constrained_edges.front().first->ccw(incident_constrained_edges.front().second))->point();
-        typename Kernel::Point_2 v2 = incident_constrained_edges.back().first->vertex(incident_constrained_edges.back().first->ccw(incident_constrained_edges.back().second))->point();
+        Point_2 v1 = incident_constrained_edges.front().first->vertex(incident_constrained_edges.front().first->ccw(incident_constrained_edges.front().second))->point();
+        Point_2 v2 = incident_constrained_edges.back().first->vertex(incident_constrained_edges.back().first->ccw(incident_constrained_edges.back().second))->point();
         if (CGAL::collinear(v1, vertex->point(), v2)) {
           // std::cout << "Collinear points" << std::endl;
           // std::cout << "v1: " << v1 << std::endl;
@@ -567,7 +576,7 @@ class Polygon_repair {
 
     // Label exterior with label -1, marking it as processed and
     // putting interior triangles adjacent to it in to_check
-    std::list<typename Triangulation::Face_handle> to_check;
+    std::list<Face_handle> to_check;
     std::list<int> to_check_added_by;
     label_region(t, t.infinite_face(), -1, to_check, to_check_added_by);
 
@@ -589,21 +598,21 @@ class Polygon_repair {
   }
 
   // Reconstruct ring boundary starting from an edge (face + opposite vertex) that is part of it
-  void reconstruct_ring(std::list<typename Kernel::Point_2>& ring,
-                        typename Triangulation::Face_handle face_adjacent_to_boundary,
+  void reconstruct_ring(std::list<Point_2>& ring,
+                        Face_handle face_adjacent_to_boundary,
                         int opposite_vertex) {
     // std::cout << "Reconstructing ring for face " << face_adjacent_to_boundary->label() << "..." << std::endl;
 
     // Create ring
-    typename Triangulation::Face_handle current_face = face_adjacent_to_boundary;
+    Face_handle current_face = face_adjacent_to_boundary;
     int current_opposite_vertex = opposite_vertex;
     do {
       CGAL_assertion(current_face->label() == face_adjacent_to_boundary->label());
       current_face->processed() = true;
-      typename Triangulation::Vertex_handle pivot_vertex = current_face->vertex(current_face->cw(current_opposite_vertex));
+      Vertex_handle pivot_vertex = current_face->vertex(current_face->cw(current_opposite_vertex));
       // std::cout << "\tAdding point " << pivot_vertex->point() << std::endl;
       ring.push_back(pivot_vertex->point());
-      typename Triangulation::Face_circulator fc = t.incident_faces(pivot_vertex, current_face);
+      Face_circulator fc = t.incident_faces(pivot_vertex, current_face);
       do {
         ++fc;
       } while (fc->label() != current_face->label());
@@ -613,8 +622,8 @@ class Polygon_repair {
              current_opposite_vertex != opposite_vertex);
 
     // Start at lexicographically smallest vertex
-    typename std::list<typename Kernel::Point_2>::iterator smallest_vertex = ring.begin();
-    for (typename std::list<typename Kernel::Point_2>::iterator current_vertex = ring.begin();
+    typename std::list<Point_2>::iterator smallest_vertex = ring.begin();
+    for (typename std::list<Point_2>::iterator current_vertex = ring.begin();
          current_vertex != ring.end(); ++current_vertex) {
       if (*current_vertex < *smallest_vertex) smallest_vertex = current_vertex;
     }
@@ -626,8 +635,8 @@ class Polygon_repair {
   // Reconstruct multipolygon based on the triangles labeled as inside the polygon
   void reconstruct_multipolygon() {
     mp.clear();
-    std::vector<Polygon_2<Kernel, Container>> polygons; // outer boundaries
-    std::vector<std::set<Polygon_2<Kernel, Container>, Polygon_less>> holes; // holes are ordered (per polygon)
+    std::vector<Polygon_2> polygons; // outer boundaries
+    std::vector<std::set<Polygon_2, Polygon_less>> holes; // holes are ordered (per polygon)
     polygons.resize(number_of_polygons);
     holes.resize(number_of_polygons);
 
@@ -641,11 +650,11 @@ class Polygon_repair {
         if (face->label() == face->neighbor(opposite_vertex)->label()) continue; // not adjacent to boundary
 
         // Reconstruct ring
-        std::list<typename Kernel::Point_2> ring;
+        std::list<Point_2> ring;
         reconstruct_ring(ring, face, opposite_vertex);
 
         // Put ring in polygons
-        Polygon_2<Kernel, Container> polygon;
+        Polygon_2 polygon;
         polygon.reserve(ring.size());
         polygon.insert(polygon.vertices_end(),ring.begin(), ring.end());
         // std::cout << "Reconstructed ring for polygon " << face->label() << " with ccw? " << (polygon.orientation() == CGAL::COUNTERCLOCKWISE) << std::endl;
@@ -658,9 +667,9 @@ class Polygon_repair {
     }
 
     // Create polygons with holes and put in multipolygon
-    std::set<Polygon_with_holes_2<Kernel, Container>, Polygon_with_holes_less> ordered_polygons;
+    std::set<Polygon_with_holes_2, Polygon_with_holes_less> ordered_polygons;
     for (std::size_t i = 0; i < polygons.size(); ++i) {
-      ordered_polygons.insert(Polygon_with_holes_2<Kernel, Container>(std::move(polygons[i]), std::make_move_iterator(holes[i].begin()), std::make_move_iterator(holes[i].end())));
+      ordered_polygons.insert(Polygon_with_holes_2(std::move(polygons[i]), std::make_move_iterator(holes[i].begin()), std::make_move_iterator(holes[i].end())));
     }
     for (auto const& polygon: ordered_polygons) {
       // std::cout << "Adding polygon " << polygon << std::endl;
@@ -687,7 +696,7 @@ class Polygon_repair {
     return t;
   }
 
-  const Multipolygon_with_holes_2<Kernel, Container>& multipolygon() {
+  const Multipolygon_with_holes_2& multipolygon() {
     return mp;
   }
 
@@ -697,9 +706,9 @@ class Polygon_repair {
 protected:
   Triangulation t;
   Edge_map unique_edges;
-  Multipolygon_with_holes_2<Kernel, Container> mp;
+  Multipolygon_with_holes_2 mp;
   int number_of_polygons, number_of_holes;
-  typename Triangulation::Face_handle search_start;
+  Face_handle search_start;
 };
 
 #endif // DOXYGEN_RUNNING

From 267ab235992202826b1c86a070376b53d59da2b5 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 08:22:05 +0100
Subject: [PATCH 07/17] remove typename

---
 Polygon_repair/include/CGAL/Polygon_repair/repair.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
index def03b7dcb00..8f420a478d87 100644
--- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h
+++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
@@ -304,7 +304,7 @@ class Polygon_repair {
   using Face_base = CGAL::Constrained_triangulation_face_base_2<Kernel>;
   using Face_base_with_repair_info = internal::Triangulation_face_base_with_repair_info_2<Kernel, Face_base>;
   using Triangulation_data_structure = CGAL::Triangulation_data_structure_2<Vertex_base, Face_base_with_repair_info>;
-  using Tag = typename std::conditional<std::is_floating_point<typename FT>::value,
+  using Tag = typename std::conditional<std::is_floating_point<FT>::value,
                                         CGAL::Exact_predicates_tag,
                                         CGAL::Exact_intersections_tag>::type;
   using Constrained_Delaunay_triangulation = CGAL::Constrained_Delaunay_triangulation_2<Kernel, Triangulation_data_structure, Tag>;

From fcff28f0aa0c6567f145b6fdfb8cf8542bb75eb1 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 08:22:23 +0100
Subject: [PATCH 08/17] move() -> forward<>()

---
 Polygon/include/CGAL/General_polygon_with_holes_2.h | 6 +++---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h    | 2 +-
 Polygon/include/CGAL/Polygon_with_holes_2.h         | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h
index bb19fcf99436..3034e1128342 100644
--- a/Polygon/include/CGAL/General_polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h
@@ -65,7 +65,7 @@ class General_polygon_with_holes_2 {
   {}
 
   explicit General_polygon_with_holes_2(Polygon_2&& pgn_boundary) :
-    m_pgn(std::move(pgn_boundary))
+    m_pgn(std::forward<Polygon_2>(pgn_boundary))
   {}
 
   template <typename HolesInputIterator>
@@ -80,7 +80,7 @@ class General_polygon_with_holes_2 {
   General_polygon_with_holes_2(Polygon_2&& pgn_boundary,
                                HolesInputIterator h_begin,
                                HolesInputIterator h_end) :
-    m_pgn(std::move(pgn_boundary)),
+    m_pgn(std::forward<Polygon_2>(pgn_boundary)),
     m_holes(h_begin, h_end)
   {}
 
@@ -104,7 +104,7 @@ class General_polygon_with_holes_2 {
 
   void add_hole(const Polygon_2& pgn_hole) { m_holes.push_back(pgn_hole); }
 
-  void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::move(pgn_hole)); }
+  void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::forward<Polygon_2>(pgn_hole)); }
 
   void erase_hole(Hole_iterator hit) { m_holes.erase(hit); }
 
diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 2449b9dd8eef..36cad53ecb3d 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -91,7 +91,7 @@ class Multipolygon_with_holes_2 {
 
   void add_polygon_with_holes(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 
-  void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }
+  void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::forward<Polygon_with_holes_2>(pgn)); }
 
   void push_back(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 
diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h
index 23eb826e9b2a..8f85085ed905 100644
--- a/Polygon/include/CGAL/Polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Polygon_with_holes_2.h
@@ -65,7 +65,7 @@ class Polygon_with_holes_2 :
 
   /*! Move constructor */
   explicit Polygon_with_holes_2 (Polygon_2&& pgn_boundary) :
-    Base (std::move(pgn_boundary))
+    Base (std::forward<Polygon_2>(pgn_boundary))
   {}
 
   /*! Constructor from a polygon (outer boundary) and hole polygons. */
@@ -84,7 +84,7 @@ class Polygon_with_holes_2 :
   Polygon_with_holes_2 (Polygon_2&& pgn_boundary,
                         HolesInputIterator h_begin,
                         HolesInputIterator h_end) :
-    Base (std::move(pgn_boundary), h_begin, h_end)
+    Base (std::forward<Polygon_2>(pgn_boundary), h_begin, h_end)
   {}
 
   /*! Obtain the bounding box of the polygon with holes */

From 3effd785c4019297cd431621a6d31f1fda0d6ab3 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 09:05:50 +0100
Subject: [PATCH 09/17] Add transform to Polygon_with_holes and
 Multipolygon_with_holes

---
 .../doc/Kernel_23/CGAL/Aff_transformation_2.h | 20 ++++----
 .../include/CGAL/Multipolygon_with_holes_2.h  | 12 +++++
 Polygon/include/CGAL/Polygon_with_holes_2.h   | 13 +++++
 .../Polygon/Multipolygon_with_holes_test.cpp  | 49 +++++++++++++++++++
 .../test/Polygon/Polygon_with_holes_test.cpp  |  8 ++-
 5 files changed, 91 insertions(+), 11 deletions(-)
 create mode 100644 Polygon/test/Polygon/Multipolygon_with_holes_test.cpp

diff --git a/Kernel_23/doc/Kernel_23/CGAL/Aff_transformation_2.h b/Kernel_23/doc/Kernel_23/CGAL/Aff_transformation_2.h
index bd9fd496af3a..a47111181d44 100644
--- a/Kernel_23/doc/Kernel_23/CGAL/Aff_transformation_2.h
+++ b/Kernel_23/doc/Kernel_23/CGAL/Aff_transformation_2.h
@@ -45,16 +45,16 @@ therefore do not appear in the constructors.
 \cgalHeading{Example}
 
 \code
-typedef Cartesian<double> K;
-typedef Aff_transformation_2<K> Transformation;
-typedef Point_2<K> Point;
-typedef Vector_2<K> Vector;
-typedef Direction_2<K> Direction;
-
-Transformation rotate(ROTATION, sin(pi), cos(pi));
-Transformation rational_rotate(ROTATION,Direction(1,1), 1, 100);
-Transformation translate(TRANSLATION, Vector(-2, 0));
-Transformation scale(SCALING, 3);
+typedef CGAL::Simple_cartesian<double> K;
+typedef CGAL::Aff_transformation_2<K> Transformation;
+typedef CGAL::Point_2<K> Point;
+typedef CGAL::Vector_2<K> Vector;
+typedef CGAL::Direction_2<K> Direction;
+
+Transformation rotate(CGAL::ROTATION, sin(pi), cos(pi));
+Transformation rational_rotate(CGAL::ROTATION,Direction(1,1), 1, 100);
+Transformation translate(CGAL::TRANSLATION, Vector(-2, 0));
+Transformation scale(CGAL::SCALING, 3);
 
 Point q(0, 1);
 q = rational_rotate(q);
diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 36cad53ecb3d..fcdaa3d6b695 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -193,6 +193,18 @@ std::ostream& operator<<(std::ostream& os,
   }
 }
 
+template <class Transformation, class Kernel, class Container>
+Multipolygon_with_holes_2<Kernel, Container> transform(const Transformation& t,
+                                                       const Multipolygon_with_holes_2<Kernel, Container>& mp)
+  {
+    Multipolygon_with_holes_2<Kernel, Container> result;
+    for(const auto& pwh : mp.polygons_with_holes()){
+      result.add_polygon_with_holes(std::move(transform(t, pwh)));
+    }
+    return result;
+
+  }
+
 
 } //namespace CGAL
 
diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h
index 8f85085ed905..fa7bb9e290c9 100644
--- a/Polygon/include/CGAL/Polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Polygon_with_holes_2.h
@@ -89,8 +89,21 @@ class Polygon_with_holes_2 :
 
   /*! Obtain the bounding box of the polygon with holes */
   Bbox_2 bbox() const { return this->outer_boundary().bbox(); }
+
 };
 
+  template <class Transformation, class Kernel, class Container>
+  Polygon_with_holes_2<Kernel,Container> transform(const Transformation& t,
+                                                   const Polygon_with_holes_2<Kernel,Container>& pwh)
+  {
+    Polygon_with_holes_2<Kernel,Container> result(transform(t, pwh.outer_boundary()));
+    for(const auto& hole : pwh.holes()){
+      result.add_hole(std::move(transform(t, hole)));
+    }
+    return result;
+  }
+
+
 //-----------------------------------------------------------------------//
 //                          operator<<
 //-----------------------------------------------------------------------//
diff --git a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
new file mode 100644
index 000000000000..1257db73f903
--- /dev/null
+++ b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
@@ -0,0 +1,49 @@
+#include <CGAL/Simple_cartesian.h>
+#include <CGAL/Polygon_2.h>
+#include <CGAL/Polygon_with_holes_2.h>
+#include <CGAL/Multipolygon_with_holes_2.h>
+
+#include <vector>
+#include <iostream>
+#include <cassert>
+#include <iterator>
+
+
+typedef CGAL::Simple_cartesian<double> K;
+typedef K::Point_2 Point;
+typedef K::Vector_2 Vector_2;
+typedef K::Aff_transformation_2 Transformation;
+
+typedef CGAL::Polygon_2<K> Polygon_2;
+typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes_2;
+typedef CGAL::Multipolygon_with_holes_2<K> Multipolygon_with_holes_2;
+
+int main()
+{
+  std::array<Point,4> outer = { Point(0, 0), Point(10, 0), Point(10, 10), Point(0, 10) };
+  std::array<Point, 4> hole1 = { Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1) };
+  std::array<Point, 4> hole2 = { Point(3, 3), Point(3, 4), Point(4, 4), Point(4, 3) };
+
+  std::vector<Polygon_2> holes;
+  holes.reserve(2);
+  holes.emplace_back(hole1.begin(), hole1.end());
+  holes.emplace_back(hole2.begin(), hole2.end());
+
+  Polygon_2 pouter(outer.begin(), outer.end());
+
+  Polygon_with_holes_2 pwh(std::move(pouter), std::move_iterator<std::vector<Polygon_2>::iterator>(holes.begin()), std::move_iterator<std::vector<Polygon_2>::iterator>(holes.end()));
+
+
+  Transformation translate(CGAL::TRANSLATION, Vector_2(20, 20));
+  Polygon_with_holes_2 pwhc = CGAL::transform(translate, pwh);
+
+  Multipolygon_with_holes_2 mp;
+  mp.add_polygon_with_holes(pwh);
+  mp.add_polygon_with_holes(pwhc);
+
+  mp = CGAL::transform(Transformation(CGAL::SCALING, 2.0), mp);
+
+  std::cout << mp << std::endl;
+
+  return 0;
+}
diff --git a/Polygon/test/Polygon/Polygon_with_holes_test.cpp b/Polygon/test/Polygon/Polygon_with_holes_test.cpp
index 97a3fc80fd18..482ab1af20d6 100644
--- a/Polygon/test/Polygon/Polygon_with_holes_test.cpp
+++ b/Polygon/test/Polygon/Polygon_with_holes_test.cpp
@@ -10,7 +10,8 @@
 
 typedef CGAL::Simple_cartesian<double> K;
 typedef K::Point_2 Point;
-
+typedef K::Vector_2 Vector_2;
+typedef K::Aff_transformation_2 Transformation;
 
 typedef CGAL::Polygon_2<K> Polygon_2;
 typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes_2;
@@ -41,5 +42,10 @@ int main()
   assert(pwh.outer_boundary().is_empty());
   Polygon_with_holes_2 pwh_move_assigned;
   pwh_move_assigned = std::move(pwh_copy);
+
+  std::cout << pwh_move_assigned << std::endl << "translated by Vector_2(2.0, 2.0)" << std::endl;
+  Transformation translate(CGAL::TRANSLATION, Vector_2(2, 2));
+  pwh_move_assigned = CGAL::transform(translate, pwh_move_assigned);
+  std::cout << pwh_move_assigned << std::endl;
   return 0;
 }

From 5d6874df85af784d92169b1607b2ac616327974b Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 10:40:12 +0200
Subject: [PATCH 10/17] Apply suggestions from code review

Co-authored-by: Laurent Rineau <Laurent.Rineau@cgal.org>
---
 Polygon/include/CGAL/General_polygon_with_holes_2.h | 6 +++---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h    | 6 +++---
 Polygon/include/CGAL/Polygon_with_holes_2.h         | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h
index 3034e1128342..bb19fcf99436 100644
--- a/Polygon/include/CGAL/General_polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h
@@ -65,7 +65,7 @@ class General_polygon_with_holes_2 {
   {}
 
   explicit General_polygon_with_holes_2(Polygon_2&& pgn_boundary) :
-    m_pgn(std::forward<Polygon_2>(pgn_boundary))
+    m_pgn(std::move(pgn_boundary))
   {}
 
   template <typename HolesInputIterator>
@@ -80,7 +80,7 @@ class General_polygon_with_holes_2 {
   General_polygon_with_holes_2(Polygon_2&& pgn_boundary,
                                HolesInputIterator h_begin,
                                HolesInputIterator h_end) :
-    m_pgn(std::forward<Polygon_2>(pgn_boundary)),
+    m_pgn(std::move(pgn_boundary)),
     m_holes(h_begin, h_end)
   {}
 
@@ -104,7 +104,7 @@ class General_polygon_with_holes_2 {
 
   void add_hole(const Polygon_2& pgn_hole) { m_holes.push_back(pgn_hole); }
 
-  void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::forward<Polygon_2>(pgn_hole)); }
+  void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::move(pgn_hole)); }
 
   void erase_hole(Hole_iterator hit) { m_holes.erase(hit); }
 
diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index fcdaa3d6b695..39ebd29dff32 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -87,11 +87,11 @@ class Multipolygon_with_holes_2 {
 
   void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); }
 
-  void add_polygon(Polygon_2&& pgn) { m_polygons.push_back(Polygon_with_holes_2(std::forward<Polygon_with_holes_2>(pgn))); }
+  void add_polygon(Polygon_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }
 
   void add_polygon_with_holes(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 
-  void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::forward<Polygon_with_holes_2>(pgn)); }
+  void add_polygon_with_holes(Polygon_with_holes_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }
 
   void push_back(const Polygon_with_holes_2& pgn) { m_polygons.push_back(pgn); }
 
@@ -199,7 +199,7 @@ Multipolygon_with_holes_2<Kernel, Container> transform(const Transformation& t,
   {
     Multipolygon_with_holes_2<Kernel, Container> result;
     for(const auto& pwh : mp.polygons_with_holes()){
-      result.add_polygon_with_holes(std::move(transform(t, pwh)));
+      result.add_polygon_with_holes(transform(t, pwh));
     }
     return result;
 
diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h
index fa7bb9e290c9..e551278bdb55 100644
--- a/Polygon/include/CGAL/Polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Polygon_with_holes_2.h
@@ -65,7 +65,7 @@ class Polygon_with_holes_2 :
 
   /*! Move constructor */
   explicit Polygon_with_holes_2 (Polygon_2&& pgn_boundary) :
-    Base (std::forward<Polygon_2>(pgn_boundary))
+    Base (std::move(pgn_boundary))
   {}
 
   /*! Constructor from a polygon (outer boundary) and hole polygons. */
@@ -84,7 +84,7 @@ class Polygon_with_holes_2 :
   Polygon_with_holes_2 (Polygon_2&& pgn_boundary,
                         HolesInputIterator h_begin,
                         HolesInputIterator h_end) :
-    Base (std::forward<Polygon_2>(pgn_boundary), h_begin, h_end)
+    Base (std::move(pgn_boundary), h_begin, h_end)
   {}
 
   /*! Obtain the bounding box of the polygon with holes */
@@ -98,7 +98,7 @@ class Polygon_with_holes_2 :
   {
     Polygon_with_holes_2<Kernel,Container> result(transform(t, pwh.outer_boundary()));
     for(const auto& hole : pwh.holes()){
-      result.add_hole(std::move(transform(t, hole)));
+      result.add_hole(transform(t, hole));
     }
     return result;
   }

From c8c67472b0f19ce312d7966dec7f6207c9545bef Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Tue, 16 Apr 2024 10:28:19 +0100
Subject: [PATCH 11/17] Add Mpwh::bbox()

---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h      | 10 ++++++++++
 Polygon/test/Polygon/Multipolygon_with_holes_test.cpp |  2 ++
 2 files changed, 12 insertions(+)

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 39ebd29dff32..8636626d1a9f 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -101,6 +101,16 @@ class Multipolygon_with_holes_2 {
 
   Size number_of_polygons_with_holes() const { return static_cast<Size>(m_polygons.size()); }
 
+  Bbox_2 bbox() const
+  {
+    Bbox_2 bb;
+    for(const auto& pwh : polygons_with_holes()){
+      bb += pwh.bbox();
+    }
+    return bb;
+  }
+
+
 protected:
   Polygon_with_holes_container m_polygons;
 };
diff --git a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
index 1257db73f903..7592211bd436 100644
--- a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
+++ b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
@@ -45,5 +45,7 @@ int main()
 
   std::cout << mp << std::endl;
 
+  CGAL::Bbox_2 bb = mp.bbox();
+
   return 0;
 }

From 02dd6ad63d72814fb6f906cabd08c19e1a5afd5a Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Wed, 17 Apr 2024 08:05:22 +0100
Subject: [PATCH 12/17] Fix warning in test

---
 Polygon/test/Polygon/Multipolygon_with_holes_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
index 7592211bd436..49584c7b0115 100644
--- a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
+++ b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
@@ -46,6 +46,6 @@ int main()
   std::cout << mp << std::endl;
 
   CGAL::Bbox_2 bb = mp.bbox();
-
+  std::cout << bb << std::endl;
   return 0;
 }

From 6158ffa63e98c9af9d1527741ab2490755ed3413 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Wed, 17 Apr 2024 10:50:13 +0100
Subject: [PATCH 13/17] fix comment in demo

---
 .../Triangulation_2/Constrained_Delaunay_triangulation_2.cpp    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp
index 990a8952cad2..076ad27660b6 100644
--- a/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp
+++ b/GraphicsView/demo/Triangulation_2/Constrained_Delaunay_triangulation_2.cpp
@@ -288,7 +288,7 @@ MainWindow::MainWindow()
   // Setup input handlers. They get events before the scene gets them
   // and the input they generate is passed to the triangulation with
   // the signal/slot mechanism
-  pi = new CGAL::Qt::GraphicsViewPolylineInput<K>(this, &scene, 0, true); // inputs polylines which are not closed
+  pi = new CGAL::Qt::GraphicsViewPolylineInput<K>(this, &scene, 0, true); // inputs polylines which are closed
   QObject::connect(pi, SIGNAL(generate(CGAL::Object)),
                    this, SLOT(processInput(CGAL::Object)));
 

From 8f1086f0509ed75517f79842dd4339bf6675c942 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Thu, 18 Apr 2024 09:57:47 +0100
Subject: [PATCH 14/17] move a using to avoid doxygen warning

---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 8636626d1a9f..79e515a2b783 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -43,9 +43,10 @@ class Multipolygon_with_holes_2 {
 
   /// polygon with holes type
   using Polygon_with_holes_2 = CGAL::Polygon_with_holes_2<Kernel, Container>;
-  using value_type = Polygon_with_holes_2;
+
   /// @}
 
+  using value_type = Polygon_with_holes_2;
   using Polygon_with_holes_container = std::deque<Polygon_with_holes_2>;
 
   using Polygon_with_holes_iterator = typename Polygon_with_holes_container::iterator;

From 29c6a7905f579e4d34d79bcaeb36bb8016f00b0c Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Fri, 19 Apr 2024 08:10:46 +0100
Subject: [PATCH 15/17] Add is_empty()

---
 Polygon/include/CGAL/General_polygon_with_holes_2.h | 13 +++++++++++++
 Polygon/include/CGAL/Multipolygon_with_holes_2.h    |  9 +++++++++
 .../test/Polygon/Multipolygon_with_holes_test.cpp   |  1 +
 Polygon_repair/include/CGAL/Polygon_repair/repair.h |  1 -
 4 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h
index bb19fcf99436..1e47948076e0 100644
--- a/Polygon/include/CGAL/General_polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h
@@ -123,6 +123,19 @@ class General_polygon_with_holes_2 {
 
   bool is_plane() const { return (m_pgn.is_empty() && m_holes.empty()); }
 
+  bool is_empty() const
+  {
+    if(! outer_boundary().is_empty()) {
+        return false;
+      }
+    for(const auto& h : holes()){
+      if(! h.is_empty()){
+        return false;
+      }
+    }
+    return true;
+  }
+
 protected:
   Polygon_2 m_pgn;
   Holes_container m_holes;
diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 79e515a2b783..6cbf3551e675 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -111,6 +111,15 @@ class Multipolygon_with_holes_2 {
     return bb;
   }
 
+  bool is_empty() const
+  {
+    for(const auto& pwh : polygons_with_holes()){
+      if(! pwh.is_empty()){
+        return false;
+      }
+    }
+    return true;
+  }
 
 protected:
   Polygon_with_holes_container m_polygons;
diff --git a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
index 49584c7b0115..18ddb1b7f459 100644
--- a/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
+++ b/Polygon/test/Polygon/Multipolygon_with_holes_test.cpp
@@ -47,5 +47,6 @@ int main()
 
   CGAL::Bbox_2 bb = mp.bbox();
   std::cout << bb << std::endl;
+  assert(! mp.is_empty());
   return 0;
 }
diff --git a/Polygon_repair/include/CGAL/Polygon_repair/repair.h b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
index 8f420a478d87..f6f2e84cfeed 100644
--- a/Polygon_repair/include/CGAL/Polygon_repair/repair.h
+++ b/Polygon_repair/include/CGAL/Polygon_repair/repair.h
@@ -314,7 +314,6 @@ class Polygon_repair {
   using Face_circulator = typename Triangulation::Face_circulator;
   using Edge = typename Triangulation::Edge;
 
-  // TODO: Edge_map and Vertex_map use std::set and std::map with exact kernels since Point_2 can't be hashed otherwise
   using Edge_map = typename std::conditional<std::is_floating_point<FT>::value,
                                              std::unordered_set<std::pair<Point_2, Point_2>,
                                                                 boost::hash<std::pair<Point_2, Point_2>>>,

From 31018d0a5008c4a758633f63709cd54e903ddc48 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Fri, 19 Apr 2024 10:13:40 +0100
Subject: [PATCH 16/17] Apply the rule of five

---
 Polygon/include/CGAL/General_polygon_with_holes_2.h |  2 +-
 Polygon/include/CGAL/Multipolygon_with_holes_2.h    |  2 +-
 Polygon/include/CGAL/Polygon_2.h                    | 12 ++----------
 Polygon/include/CGAL/Polygon_with_holes_2.h         | 10 ++++------
 4 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h
index 1e47948076e0..90b3bca3b489 100644
--- a/Polygon/include/CGAL/General_polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h
@@ -57,7 +57,7 @@ class General_polygon_with_holes_2 {
 
   typedef unsigned int                                Size;
 
-  General_polygon_with_holes_2() : m_pgn() {}
+  General_polygon_with_holes_2() = default;
 
 
   explicit General_polygon_with_holes_2(const Polygon_2& pgn_boundary) :
diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index 6cbf3551e675..b225e8498e57 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -56,7 +56,7 @@ class Multipolygon_with_holes_2 {
   using Size = unsigned int;
 
   /*! %Default constructor. */
-  Multipolygon_with_holes_2() {}
+  Multipolygon_with_holes_2() = default;
 
   /*! Constructor from polygons. */
   template <typename PolygonsInputIterator>
diff --git a/Polygon/include/CGAL/Polygon_2.h b/Polygon/include/CGAL/Polygon_2.h
index ff97d3c89932..c3300d939fa4 100644
--- a/Polygon/include/CGAL/Polygon_2.h
+++ b/Polygon/include/CGAL/Polygon_2.h
@@ -161,11 +161,8 @@ class Polygon_2 {
     /// Creates an empty polygon.
     Polygon_2(const Traits & p_traits) : traits(p_traits) {}
 
-    /// Copy constructor.
-    Polygon_2(const Polygon_2<Traits_P,Container_P>& polygon) = default;
-
-    /// Move constructor
-    Polygon_2(Polygon_2<Traits_P,Container_P>&& polygon) = default;
+    // Move constructor
+    // Polygon_2(Polygon_2<Traits_P,Container_P>&& polygon) = default;
 
     /// Creates a polygon with vertices from the sequence
     /// defined by the range \c [first,last).
@@ -176,11 +173,6 @@ class Polygon_2 {
       : d_container(first,last), traits(p_traits)
     {}
 
-#ifndef DOXYGEN_RUNNING
-  Polygon_2& operator=(const Polygon_2&) = default;
-  Polygon_2& operator=(Polygon_2&& p) = default;
-#endif
-
     /// @}
 
     /// \name Modifiers
diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h
index e551278bdb55..032b2c52084d 100644
--- a/Polygon/include/CGAL/Polygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Polygon_with_holes_2.h
@@ -49,9 +49,7 @@ class Polygon_with_holes_2 :
   typedef typename Base::Size                        Size;
 
   /*! %Default constructor. */
-  Polygon_with_holes_2 () :
-    Base()
-  {}
+  Polygon_with_holes_2 () = default;
 
   /*! Constructor from the base class. */
   Polygon_with_holes_2 (const Base& base) :
@@ -63,7 +61,7 @@ class Polygon_with_holes_2 :
     Base (pgn_boundary)
   {}
 
-  /*! Move constructor */
+  /*! Cconstructor moving a polygon */
   explicit Polygon_with_holes_2 (Polygon_2&& pgn_boundary) :
     Base (std::move(pgn_boundary))
   {}
@@ -76,7 +74,7 @@ class Polygon_with_holes_2 :
     Base (pgn_boundary, h_begin, h_end)
   {}
 
-  /*! Move constructor.
+  /*! Cconstructor moving a polygon.
    * \note In order to move the hole polygons a
    * `std::move_iterator` may be used.
    */
@@ -87,7 +85,7 @@ class Polygon_with_holes_2 :
     Base (std::move(pgn_boundary), h_begin, h_end)
   {}
 
-  /*! Obtain the bounding box of the polygon with holes */
+  /*! returns the bounding box of the polygon with holes */
   Bbox_2 bbox() const { return this->outer_boundary().bbox(); }
 
 };

From dfa0a124cdff326dc252a284270522c2cc602673 Mon Sep 17 00:00:00 2001
From: Andreas Fabri <andreas.fabri@geometryfactory.com>
Date: Fri, 19 Apr 2024 11:29:19 +0200
Subject: [PATCH 17/17] Update Polygon/include/CGAL/Multipolygon_with_holes_2.h

---
 Polygon/include/CGAL/Multipolygon_with_holes_2.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Polygon/include/CGAL/Multipolygon_with_holes_2.h b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
index b225e8498e57..a8b6a32ca2d0 100644
--- a/Polygon/include/CGAL/Multipolygon_with_holes_2.h
+++ b/Polygon/include/CGAL/Multipolygon_with_holes_2.h
@@ -86,7 +86,7 @@ class Multipolygon_with_holes_2 {
   Polygon_with_holes_const_iterator end() const { return m_polygons.end(); }
 
 
-  void add_polygon(const Polygon_2& pgn) { m_polygons.push_back(Polygon_with_holes_2(pgn)); }
+  void add_polygon(const Polygon_2& pgn) { m_polygons.emplace_back(pgn); }
 
   void add_polygon(Polygon_2&& pgn) { m_polygons.emplace_back(std::move(pgn)); }