116 using ctype =
typename RandomAccessContainer::value_type::value_type;
117 using Point = Dune::FieldVector<ctype, dimWorld>;
118 using Triangle = std::array<Point, 3>;
120 static_assert(std::is_same_v<typename RandomAccessContainer::value_type, Point>,
121 "Triangulation expects Dune::FieldVector as point type");
123 if (convexHullPoints.size() < 3)
124 DUNE_THROW(Dune::InvalidStateException,
"Try to triangulate point cloud with less than 3 points!");
126 if (convexHullPoints.size() == 3)
127 return std::vector<Triangle>(1, {convexHullPoints[0], convexHullPoints[1], convexHullPoints[2]});
130 for (
const auto& p : convexHullPoints)
132 midPoint /= convexHullPoints.size();
134 std::vector<Triangle> triangulation;
135 triangulation.reserve(convexHullPoints.size());
137 for (std::size_t i = 0; i < convexHullPoints.size()-1; ++i)
138 triangulation.emplace_back(Triangle{midPoint, convexHullPoints[i], convexHullPoints[i+1]});
140 triangulation.emplace_back(Triangle{midPoint, convexHullPoints[convexHullPoints.size()-1], convexHullPoints[0]});
142 return triangulation;
185 using ctype =
typename RandomAccessContainer::value_type::value_type;
186 using Point = Dune::FieldVector<ctype, dimWorld>;
187 using Tetrahedron = std::array<Point, 4>;
189 static_assert(std::is_same_v<typename RandomAccessContainer::value_type, Point>,
190 "Triangulation expects Dune::FieldVector as point type");
192 const auto numPoints = points.size();
194 DUNE_THROW(Dune::InvalidStateException,
"Trying to create 3D triangulation of point cloud with less than 4 points!");
197 return std::vector<Tetrahedron>(1, {points[0], points[1], points[2], points[3]});
202 Point lowerLeft(1e100);
203 Point upperRight(-1e100);
204 for (
const auto& p : points)
207 for (
int i = 0; i < dimWorld; ++i)
209 using std::max;
using std::min;
210 lowerLeft[i] = min(p[i], lowerLeft[i]);
211 upperRight[i] = max(p[i], upperRight[i]);
214 midPoint /= numPoints;
216 auto magnitude = 0.0;
218 for (
int i = 0; i < dimWorld; ++i)
219 magnitude = max(upperRight[i] - lowerLeft[i], magnitude);
220 const auto eps = 1e-7*magnitude;
221 const auto eps2 = eps*eps;
222 const auto epsDist = 1e-8*magnitude;
225 std::vector<Tetrahedron> triangulation;
226 triangulation.reserve(numPoints);
229 std::vector<Point> coplanarPointBuffer;
230 coplanarPointBuffer.reserve(std::min<std::size_t>(12, numPoints-1));
235 std::vector<std::pair<Point, ctype>> coplanarClusters;
236 coplanarClusters.reserve(numPoints/3);
242 for (
int i = 0; i < numPoints; ++i)
244 for (
int j = i+1; j < numPoints; ++j)
246 for (
int k = j+1; k < numPoints; ++k)
248 const auto pointI = points[i];
249 const auto ab = points[j] - pointI;
250 const auto ac = points[k] - pointI;
254 coplanarPointBuffer.clear();
258 const bool isAdmissible = [&]()
262 if (
normal.two_norm2() < eps2*eps2)
266 for (
int m = 0; m < numPoints; ++m)
268 if (m != i && m != j && m != k)
271 const auto ad = points[m] - pointI;
272 const auto sp =
normal*ad;
276 using std::abs;
using std::signbit;
277 const bool coplanar = abs(sp) < epsDist*
normal.two_norm();
278 int newMarker = coplanar ? 0 : signbit(sp) ? -1 : 1;
282 if (marker == 0 && newMarker != 0)
287 if (newMarker != 0 && marker != newMarker)
292 coplanarPointBuffer.push_back(points[m]);
298 if (!coplanarPointBuffer.empty())
308 coplanarClusters.begin(), coplanarClusters.end(),
309 [&](
const auto& c){ return unitNormal*c.first > 1.0 - 1e-6 && abs(offset - c.second) < epsDist; }
310 ) != coplanarClusters.end())
313 coplanarPointBuffer.clear();
317 coplanarPointBuffer.insert(coplanarPointBuffer.end(), { points[i], points[j], points[k] });
318 coplanarClusters.emplace_back(std::make_pair(
unitNormal, offset));
332 if (!coplanarPointBuffer.empty())
335 for (
const auto& triangle : triangles)
337 const auto ab = triangle[1] - triangle[0];
338 const auto ac = triangle[2] - triangle[0];
340 const auto am = midPoint - triangle[0];
341 const auto sp =
normal*am;
343 const bool isBelow = signbit(sp);
345 triangulation.emplace_back(Tetrahedron{
346 triangle[0], triangle[2], triangle[1], midPoint
349 triangulation.emplace_back(Tetrahedron{
350 triangle[0], triangle[1], triangle[2], midPoint
356 const auto am = midPoint - pointI;
357 const auto sp =
normal*am;
359 const bool isBelow = signbit(sp);
361 triangulation.emplace_back(Tetrahedron{
362 pointI, points[k], points[j], midPoint
365 triangulation.emplace_back(Tetrahedron{
366 pointI, points[j], points[k], midPoint
375 if (triangulation.size() < 4)
376 DUNE_THROW(Dune::InvalidStateException,
"Something went wrong with the triangulation!");
378 return triangulation;