26 typedef hrleVectorType<unsigned,
D - 1> EdgeType;
28 SmartPointer<Mesh<T>> mesh =
nullptr;
29 SmartPointer<PointCloud<T, D>> pointCloud =
nullptr;
30 std::vector<EdgeType> visitedEdges;
31 std::vector<hrleVectorType<unsigned, D>> hullElements;
32 std::list<EdgeType> remainingEdges;
37 unsigned pivotEdge(EdgeType currentEdge)
const {
38 auto &points = pointCloud->points;
39 unsigned nextIndex = 0;
42 while (nextIndex == currentEdge[0] ||
43 (
D == 3 && nextIndex == currentEdge[1])) {
47 for (
unsigned i = 0; i < points.size(); ++i) {
48 if (i == currentEdge[0] || i == nextIndex)
50 if (
D == 3 && i == currentEdge[1])
54 hrleVectorType<T, D> normal;
55 hrleVectorType<T, D> distance = points[i] - points[currentEdge[0]];
57 if constexpr (
D == 2) {
59 normal = points[nextIndex] - points[currentEdge[0]];
61 std::swap(normal[0], normal[1]);
62 normal[0] = -normal[0];
64 }
else if constexpr (
D == 3) {
65 auto v1 = points[currentEdge[1]] - points[currentEdge[0]];
66 auto v2 = points[nextIndex] - points[currentEdge[0]];
67 normal = calculateNormal(v1, v2);
70 auto product = DotProduct(distance, normal);
74 if (std::abs(product) < 1e-9) {
77 hrleVectorType<unsigned, D> triangle;
78 triangle[0] = currentEdge[0];
79 triangle[1] = currentEdge[1];
81 if (doesTriangleClip(triangle)) {
86 edges[0][0] = currentEdge[0];
88 edges[1][0] = currentEdge[1];
91 if (!wasEdgeVisited(edges[0]) && !wasEdgeVisited(edges[1])) {
96 else if (product > 0) {
104 bool wasEdgeVisited(
const EdgeType &edge)
const {
105 for (
unsigned i = 0; i < visitedEdges.size(); ++i) {
107 if (edge[0] == visitedEdges[i][0]) {
108 if constexpr (
D == 3) {
109 if (edge[1] == visitedEdges[i][1]) {
118 if constexpr (
D == 3) {
119 if (edge[0] == visitedEdges[i][1] && edge[1] == visitedEdges[i][0]) {
128 typename std::list<EdgeType>::iterator findEdge(EdgeType edge) {
129 for (
typename std::list<EdgeType>::iterator it = remainingEdges.begin();
130 it != remainingEdges.end(); ++it) {
131 bool containsElem[2] = {
false,
false};
132 for (
unsigned i = 0; i <
D - 1; ++i) {
134 for (
unsigned k = 0; k <
D - 1; ++k) {
135 if ((*it)[i] == edge[k]) {
136 containsElem[i] =
true;
140 if (containsElem[0] && containsElem[1]) {
144 return remainingEdges.end();
148 bool intersectSharedNode(
const hrleVectorType<unsigned, D> &triangle1,
149 const hrleVectorType<unsigned, D> &triangle2)
const {
151 std::vector<unsigned> sharedNodes;
153 std::vector<unsigned> otherNodes;
155 for (
unsigned i = 0; i <
D; ++i) {
156 unsigned shared = sharedNodes.size();
157 for (
unsigned j = 0; j <
D; ++j) {
158 if (triangle1[i] == triangle2[j]) {
160 sharedNodes.push_back(j);
164 if (shared == sharedNodes.size()) {
165 otherNodes.push_back(i);
169 assert(sharedNodes.size() > 0);
171 auto &points = pointCloud->points;
179 for (
unsigned i = 0; i < sharedNodes.size(); ++i) {
180 hrleVectorType<T, D> averageVector;
182 double centerEdgeDot;
184 auto shared = sharedNodes[i];
185 hrleVectorType<T, D> edge1 = Normalize(
186 points[triangle2[(shared + 1) %
D]] - points[triangle2[shared]]);
187 hrleVectorType<T, D> edge2 = Normalize(
188 points[triangle2[(shared + 2) %
D]] - points[triangle2[shared]]);
189 averageVector = Normalize((edge1 + edge2) / 2);
190 centerEdgeDot = DotProduct(averageVector, edge2);
194 for (
unsigned j = 0; j < otherNodes.size(); ++j) {
195 hrleVectorType<T, D> vector =
196 Normalize(points[triangle1[otherNodes[j]]] -
197 points[triangle2[sharedNodes[i]]]);
199 if (DotProduct(vector, averageVector) > centerEdgeDot + 1e-9) {
209 bool doesTriangleClip(
const hrleVectorType<unsigned, D> &triangle)
const {
210 auto &points = pointCloud->points;
212 auto triangleNormal =
213 Normalize(calculateNormal(points[triangle[1]] - points[triangle[0]],
214 points[triangle[2]] - points[triangle[0]]));
217 for (
unsigned i = 0; i < hullElements.size(); ++i) {
218 unsigned inOneTriangle = 0;
219 for (
unsigned j = 0; j <
D; ++j) {
221 for (
unsigned k = 0; k <
D; ++k) {
222 if (hullElements[i][j] == triangle[k]) {
229 if (inOneTriangle > 0) {
231 auto normal2 = Normalize(calculateNormal(
232 points[hullElements[i][1]] - points[hullElements[i][0]],
233 points[hullElements[i][2]] - points[hullElements[i][0]]));
236 for (
unsigned d = 0; d <
D; ++d) {
238 std::abs(std::abs(triangleNormal[d]) - std::abs(normal2[d]));
246 if (intersectSharedNode(triangle, hullElements[i]))
248 if (intersectSharedNode(hullElements[i], triangle))
256 hrleVectorType<T, D> calculateNormal(
const hrleVectorType<T, D> &v1,
257 const hrleVectorType<T, D> &v2)
const {
258 hrleVectorType<T, D> newNormal;
259 newNormal[0] = v1[1] * v2[2] - v1[2] * v2[1];
260 newNormal[1] = v1[2] * v2[0] - v1[0] * v2[2];
261 newNormal[2] = v1[0] * v2[1] - v1[1] * v2[0];
266 T calculateArea(
const hrleVectorType<T, D> &v1,
267 const hrleVectorType<T, D> &v2)
const {
268 hrleVectorType<T, D> newNormal = calculateNormal(v1, v2);
269 return std::sqrt(DotProduct(newNormal, newNormal));
277 : mesh(passedMesh), pointCloud(passedPointCloud) {}
282 pointCloud = passedPointCloud;
286 if (mesh ==
nullptr) {
287 Logger::getInstance()
288 .addWarning(
"No mesh was passed to ConvexHull.")
292 if (pointCloud ==
nullptr) {
293 Logger::getInstance()
294 .addWarning(
"No point cloud was passed to ConvexHull.")
300 auto &points = pointCloud->points;
301 if (points.size() == 0)
306 auto it = std::min_element(points.begin(), points.end());
307 unsigned currentIndex = std::distance(points.begin(), it);
310 remainingEdges.push_back(EdgeType(currentIndex));
313 int currentPointIndex = -1;
314 double hullMetric = std::numeric_limits<double>::max();
315 for (
unsigned i = 0; i < points.size(); ++i) {
316 if (i == currentIndex)
318 if (std::abs(points[i][2] - points[currentIndex][2]) < 1e-7) {
319 auto diff = points[currentIndex] - points[i];
321 double currentHullMetric = DotProduct(diff, diff);
322 if (currentHullMetric < hullMetric) {
323 hullMetric = currentHullMetric;
324 currentPointIndex = i;
330 edge[0] = currentIndex;
332 if (currentPointIndex == -1) {
333 hrleVectorType<T, D> newPoint;
334 newPoint = points[currentIndex];
337 points.push_back(newPoint);
338 edge[1] = points.size() - 1;
339 edge[1] = pivotEdge(edge);
342 edge[1] = currentPointIndex;
345 remainingEdges.push_back(edge);
350 while (remainingEdges.size() != 0) {
352 EdgeType currentEdge = remainingEdges.back();
353 remainingEdges.pop_back();
355 if (wasEdgeVisited(currentEdge))
359 unsigned nextIndex = pivotEdge(currentEdge);
362 hrleVectorType<unsigned, D> element;
363 for (
unsigned i = 0; i <
D - 1; ++i) {
364 element[i] = currentEdge[i];
366 element[
D - 1] = nextIndex;
367 hullElements.push_back(element);
370 visitedEdges.push_back(currentEdge);
372 remainingEdges.push_back(EdgeType(nextIndex));
376 edge[1] = currentEdge[1];
380 auto it = findEdge(edge);
381 if (it != remainingEdges.end()) {
382 remainingEdges.erase(it);
384 remainingEdges.push_back(edge);
387 edge[0] = currentEdge[0];
390 if (it != remainingEdges.end()) {
391 remainingEdges.erase(it);
393 remainingEdges.push_back(edge);
399 auto &elements = mesh->template getElements<D>();
400 std::unordered_map<unsigned, unsigned> oldToNewNodes;
401 for (
unsigned i = 0; i < hullElements.size(); ++i) {
403 std::array<unsigned, D> newElement;
404 for (
unsigned j = 0; j <
D; ++j) {
405 auto insertion = oldToNewNodes.insert(
406 std::make_pair(hullElements[i][j], oldToNewNodes.size()));
409 if (insertion.second) {
410 Vec3D<T> node{points[hullElements[i][j]][0],
411 points[hullElements[i][j]][1],
412 (
D == 2) ?
T(0.) : points[hullElements[i][j]][2]};
413 mesh->nodes.push_back(node);
416 newElement[j] = insertion.first->second;
419 elements.push_back(newElement);