Loading [MathJax]/extensions/tex2jax.js

dune-mmesh (1.4)

polygoncutting.hh
1#ifndef DUNE_MMESH_GRID_POLYGONCUTTING_HH
2#define DUNE_MMESH_GRID_POLYGONCUTTING_HH
3
4#include <iostream>
5#include <algorithm>
6
7namespace Dune
8{
9 template<class Scalar, class Point>
10 class PolygonCutting
11 {
12 public:
13
14 //implements the Sutherland-Hodgman algorithm to determine the polygon that
15 //emerges from clipping a subject polygon with respect to the edges of a
16 //clip polygon, subject polygon and clip polygon as well as the resulting
17 //polygon are represented by lists of their corners points with the points
18 //arranged in a consecutive counterclockwise order
19 template< typename Polygon >
20 static std::vector<Point> sutherlandHodgman(const Polygon& subjectPolygon,
21 const Polygon& clipPolygonInput)
22 {
23 std::vector<Point>
24 outputPolygon(subjectPolygon.begin(), subjectPolygon.end());
25 std::vector<Point>
26 clipPolygon(clipPolygonInput.begin(), clipPolygonInput.end());
27
28 const int clipSize = clipPolygon.size();
29
30 //iterate over the edges of the clipping polygon represented by
31 //consecutive points (indices clipIdx and clipIdxNext) in clipPolygon
32 for (int clipIdx = 0; clipIdx < clipSize; clipIdx++)
33 {
34 const int clipIdxNext = (clipIdx + 1) % clipSize;
35
36 std::vector<Point> inputPolygon(outputPolygon);
37 outputPolygon.clear();
38 const int inputSize = inputPolygon.size();
39
40 //iterate over the edges of the subject polygon represented by
41 //consectutive points (indices subjIdx and subjIdxNext) and clip each
42 //subject edge with respect to current clipping edge (indices clipIdx
43 //and clipIdxNext)
44 for (int inputIdx = 0; inputIdx < inputSize; inputIdx++)
45 {
46 const int inputIdxNext = (inputIdx + 1) % inputSize;
47
48 //Case differentation: Determine the positions of the corner points
49 //of the subject edge p1, p2 with respect to the current clipping
50 //edge given as the line from q1 to q2.
51 //This is done by evaluating the cross product
52 //d := (q1 - q2) x (p_i - q_1) = [(q1 - q2) x p_i] + q2 x q1
53 //for i = 1, 2.
54 //d < 0 => p_i inside, d > 0 => p_i outside,
55 //d = 0 => p_i on clipping edge
56
57 Point deltaQ = clipPolygon[clipIdxNext] - clipPolygon[clipIdx];
58
59 Scalar q2_cross_q1 =
60 clipPolygon[clipIdx][1] * clipPolygon[clipIdxNext][0] -
61 clipPolygon[clipIdx][0] * clipPolygon[clipIdxNext][1];
62
63 Scalar firstPos = - deltaQ[0] * inputPolygon[inputIdx][1]
64 + deltaQ[1] * inputPolygon[inputIdx][0] + q2_cross_q1;
65 Scalar secondPos = - deltaQ[0] * inputPolygon[inputIdxNext][1]
66 + deltaQ[1] * inputPolygon[inputIdxNext][0] + q2_cross_q1;
67
68 static constexpr double EPSILON = 1e-14;
69 //case 1: first point outside, second point inside
70 if ( firstPos > EPSILON && secondPos < -EPSILON )
71 {
72 //add intersection point and second point to output polygon
73 outputPolygon.push_back( lineIntersectionPoint(
74 inputPolygon[inputIdx], inputPolygon[inputIdxNext],
75 clipPolygon[clipIdx], clipPolygon[clipIdxNext] )
76 );
77 outputPolygon.push_back( inputPolygon[inputIdxNext] );
78 }
79
80 //case 2: first point inside, second point outside
81 else if ( firstPos < -EPSILON && secondPos > EPSILON )
82 {
83 //add intersection point to output polygon
84 outputPolygon.push_back( lineIntersectionPoint(
85 inputPolygon[inputIdx], inputPolygon[inputIdxNext],
86 clipPolygon[clipIdx], clipPolygon[clipIdxNext] )
87 );
88 }
89
90 //case 3: first point outside or on the edge, scond point outside
91 else if ( firstPos >= -EPSILON && secondPos > EPSILON )
92 {
93 //do nothing
94 continue;
95 }
96
97 //case 4: first point inside, second point inside or on the edge
98 else
99 {
100 //add second point to output polygon
101 outputPolygon.push_back( inputPolygon[inputIdxNext] );
102 }
103 }
104 }
105
106 return outputPolygon;
107 }
108
109 //computes the point of intersection in 2d between the line given by the
110 //points p1, p2 and the line defined by the points q1, q2
111 static Point lineIntersectionPoint(const Point& p1, const Point& p2,
112 const Point& q1, const Point& q2)
113 {
114 Point deltaP = p1 - p2;
115 Point deltaQ = q1 - q2;
116
117 Scalar scaleFactor = deltaP[0] * deltaQ[1] - deltaQ[0] * deltaP[1];
118
119 deltaP *= q1[0] * q2[1] - q1[1] * q2[0];
120 deltaQ *= p1[0] * p2[1] - p1[1] * p2[0];
121
122 Point intersection = deltaQ - deltaP;
123 intersection /= scaleFactor;
124
125 return intersection;
126 }
127
128
129 //computes the area of a convex polygon by evaluating the shoelace formula,
130 //the polygon is represented by a corner point list with the points arranged
131 //consecutively in counterclockwise order (for clockwise order (-1)*area
132 //will be returned)
133 template< typename Points >
134 static Scalar polygonArea (const Points& polygonPoints)
135 {
136 const int polygonSize = polygonPoints.size();
137
138 if (polygonSize < 3)
139 {
140 return 0.0;
141 }
142
143 Scalar area(0.0);
144
145 for (int i = 0; i < polygonSize; i++)
146 {
147 const int j = (i+1) % polygonSize;
148 area += polygonPoints[i][0] * polygonPoints[j][1];
149 area -= polygonPoints[j][0] * polygonPoints[i][1];
150 }
151
152 return 0.5 * area;
153 }
154
155#if CGAL_INTERSECTION
156 template< typename Triang >
157 static Scalar intersectionVolumeCGAL( const Triang& subjectTriangle,
158 const Triang& clipTriangle )
159 {
160 using Epeck = CGAL::Exact_predicates_exact_constructions_kernel;
161 using PointCGAL = CGAL::Point_2<Epeck>;
162 using Triangle = CGAL::Triangle_2<Epeck>;
163
164 std::array<PointCGAL, 3> v;
165 for ( int i = 0; i < 3; ++i )
166 {
167 const auto& p = makePoint( subjectTriangle[i] );
168 v[i] = PointCGAL( p.x(), p.y() );
169 }
170 const Triangle triangle1 ( v[0], v[1], v[2] );
171
172 for ( int i = 0; i < 3; ++i )
173 {
174 const auto& p = makePoint( clipTriangle[i] );
175 v[i] = PointCGAL( p.x(), p.y() );
176 }
177 const Triangle triangle2 ( v[0], v[1], v[2] );
178
179 const auto result = CGAL::intersection( triangle1, triangle2 );
180
181 using PointList = std::vector<PointCGAL>;
182 using Polygon = CGAL::Polygon_2<Epeck>;
183 if (result)
184 {
185 // intersection is triangle
186 if (const Triangle* t = boost::get<Triangle>(&*result))
187 return std::abs( CGAL::to_double(
188 CGAL::area( t->vertex(0), t->vertex(1), t->vertex(2) ) ) );
189
190 // intersection is polygon
191 else if ( const PointList* points = boost::get<PointList>(&*result))
192 {
193 Polygon polygon( points->begin(), points->end() );
194 return std::abs( CGAL::to_double( polygon.area() ) );
195 }
196 }
197
198 // there is no intersection
199 return 0;
200 }
201#endif
202
203 };
204}
205
206#endif
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Apr 6, 22:49, 2025)