PolyFEM
Loading...
Searching...
No Matches
ClipperUtils.cpp
Go to the documentation of this file.
1#include "ClipperUtils.hpp"
2
3#include <polyclipper2d.hh>
4#include <polyclipper3d.hh>
5
7
8namespace polyfem::utils
9{
10 std::vector<Eigen::MatrixXd> PolygonClipping::clip(
11 const Eigen::MatrixXd &subject_polygon,
12 const Eigen::MatrixXd &clipping_polygon)
13 {
14 // #ifdef POLYFEM_WITH_CLIPPER
15 // using namespace ClipperLib;
16
17 // Clipper clipper;
18
19 // clipper.AddPath(toClipperPolygon(subject_polygon), ptSubject, /*closed=*/true);
20 // clipper.AddPath(toClipperPolygon(clipping_polygon), ptClip, /*closed=*/true);
21
22 // Paths solution;
23 // clipper.Execute(ctIntersection, solution, pftNonZero, pftNonZero);
24
25 // std::vector<Eigen::MatrixXd> result;
26 // result.reserve(solution.size());
27 // for (const auto &path : solution)
28 // {
29 // result.push_back(fromClipperPolygon(path));
30 // }
31
32 // return result;
33 // #else
34 using namespace PolyClipper;
35
36 // Convert the subject polygon to PolyClipper format.
37 std::vector<Vertex2d<>> poly;
38 {
39 std::vector<Vector2d> positions;
40 positions.reserve(subject_polygon.rows());
41 std::vector<std::vector<int>> neighbors;
42 neighbors.reserve(subject_polygon.rows());
43 for (int i = 0; i < subject_polygon.rows(); i++)
44 {
45 positions.push_back(toPolyClipperVector(subject_polygon.row(i)));
46 neighbors.emplace_back(2);
47 // Clockwise neighbor is the next vertex (assuming the polygon is given in clockwise order).
48 neighbors.back()[0] = (i + 1) % subject_polygon.rows();
49 // Counter-clockwise neighbor is the previous vertex (assuming the polygon is given in clockwise order).
50 neighbors.back()[1] = i == 0 ? (subject_polygon.rows() - 1) : (i - 1); // -1 % n = -1 but we want n-1;
51 }
52
53 initializePolygon(poly, positions, neighbors);
54 }
55
56 // Clip the subject polygon with the clipping polygon.
57 {
58 // Convert the clipping polygon to planes.
59 std::vector<Plane<internal::VectorAdapter<Vector2d>>> planes;
60 for (int i = 0; i < clipping_polygon.rows(); i++)
61 {
62 const Vector2d e0 = toPolyClipperVector(clipping_polygon.row(i));
63 const Vector2d e1 = toPolyClipperVector(clipping_polygon.row((i + 1) % clipping_polygon.rows()));
64 const Vector2d e = e1 - e0;
65 planes.emplace_back(e0, Vector2d(e.y, -e.x).unitVector());
66 }
67
68 clipPolygon(poly, planes);
69 }
70
71 // Convert the clipped polygon to Eigen format.
72 std::vector<Eigen::MatrixXd> result;
73 {
74 std::vector<std::vector<Eigen::Vector2d>> polygons;
75
76 std::vector<bool> found_vertex(poly.size(), false);
77 for (int i = 0; i < poly.size(); i++)
78 {
79 if (!found_vertex[i])
80 polygons.emplace_back();
81
82 int j = i;
83 while (!found_vertex[j])
84 {
85 found_vertex[j] = true;
86 polygons.back().emplace_back(fromPolyClipperVector(poly[j].position));
87 j = poly[j].neighbors.first; // clockwise neighbor
88 }
89 }
90
91 for (const std::vector<Eigen::Vector2d> &polygon : polygons)
92 {
93 result.emplace_back(polygon.size(), 2);
94 for (int i = 0; i < polygon.size(); i++)
95 result.back().row(i) = polygon[i];
96 }
97 }
98
99 return result;
100 // #endif
101 }
102
103 std::vector<Eigen::MatrixXd> TriangleClipping::clip(
104 const Eigen::MatrixXd &subject_triangle,
105 const Eigen::MatrixXd &clipping_triangle)
106 {
107 const std::vector<Eigen::MatrixXd> overlap =
109 triangle_to_clockwise_order(subject_triangle),
110 triangle_to_clockwise_order(clipping_triangle));
111 assert(overlap.size() <= 1);
112
113 if (overlap.empty() || overlap[0].rows() < 3)
114 return std::vector<Eigen::MatrixXd>();
115
116 return triangle_fan(overlap[0]);
117 }
118
119 std::vector<Eigen::MatrixXd> TetrahedronClipping::clip(
120 const Eigen::MatrixXd &subject_tet,
121 const Eigen::MatrixXd &clipping_tet)
122 {
123 using namespace PolyClipper;
124 assert(subject_tet.rows() == 4 && subject_tet.cols() == 3);
125 assert(clipping_tet.rows() == 4 && clipping_tet.cols() == 3);
126 assert(tetrahedron_volume(subject_tet) > 0);
127 assert(tetrahedron_volume(clipping_tet) > 0);
128
129 // Convert the subject tet to PolyClipper format.
130 std::vector<Vertex3d<>> poly;
131 {
132 std::vector<Vector3d> positions(subject_tet.rows());
133 for (int i = 0; i < subject_tet.rows(); i++)
134 positions[i] = toPolyClipperVector(subject_tet.row(i));
135
136 std::vector<std::vector<int>> neighbors = {{1, 3, 2}, {2, 3, 0}, {0, 3, 1}, {0, 1, 2}};
137
138 initializePolyhedron(poly, positions, neighbors);
139 }
140
141 // Clip the subject tet with the clipping tet.
142 {
143 // Convert the clipping tet to planes.
144 const Vector3d t0 = toPolyClipperVector(clipping_tet.row(0));
145 const Vector3d t1 = toPolyClipperVector(clipping_tet.row(1));
146 const Vector3d t2 = toPolyClipperVector(clipping_tet.row(2));
147 const Vector3d t3 = toPolyClipperVector(clipping_tet.row(3));
148
149 std::vector<Plane<internal::VectorAdapter<Vector3d>>> planes;
150 planes.emplace_back(t0, (t1 - t0).cross(t2 - t0).unitVector());
151 planes.emplace_back(t0, (t2 - t0).cross(t3 - t0).unitVector());
152 planes.emplace_back(t0, (t3 - t0).cross(t1 - t0).unitVector());
153 planes.emplace_back(t1, (t3 - t1).cross(t2 - t1).unitVector());
154
155 clipPolyhedron(poly, planes);
156 }
157
158 // Convert the clipped polygon to Eigen format.
159 const std::vector<std::vector<int>> T = splitIntoTetrahedra(poly);
160 std::vector<Eigen::MatrixXd> result(T.size(), Eigen::MatrixXd(4, 3));
161 for (int i = 0; i < T.size(); i++)
162 {
163 for (int j = 0; j < 4; j++)
164 result[i].row(j) = fromPolyClipperVector(poly[T[i][j]].position);
165 assert(tetrahedron_volume(result[i]) > 0);
166 }
167
168 return result;
169 }
170
171#ifdef POLYFEM_WITH_CLIPPER
172 namespace
173 {
174 double scale_double_coord(double coord)
175 {
176 return coord * (double)DOUBLE_TO_INT_SCALE_FACTOR;
177 }
178 } // namespace
179
180 ClipperLib::IntPoint PolygonClipping::toClipperPoint(const Eigen::RowVector2d &p)
181 {
182 ClipperLib::IntPoint r;
183 assert(abs(scale_double_coord(p.x())) <= ClipperLib::hiRange);
184 r.X = (ClipperLib::cInt)std::round(scale_double_coord(p.x()));
185 assert(abs(scale_double_coord(p.y())) <= ClipperLib::hiRange);
186 r.Y = (ClipperLib::cInt)std::round(scale_double_coord(p.y()));
187 return r;
188 }
189
190 Eigen::RowVector2d PolygonClipping::fromClipperPoint(const ClipperLib::IntPoint &p)
191 {
192 return Eigen::RowVector2d(p.X, p.Y) / DOUBLE_TO_INT_SCALE_FACTOR;
193 }
194
195 ClipperLib::Path PolygonClipping::toClipperPolygon(const Eigen::MatrixXd &V)
196 {
197 ClipperLib::Path path(V.rows());
198 for (size_t i = 0; i < path.size(); ++i)
199 {
200 path[i] = toClipperPoint(V.row(i));
201 }
202 return path;
203 }
204
205 Eigen::MatrixXd PolygonClipping::fromClipperPolygon(const ClipperLib::Path &path)
206 {
207 Eigen::MatrixXd V(path.size(), 2);
208 for (size_t i = 0; i < path.size(); ++i)
209 {
210 V.row(i) = fromClipperPoint(path[i]);
211 }
212 return V;
213 }
214#endif
215
216 PolyClipper::Vector2d PolygonClipping::toPolyClipperVector(const Eigen::Vector2d &v)
217 {
218 return PolyClipper::Vector2d(v.x(), v.y());
219 }
220
221 Eigen::Vector2d PolygonClipping::fromPolyClipperVector(const PolyClipper::Vector2d &v)
222 {
223 return Eigen::Vector2d(v.x, v.y);
224 }
225
226 PolyClipper::Vector3d TetrahedronClipping::toPolyClipperVector(const Eigen::Vector3d &v)
227 {
228 return PolyClipper::Vector3d(v.x(), v.y(), v.z());
229 }
230
231 Eigen::Vector3d TetrahedronClipping::fromPolyClipperVector(const PolyClipper::Vector3d &v)
232 {
233 return Eigen::Vector3d(v.x, v.y, v.z);
234 }
235} // namespace polyfem::utils
int V
static PolyClipper::Vector2d toPolyClipperVector(const Eigen::Vector2d &v)
static std::vector< Eigen::MatrixXd > clip(const Eigen::MatrixXd &subject_polygon, const Eigen::MatrixXd &clipping_polygon)
Clip a polygon using convex polygon.
static Eigen::Vector2d fromPolyClipperVector(const PolyClipper::Vector2d &v)
static Eigen::Vector3d fromPolyClipperVector(const PolyClipper::Vector3d &v)
static std::vector< Eigen::MatrixXd > clip(const Eigen::MatrixXd &subject_tet, const Eigen::MatrixXd &clipping_tet)
Clip a tetrahedron using tetrahedron.
static PolyClipper::Vector3d toPolyClipperVector(const Eigen::Vector3d &v)
static std::vector< Eigen::MatrixXd > clip(const Eigen::MatrixXd &subject_triangle, const Eigen::MatrixXd &clipping_triangle)
Clip a triangle using triangle.
path
Definition eigs.py:128
Eigen::Matrix< double, dim, 1 > cross(const Eigen::Matrix< double, dim, 1 > &x, const Eigen::Matrix< double, dim, 1 > &y)
double tetrahedron_volume(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, const Eigen::Vector3d &d)
Compute the signed volume of a tetrahedron defined by four points.
Eigen::MatrixXd triangle_to_clockwise_order(const Eigen::MatrixXd &triangle)
Reorder the vertices of a triangle so they are in clockwise order.
std::vector< Eigen::MatrixXd > triangle_fan(const Eigen::MatrixXd &convex_polygon)
Convert a convex polygon to a list of triangles fanned around the first vertex.