128 using ctype =
typename RandomAccessContainer::value_type::value_type;
129 using Point = Dune::FieldVector<ctype, dimWorld>;
130 using Triangle = std::array<Point, 3>;
132 static_assert(std::is_same_v<typename RandomAccessContainer::value_type, Point>,
133 "Triangulation expects Dune::FieldVector as point type");
135 if (convexHullPoints.size() < 3)
136 DUNE_THROW(Dune::InvalidStateException,
"Try to triangulate point cloud with less than 3 points!");
138 if (convexHullPoints.size() == 3)
139 return std::vector<Triangle>(1, {convexHullPoints[0], convexHullPoints[1], convexHullPoints[2]});
142 for (
const auto& p : convexHullPoints)
144 midPoint /= convexHullPoints.size();
146 std::vector<Triangle> triangulation;
147 triangulation.reserve(convexHullPoints.size());
149 for (std::size_t i = 0; i < convexHullPoints.size()-1; ++i)
150 triangulation.emplace_back(Triangle{midPoint, convexHullPoints[i], convexHullPoints[i+1]});
152 triangulation.emplace_back(Triangle{midPoint, convexHullPoints[convexHullPoints.size()-1], convexHullPoints[0]});
154 return triangulation;
197 using ctype =
typename RandomAccessContainer::value_type::value_type;
198 using Point = Dune::FieldVector<ctype, dimWorld>;
199 using Tetrahedron = std::array<Point, 4>;
201 static_assert(std::is_same_v<typename RandomAccessContainer::value_type, Point>,
202 "Triangulation expects Dune::FieldVector as point type");
204 const auto numPoints = points.size();
206 DUNE_THROW(Dune::InvalidStateException,
"Trying to create 3D triangulation of point cloud with less than 4 points!");
209 return std::vector<Tetrahedron>(1, {points[0], points[1], points[2], points[3]});
214 Point lowerLeft(1e100);
215 Point upperRight(-1e100);
216 for (
const auto& p : points)
219 for (
int i = 0; i < dimWorld; ++i)
221 using std::max;
using std::min;
222 lowerLeft[i] = min(p[i], lowerLeft[i]);
223 upperRight[i] = max(p[i], upperRight[i]);
226 midPoint /= numPoints;
228 auto magnitude = 0.0;
230 for (
int i = 0; i < dimWorld; ++i)
231 magnitude = max(upperRight[i] - lowerLeft[i], magnitude);
232 const auto eps = 1e-7*magnitude;
233 const auto eps2 = eps*magnitude;
236 std::vector<Tetrahedron> triangulation;
237 triangulation.reserve(numPoints);
240 std::vector<Point> coplanarPointBuffer;
241 coplanarPointBuffer.reserve(std::min<std::size_t>(12, numPoints-1));
246 std::vector<std::pair<int, Point>> coplanarClusters;
247 coplanarClusters.reserve(numPoints/3);
253 for (
int i = 0; i < numPoints; ++i)
255 for (
int j = i+1; j < numPoints; ++j)
257 for (
int k = j+1; k < numPoints; ++k)
259 const auto pointI = points[i];
260 const auto ab = points[j] - pointI;
261 const auto ac = points[k] - pointI;
265 coplanarPointBuffer.clear();
269 const bool isAdmissible = [&]()
273 if (
normal.two_norm2() < eps2*eps2)
277 for (
int m = 0; m < numPoints; ++m)
279 if (m != i && m != j && m != k)
282 const auto ad = points[m] - pointI;
283 const auto sp =
normal*ad;
286 using std::abs;
using std::signbit;
287 const bool coplanar = abs(sp) < eps2*magnitude;
288 int newMarker = coplanar ? 0 : signbit(sp) ? -1 : 1;
292 if (marker == 0 && newMarker != 0)
297 if (newMarker != 0 && marker != newMarker)
304 if (m < k && std::find_if(
305 coplanarClusters.begin(), coplanarClusters.end(),
306 [=](
const auto& c){ return c.first == std::min(m, i) && abs(ab*c.second) < eps2*magnitude; }
307 ) != coplanarClusters.end())
310 coplanarPointBuffer.clear();
314 coplanarPointBuffer.push_back(points[m]);
321 if (!coplanarPointBuffer.empty())
323 coplanarPointBuffer.insert(coplanarPointBuffer.end(), { points[i], points[j], points[k] });
324 coplanarClusters.emplace_back(std::make_pair(i,
normal));
338 if (!coplanarPointBuffer.empty())
341 for (
const auto& triangle : triangles)
343 const auto ab = triangle[1] - triangle[0];
344 const auto ac = triangle[2] - triangle[0];
346 const auto am = midPoint - triangle[0];
347 const auto sp =
normal*am;
349 const bool isBelow = signbit(sp);
351 triangulation.emplace_back(Tetrahedron{
352 triangle[0], triangle[2], triangle[1], midPoint
355 triangulation.emplace_back(Tetrahedron{
356 triangle[0], triangle[1], triangle[2], midPoint
362 const auto am = midPoint - pointI;
363 const auto sp =
normal*am;
365 const bool isBelow = signbit(sp);
367 triangulation.emplace_back(Tetrahedron{
368 pointI, points[k], points[j], midPoint
371 triangulation.emplace_back(Tetrahedron{
372 pointI, points[j], points[k], midPoint
381 if (triangulation.size() < 4)
382 DUNE_THROW(Dune::InvalidStateException,
"Something went wrong with the triangulation!");
384 return triangulation;