ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ManualSegmentationTools.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 // local
11 #include <CVPointCloud.h>
13 #include <Polyline.h>
14 #include <SimpleMesh.h>
15 
16 // system
17 #include <cstdint>
18 #include <map>
19 
20 using namespace cloudViewer;
21 
24  const Polyline* poly,
25  bool keepInside,
26  const float* viewMat) {
27  assert(poly && aCloud);
28 
30  (viewMat ? new cloudViewer::SquareMatrix(viewMat) : nullptr);
31 
32  ReferenceCloud* Y = new ReferenceCloud(aCloud);
33 
34  // we check for each point if it falls inside the polyline
35  unsigned count = aCloud->size();
36  for (unsigned i = 0; i < count; ++i) {
37  CCVector3 P;
38  aCloud->getPoint(i, P);
39 
40  // we project the point in screen space first if necessary
41  if (trans) {
42  P = (*trans) * P;
43  }
44 
45  bool pointInside = isPointInsidePoly(CCVector2(P.x, P.y), poly);
46  if ((keepInside && pointInside) || (!keepInside && !pointInside)) {
47  if (!Y->addPointIndex(i)) {
48  // not engouh memory
49  delete Y;
50  Y = nullptr;
51  break;
52  }
53  }
54  }
55 
56  delete trans;
57 
58  return Y;
59 }
60 
62  const CCVector2& P, const GenericIndexedCloud* polyVertices) {
63  // number of vertices
64  unsigned vertCount = (polyVertices ? polyVertices->size() : 0);
65  if (vertCount < 2) return false;
66 
67  bool inside = false;
68 
69  CCVector3 A;
70  polyVertices->getPoint(0, A);
71  for (unsigned i = 1; i <= vertCount; ++i) {
72  CCVector3 B;
73  polyVertices->getPoint(i % vertCount, B);
74 
75  // Point Inclusion in Polygon Test (inspired from W. Randolph Franklin -
76  // WRF) The polyline is considered as a 2D polyline here!
77  if ((B.y <= P.y && P.y < A.y) || (A.y <= P.y && P.y < B.y)) {
79  (P.x - B.x) * (A.y - B.y) - (A.x - B.x) * (P.y - B.y);
80  if (A.y < B.y) t = -t;
81  if (t < 0) inside = !inside;
82  }
83 
84  A = B;
85  }
86 
87  return inside;
88 }
89 
91  const CCVector2& P, const std::vector<CCVector2>& polyVertices) {
92  // number of vertices
93  std::size_t vertCount = polyVertices.size();
94  if (vertCount < 2) return false;
95 
96  bool inside = false;
97 
98  for (unsigned i = 1; i <= vertCount; ++i) {
99  const CCVector2& A = polyVertices[i - 1];
100  const CCVector2& B = polyVertices[i % vertCount];
101 
102  // Point Inclusion in Polygon Test (inspired from W. Randolph Franklin -
103  // WRF) The polyline is considered as a 2D polyline here!
104  if ((B.y <= P.y && P.y < A.y) || (A.y <= P.y && P.y < B.y)) {
106  (P.x - B.x) * (A.y - B.y) - (A.x - B.x) * (P.y - B.y);
107  if (A.y < B.y) t = -t;
108  if (t < 0) inside = !inside;
109  }
110  }
111 
112  return inside;
113 }
114 
117  ScalarType minDist,
118  ScalarType maxDist,
119  bool outside /*=false*/) {
120  if (!cloud) {
121  assert(false);
122  return nullptr;
123  }
124 
125  ReferenceCloud* Y = new ReferenceCloud(cloud);
126 
127  // for each point
128  for (unsigned i = 0; i < cloud->size(); ++i) {
129  const ScalarType dist = cloud->getPointScalarValue(i);
130  // we test if its associated scalar value falls inside the specified
131  // interval
132  if ((dist >= minDist && dist <= maxDist) ^ outside) {
133  if (!Y->addPointIndex(i)) {
134  // not engouh memory
135  delete Y;
136  Y = nullptr;
137  break;
138  }
139  }
140  }
141 
142  return Y;
143 }
144 
147  std::vector<ScalarType> values,
148  bool outside /*=false*/) {
149  if (!cloud) {
150  assert(false);
151  return nullptr;
152  }
153 
154  ReferenceCloud* Y = new ReferenceCloud(cloud);
155 
156  // for each point
157  for (unsigned i = 0; i < cloud->size(); ++i) {
158  const ScalarType dist = cloud->getPointScalarValue(i);
159  bool find_flag = false;
160  for (auto label : values) {
161  if (std::abs(label - dist) < EPSILON_VALUE) {
162  find_flag = true;
163  break;
164  }
165  }
166 
167  // we test if its associated scalar value falls inside the specified
168  // interval
169  if (find_flag ^ outside) {
170  if (!Y->addPointIndex(i)) {
171  // not engouh memory
172  delete Y;
173  Y = nullptr;
174  break;
175  }
176  }
177  }
178 
179  return Y;
180 }
181 
183  GenericIndexedMesh* mesh,
184  ReferenceCloud* selectedVertexIndexes,
185  bool useSelectedVertices,
186  GenericProgressCallback* progressCb /*=nullptr*/,
187  GenericIndexedCloud* destCloud /*=nullptr*/,
188  unsigned indexShift /*=0*/,
189  std::vector<int>* triangleIndexMap /*=nullptr*/) {
190  if (!mesh || !selectedVertexIndexes ||
191  !selectedVertexIndexes->getAssociatedCloud())
192  return nullptr;
193 
194  // by default we try a fast process (but with a higher memory consumption)
195  unsigned totalNumberOfVertices =
196  selectedVertexIndexes->getAssociatedCloud()->size();
197  unsigned numberOfSelectedVertices = selectedVertexIndexes->size();
198 
199  // we determine for each point if it is used in the output mesh or not
200  //(and we compute its new index by the way: 0 means that the point is not
201  // used, otherwise its index will be newPointIndexes-1)
202  std::vector<int> newPointIndexes;
203  {
204  try {
205  newPointIndexes.resize(
206  totalNumberOfVertices,
207  -1); // an index < 0 means that the point is discarded
208  } catch (const std::bad_alloc&) {
209  return nullptr; // not enough memory
210  }
211 
212  for (unsigned i = 0; i < numberOfSelectedVertices; ++i) {
213  unsigned vertexIndex =
214  selectedVertexIndexes->getPointGlobalIndex(i);
215  assert(vertexIndex < totalNumberOfVertices);
216  newPointIndexes[vertexIndex] = static_cast<int>(i);
217  }
218 
219  // negative array for the case where selected vertices are "outside"
220  if (!useSelectedVertices) {
221  int newIndex = 0;
222  for (unsigned i = 0; i < totalNumberOfVertices; ++i)
223  newPointIndexes[i] = (newPointIndexes[i] < 0 ? newIndex++ : -1);
224  }
225  }
226 
227  // create resulting mesh
228  SimpleMesh* newMesh = nullptr;
229  {
230  unsigned numberOfTriangles = mesh->size();
231 
232  if (triangleIndexMap) {
233  try {
234  triangleIndexMap->resize(numberOfTriangles);
235  } catch (const std::bad_alloc&) {
236  return nullptr; // not enough memory
237  }
238  }
239 
240  // progress notification
241  NormalizedProgress nprogress(progressCb, numberOfTriangles);
242  if (progressCb) {
243  if (progressCb->textCanBeEdited()) {
244  progressCb->setMethodTitle("Extract mesh");
245  char buffer[64];
246  snprintf(buffer, 64, "New vertex number: %u",
247  numberOfSelectedVertices);
248  progressCb->setInfo(buffer);
249  }
250  progressCb->update(0);
251  progressCb->start();
252  }
253 
254  newMesh = new SimpleMesh(
255  destCloud ? destCloud
256  : selectedVertexIndexes->getAssociatedCloud());
257  unsigned newTriangleCount = 0;
258 
259  mesh->placeIteratorAtBeginning();
260  for (unsigned i = 0; i < numberOfTriangles; ++i) {
261  const VerticesIndexes* tsi =
262  mesh->getNextTriangleVertIndexes(); // DGM:
263  // getNextTriangleVertIndexes
264  // is faster for mesh
265  // groups!
266 
267  // WE ONLY KEEP A TRIANGLE IF ITS 3 VERTICES ARE 'SELECTED'
268  bool keepTriangle = true;
269  int newVertexIndexes[3];
270  for (unsigned char j = 0; j < 3; ++j) {
271  int vertexIndex = tsi->i[j];
272  assert(vertexIndex >= 0 && static_cast<unsigned>(vertexIndex) <
273  totalNumberOfVertices);
274  newVertexIndexes[j] = newPointIndexes[vertexIndex];
275 
276  // if any vertex is rejected, we discard this triangle
277  if (newVertexIndexes[j] < 0) {
278  keepTriangle = false;
279  break;
280  }
281  }
282 
283  // if we keep the triangle
284  if (keepTriangle) {
285  if (newTriangleCount == newMesh->capacity() &&
286  !newMesh->reserve(newMesh->size() +
287  4096)) // auto expand mesh size
288  {
289  // stop process
290  delete newMesh;
291  newMesh = nullptr;
292  break;
293  }
294 
295  newMesh->addTriangle(indexShift + newVertexIndexes[0],
296  indexShift + newVertexIndexes[1],
297  indexShift + newVertexIndexes[2]);
298 
299  if (triangleIndexMap) {
300  triangleIndexMap->at(i) =
301  static_cast<int>(newTriangleCount);
302  }
303  ++newTriangleCount;
304  } else if (triangleIndexMap) {
305  triangleIndexMap->at(i) = -1;
306  }
307 
308  if (progressCb && !nprogress.oneStep()) {
309  // cancel process
310  break;
311  }
312  }
313 
314  // we don't need it anymore
315  newPointIndexes.clear();
316 
317  if (newMesh) {
318  if (newMesh->size() == 0) {
319  delete newMesh;
320  newMesh = nullptr;
321  } else if (newTriangleCount < newMesh->size()) {
322  newMesh->resize(newTriangleCount); // should always be ok as
323  // newTriangleCount <
324  // newMesh->size()
325  }
326  }
327  }
328 
329  return newMesh;
330 }
331 
332 const unsigned c_origIndexFlag = 0x80000000; // original index flag (bit 31)
333 const unsigned c_srcIndexFlag = 0x40000000; // source index flag (bit 30)
334 const unsigned c_realIndexMask =
335  0x3FFFFFFF; // original index mask (bit 0 to 29) --> max allowed index
336  // = 1073741823 ;)
337 const unsigned c_defaultArrayGrowth = 1024;
338 
340  InsideOutsideIndexes() : insideIndex(0), outsideIndex(0) {}
341  InsideOutsideIndexes(unsigned inside, unsigned outside)
342  : insideIndex(inside), outsideIndex(outside) {}
343  unsigned insideIndex;
344  unsigned outsideIndex;
345 };
346 static std::map<uint64_t, InsideOutsideIndexes> s_edgePoint;
347 
348 bool AddVertex(CCVector3d& P, PointCloud* vertices, unsigned& index) {
349  assert(vertices);
350  // add vertex to the 'vertices' set
351  unsigned vertCount = vertices->size();
352  if (vertCount == vertices->capacity() &&
353  !vertices->reserve(vertCount + c_defaultArrayGrowth)) {
354  // not enough memory!
355  return false;
356  }
357  vertices->addPoint(CCVector3::fromArray(P.u));
358  index = vertCount;
359  return true;
360 }
361 
363  unsigned iA,
364  const CCVector3d& B,
365  unsigned iB,
366  unsigned& iCoutside,
367  unsigned& iCinside,
368  double planeCoord,
369  unsigned char planeDim,
370  PointCloud* outsideVertices,
371  PointCloud* insideVertices) {
372  assert(outsideVertices || insideVertices);
373 
374  // first look if we already know this edge
375  uint64_t key = 0;
376  {
377  unsigned minIndex = iA;
378  unsigned maxIndex = iB;
379  if (minIndex > maxIndex) std::swap(minIndex, maxIndex);
380  key = (static_cast<uint64_t>(minIndex) << 32) |
381  static_cast<uint64_t>(maxIndex);
382  }
383 
384  // if the key (edge) already exists
385  if (s_edgePoint.find(key) != s_edgePoint.end()) {
386  const InsideOutsideIndexes& pmi = s_edgePoint[key];
387  iCoutside = pmi.outsideIndex;
388  iCinside = pmi.insideIndex;
389  }
390  // otherwise we'll create it
391  else {
392  CCVector3d I = A + (B - A) * (planeCoord - A.u[planeDim]) /
393  (B.u[planeDim] - A.u[planeDim]);
394 
395  // add vertex to the inside 'vertices' set
396  iCinside = 0;
397  if (insideVertices && !AddVertex(I, insideVertices, iCinside))
398  return false;
399  // add vertex to the outside 'vertices' set
400  iCoutside = 0;
401  if (outsideVertices && !AddVertex(I, outsideVertices, iCoutside))
402  return false;
403 
404  s_edgePoint[key] = InsideOutsideIndexes(iCinside, iCoutside);
405  }
406 
407  return true;
408 }
409 
410 bool AddTriangle(unsigned iA,
411  unsigned iB,
412  unsigned iC,
413  SimpleMesh* mesh,
414  bool directOrder) {
415  // special case: the mesh might not exist (if we skip the 'outside' mesh
416  // creation) so we accept this eventuallity to simply the code
417  if (!mesh) return true;
418 
419  // now add the triangle
420  if (mesh->size() == mesh->capacity() &&
422  !mesh->reserve(mesh->size() + c_defaultArrayGrowth))) {
423  // not enough memory (or too many triangles!)
424  return false;
425  }
426 
427  if (directOrder)
428  mesh->addTriangle(iA, iB, iC);
429  else
430  mesh->addTriangle(iA, iC, iB);
431 
432  return true;
433 }
434 
436  GenericIndexedCloudPersist* origVertices,
437  SimpleMesh* newMesh,
438  PointCloud* newVertices,
439  const std::vector<unsigned>& preservedTriangleIndexes,
440  std::vector<unsigned>* origTriIndexesMap = nullptr) {
441  assert(origMesh && origVertices && newMesh && newVertices);
442 
443  unsigned importedTriCount =
444  static_cast<unsigned>(preservedTriangleIndexes.size());
445  unsigned origVertCount = origVertices->size();
446  unsigned newVertCount = newVertices->size();
447  unsigned newTriCount = newMesh->size();
448 
449  try {
450  // first determine the number of original vertices that should be
451  // imported
452  std::vector<unsigned> newIndexMap;
453  newIndexMap.resize(origVertCount, 0);
454 
455  // either for the preserved triangles
456  {
457  for (unsigned i = 0; i < importedTriCount; ++i) {
458  unsigned triIndex = preservedTriangleIndexes[i];
459  const VerticesIndexes* tsi =
460  origMesh->getTriangleVertIndexes(triIndex);
461  newIndexMap[tsi->i1] = 1;
462  newIndexMap[tsi->i2] = 1;
463  newIndexMap[tsi->i3] = 1;
464  }
465  }
466 
467  // or by the new triangles
468  {
469  for (unsigned i = 0; i < newTriCount; ++i) {
470  const VerticesIndexes* tsi = newMesh->getTriangleVertIndexes(i);
471  if (tsi->i1 & c_origIndexFlag)
472  newIndexMap[tsi->i1 & c_realIndexMask] = 1;
473  if (tsi->i2 & c_origIndexFlag)
474  newIndexMap[tsi->i2 & c_realIndexMask] = 1;
475  if (tsi->i3 & c_origIndexFlag)
476  newIndexMap[tsi->i3 & c_realIndexMask] = 1;
477  }
478  }
479 
480  // count the number of used vertices
481  unsigned importedVertCount = 0;
482  {
483  for (unsigned i = 0; i < origVertCount; ++i)
484  if (newIndexMap[i]) ++importedVertCount;
485  }
486 
487  if (importedVertCount == 0) {
488  // nothing to do
489  //(shouldn't happen but who knows?)
490  return true;
491  }
492 
493  // reserve the memory to import the original vertices
494  if (!newVertices->reserve(newVertices->size() + importedVertCount)) {
495  // not enough memory
496  return false;
497  }
498  // then copy them
499  {
500  // update the destination indexes by the way
501  unsigned lastVertIndex = newVertCount;
502  for (unsigned i = 0; i < origVertCount; ++i) {
503  if (newIndexMap[i]) {
504  newVertices->addPoint(*origVertices->getPoint(i));
505  newIndexMap[i] = lastVertIndex++;
506  }
507  }
508  }
509 
510  // update the existing indexes
511  {
512  for (unsigned i = 0; i < newTriCount; ++i) {
513  VerticesIndexes* tsi = newMesh->getTriangleVertIndexes(i);
514  if (tsi->i1 & c_origIndexFlag)
515  tsi->i1 = newIndexMap[tsi->i1 & c_realIndexMask];
516  if (tsi->i2 & c_origIndexFlag)
517  tsi->i2 = newIndexMap[tsi->i2 & c_realIndexMask];
518  if (tsi->i3 & c_origIndexFlag)
519  tsi->i3 = newIndexMap[tsi->i3 & c_realIndexMask];
520  }
521  }
522 
523  if (importedTriCount) {
524  // reserve the memory to import the original triangles
525  if (!newMesh->reserve(newMesh->size() + importedTriCount)) {
526  // not enough memory
527  return false;
528  }
529  // then copy them
530  {
531  assert(!origTriIndexesMap ||
532  newMesh->size() == origTriIndexesMap->size());
533  for (unsigned i = 0; i < importedTriCount; ++i) {
534  unsigned triIndex = preservedTriangleIndexes[i];
535  const VerticesIndexes* tsi =
536  origMesh->getTriangleVertIndexes(triIndex);
537  newMesh->addTriangle(newIndexMap[tsi->i1],
538  newIndexMap[tsi->i2],
539  newIndexMap[tsi->i3]);
540  if (origTriIndexesMap)
541  origTriIndexesMap->push_back(triIndex);
542  }
543  }
544  }
545  } catch (const std::bad_alloc&) {
546  // not enough memory
547  return false;
548  }
549 
550  newMesh->resize(newMesh->size());
551  newVertices->resize(newVertices->size());
552 
553  assert(!origTriIndexesMap || newMesh->size() == origTriIndexesMap->size());
554 
555  return true;
556 }
557 
559  SimpleMesh* newMesh,
560  PointCloud* newVertices) {
561  assert(srcVertices && newMesh && newVertices);
562 
563  unsigned srcVertCount = srcVertices->size();
564  unsigned newVertCount = newVertices->size();
565  unsigned newTriCount = newMesh->size();
566 
567  try {
568  // first determine the number of source vertices that should be imported
569  std::vector<unsigned> newIndexMap;
570  newIndexMap.resize(srcVertCount, 0);
571 
572  for (unsigned i = 0; i < newTriCount; ++i) {
573  const VerticesIndexes* tsi = newMesh->getTriangleVertIndexes(i);
574  if (tsi->i1 & c_srcIndexFlag)
575  newIndexMap[tsi->i1 & c_realIndexMask] = 1;
576  if (tsi->i2 & c_srcIndexFlag)
577  newIndexMap[tsi->i2 & c_realIndexMask] = 1;
578  if (tsi->i3 & c_srcIndexFlag)
579  newIndexMap[tsi->i3 & c_realIndexMask] = 1;
580  }
581 
582  // count the number of used vertices
583  unsigned importedVertCount = 0;
584  {
585  for (unsigned i = 0; i < srcVertCount; ++i)
586  if (newIndexMap[i]) ++importedVertCount;
587  }
588 
589  if (importedVertCount == 0) {
590  // nothing to do
591  //(shouldn't happen but who knows?)
592  return true;
593  }
594 
595  // reserve the memory to import the source vertices
596  if (!newVertices->reserve(newVertices->size() + importedVertCount)) {
597  // not enough memory
598  return false;
599  }
600  // then copy them
601  {
602  // update the destination indexes by the way
603  unsigned lastVertIndex = newVertCount;
604  for (unsigned i = 0; i < srcVertCount; ++i) {
605  if (newIndexMap[i]) {
606  newVertices->addPoint(*srcVertices->getPoint(i));
607  newIndexMap[i] = lastVertIndex++;
608  }
609  }
610  }
611 
612  // update the existing indexes
613  {
614  for (unsigned i = 0; i < newTriCount; ++i) {
615  VerticesIndexes* tsi = newMesh->getTriangleVertIndexes(i);
616  if (tsi->i1 & c_srcIndexFlag)
617  tsi->i1 = newIndexMap[tsi->i1 & c_realIndexMask];
618  if (tsi->i2 & c_srcIndexFlag)
619  tsi->i2 = newIndexMap[tsi->i2 & c_realIndexMask];
620  if (tsi->i3 & c_srcIndexFlag)
621  tsi->i3 = newIndexMap[tsi->i3 & c_realIndexMask];
622  }
623  }
624  } catch (const std::bad_alloc&) {
625  // not enough memory
626  return false;
627  }
628 
629  newVertices->resize(newVertices->size());
630 
631  return true;
632 }
633 
635  GenericIndexedMesh* mesh,
636  GenericIndexedCloudPersist* vertices,
637  MeshCutterParams& ioParams,
638  GenericProgressCallback* progressCb /*=0*/) {
639  if (!mesh || !vertices || mesh->size() == 0 || vertices->size() < 3 ||
640  ioParams.planeOrthoDim > 2) {
641  // invalid input parameters
642  return false;
643  }
644 
645  if (mesh->size() > c_realIndexMask) {
646  // too many triangles!
647  return false;
648  }
649 
650  // should be empty (just in case)
651  s_edgePoint.clear();
652 
653  // working dimensions
654  unsigned char Z = ioParams.planeOrthoDim;
655  // unsigned char X = (Z == 2 ? 0 : Z + 1);
656  // unsigned char Y = (X == 2 ? 0 : X + 1);
657 
658  const double& epsilon = ioParams.epsilon;
659  const double& planeZ = ioParams.planeCoord;
660 
661  // indexes of original triangle that are not modified bt copied "as is"
662  std::vector<unsigned> preservedTrianglesMinus;
663  std::vector<unsigned> preservedTrianglesPlus;
664 
665  PointCloud* insideVertices = new PointCloud;
666  SimpleMesh* minusMesh = new SimpleMesh(insideVertices, true);
667  PointCloud* outsideVertices = new PointCloud;
668  SimpleMesh* plusMesh = new SimpleMesh(outsideVertices, true);
669 
670  bool error = false;
671 
672  // for each triangle
673  try {
674  unsigned triCount = mesh->size();
675  for (unsigned i = 0; i < triCount; ++i) {
676  // original vertices indexes
677  const VerticesIndexes* tsi = mesh->getTriangleVertIndexes(i);
678  CCVector3d V[3] = {
679  CCVector3d::fromArray(vertices->getPoint(tsi->i1)->u),
680  CCVector3d::fromArray(vertices->getPoint(tsi->i2)->u),
681  CCVector3d::fromArray(vertices->getPoint(tsi->i3)->u)};
682 
683  const unsigned origVertIndexes[3] = {tsi->i1 | c_origIndexFlag,
684  tsi->i2 | c_origIndexFlag,
685  tsi->i3 | c_origIndexFlag};
686 
687  // test each vertex
688  // char relativePos[3] = { 1, 1, 1 };
689  std::vector<unsigned char> minusVertIndexes, plusVertIndexes;
690  for (unsigned char j = 0; j < 3; ++j) {
691  const CCVector3d& v = V[j];
692  if (std::abs(v.u[Z] - planeZ) < epsilon) {
693  // relativePos[j] = 0;
694  } else {
695  if (v.u[Z] < planeZ) {
696  minusVertIndexes.push_back(j);
697  // relativePos[j] = -1;
698  } else {
699  // relativePos is already equal to 1
700  // relativePos[j] = 1;
701  plusVertIndexes.push_back(j);
702  }
703  }
704  }
705 
706  // depending on the number of entities on the plane
707  // we'll process the triangles differently
708  switch (minusVertIndexes.size() + plusVertIndexes.size()) {
709  case 0: // all vertices 'in' the plane
710  {
711  // the triangle is inside the plane!
712  preservedTrianglesMinus.push_back(i);
713  } break;
714 
715  case 1: // 2 vertices 'in' the plane
716  {
717  // the triangle is either on one side or another ;)
718  // const std::vector<unsigned char>& nonEmptySet =
719  // (insideVertices.empty() ? outsideVertices :
720  // insideVertices); assert(nonEmptySet.size() != 0);
721  if (minusVertIndexes.empty()) {
722  // the only vertex far from the plane is on the 'plus'
723  // side
724  preservedTrianglesPlus.push_back(i);
725  } else {
726  // the only vertex far from the plane is on the 'minus'
727  // side
728  preservedTrianglesMinus.push_back(i);
729  }
730  } break;
731 
732  case 2: // 1 vertex 'in' the plane
733  {
734  // 3 cases:
735  if (minusVertIndexes.empty()) {
736  // the two vertices far from the plane are on the 'plus'
737  // side
738  preservedTrianglesPlus.push_back(i);
739  } else if (plusVertIndexes.empty()) {
740  // the two vertices far from the plane are on the
741  // 'minus' side
742  preservedTrianglesMinus.push_back(i);
743  } else {
744  // the two vertices far from the plane are on both sides
745  // the plane will cut through the edge connecting those
746  // two vertices
747  unsigned char iMinus = minusVertIndexes.front();
748  unsigned char iPlus = plusVertIndexes.front();
749 
750  unsigned iCoutside, iCinside;
751  if (!ComputeEdgePoint(
752  V[iMinus], origVertIndexes[iMinus],
753  V[iPlus], origVertIndexes[iPlus], iCoutside,
754  iCinside, planeZ, Z, outsideVertices,
755  insideVertices)) {
756  // early stop
757  i = triCount;
758  error = true;
759  break;
760  }
761 
762  // we can now create two triangles
763  unsigned char iCenter = 3 - iMinus - iPlus;
764  if (!AddTriangle(origVertIndexes[iCenter],
765  origVertIndexes[iMinus], iCinside,
766  minusMesh,
767  ((iCenter + 1) % 3) == iMinus)
768 
769  || !AddTriangle(origVertIndexes[iCenter],
770  origVertIndexes[iPlus], iCoutside,
771  plusMesh,
772  ((iCenter + 1) % 3) == iPlus)) {
773  // early stop
774  i = triCount;
775  error = true;
776  break;
777  }
778  }
779  } break;
780 
781  case 3: // no vertex 'in' the plane
782  {
783  if (minusVertIndexes.empty()) {
784  // all vertices are on the 'plus' side
785  preservedTrianglesPlus.push_back(i);
786  } else if (plusVertIndexes.empty()) {
787  // all vertices are on the 'minus' side
788  preservedTrianglesMinus.push_back(i);
789  } else {
790  // we have one vertex on one side and two on the other
791  // side
792  unsigned char iLeft, iRight1, iRight2;
793  bool leftIsMinus = true;
794  if (minusVertIndexes.size() == 1) {
795  assert(plusVertIndexes.size() == 2);
796  iLeft = minusVertIndexes.front();
797  iRight1 = plusVertIndexes[0];
798  iRight2 = plusVertIndexes[1];
799  leftIsMinus = true;
800  } else {
801  assert(minusVertIndexes.size() == 2);
802  iLeft = plusVertIndexes.front();
803  iRight1 = minusVertIndexes[0];
804  iRight2 = minusVertIndexes[1];
805  leftIsMinus = false;
806  }
807 
808  // the plane cuts through the two edges having the
809  // 'single' vertex in common
810  unsigned i1outside, i1inside;
811  unsigned i2outside, i2inside;
812  if (!ComputeEdgePoint(
813  V[iRight1], origVertIndexes[iRight1],
814  V[iLeft], origVertIndexes[iLeft], i1outside,
815  i1inside, planeZ, Z, outsideVertices,
816  insideVertices) ||
818  V[iRight2], origVertIndexes[iRight2],
819  V[iLeft], origVertIndexes[iLeft], i2outside,
820  i2inside, planeZ, Z, outsideVertices,
821  insideVertices)) {
822  // early stop
823  i = triCount;
824  error = true;
825  break;
826  }
827 
828  // we are going to create 3 triangles
829  if (!AddTriangle(origVertIndexes[iLeft],
830  leftIsMinus ? i1inside : i1outside,
831  leftIsMinus ? i2inside : i2outside,
832  leftIsMinus ? minusMesh : plusMesh,
833  ((iLeft + 1) % 3) == iRight1)
834 
835  || !AddTriangle(leftIsMinus ? i1outside : i1inside,
836  leftIsMinus ? i2outside : i2inside,
837  origVertIndexes[iRight1],
838  leftIsMinus ? plusMesh : minusMesh,
839  ((iRight2 + 1) % 3) == iRight1)
840 
841  || !AddTriangle(origVertIndexes[iRight1],
842  leftIsMinus ? i2outside : i2inside,
843  origVertIndexes[iRight2],
844  leftIsMinus ? plusMesh : minusMesh,
845  ((iRight2 + 1) % 3) == iRight1)) {
846  // early stop
847  i = triCount;
848  error = true;
849  break;
850  }
851  }
852  } break;
853  }
854  }
855  // end for each triangle
856 
857  // now add the remaining triangles
858  } catch (const std::bad_alloc&) {
859  // not enough memory
860  error = true;
861  }
862 
863  // free some memory
864  s_edgePoint.clear();
865 
866  if (!error) {
867  // import the 'preserved' (original) triangles
868  if (!MergeOldTriangles(mesh, vertices, minusMesh, insideVertices,
869  preservedTrianglesMinus) ||
870  !MergeOldTriangles(mesh, vertices, plusMesh, outsideVertices,
871  preservedTrianglesPlus)) {
872  error = true;
873  }
874  }
875 
876  if (error) {
877  delete minusMesh;
878  delete plusMesh;
879  return false;
880  }
881 
882  ioParams.insideMesh = minusMesh;
883  ioParams.outsideMesh = plusMesh;
884  return true;
885 }
886 
888  GenericIndexedMesh* origMesh,
889  GenericIndexedCloudPersist* origVertices,
890  MeshCutterParams& ioParams,
891  GenericProgressCallback* progressCb /*=0*/) {
892  if (!origMesh || !origVertices || origMesh->size() == 0 ||
893  origVertices->size() < 3 || ioParams.bbMin.x >= ioParams.bbMax.x ||
894  ioParams.bbMin.y >= ioParams.bbMax.y ||
895  ioParams.bbMin.z >= ioParams.bbMax.z) {
896  // invalid input parameters
897  return false;
898  }
899 
900  if (origMesh->size() > c_realIndexMask) {
901  // too many triangles!
902  return false;
903  }
904 
905  const double& epsilon = ioParams.epsilon;
906  const CCVector3d& bbMin = ioParams.bbMin;
907  const CCVector3d& bbMax = ioParams.bbMax;
908 
909  // indexes of original triangle that are not modified bt copied "as is"
910  std::vector<unsigned> preservedTrianglesInside1; // insde (1)
911  std::vector<unsigned> preservedTrianglesInside2; // insde (2)
912  std::vector<unsigned> preservedTrianglesOutside; // outside
913 
914  // inside meshes (swapped for each dimension)
915  PointCloud* insideVertices1 = new PointCloud;
916  SimpleMesh* insideMesh1 = new SimpleMesh(insideVertices1, true);
917  PointCloud* insideVertices2 = new PointCloud;
918  SimpleMesh* insideMesh2 = new SimpleMesh(insideVertices2, true);
919 
920  // outside mesh (output)
921  PointCloud* outsideVertices = nullptr;
922  SimpleMesh* outsideMesh = nullptr;
923  if (ioParams.generateOutsideMesh) {
924  outsideVertices = new PointCloud;
925  outsideMesh = new SimpleMesh(outsideVertices, true);
926  }
927 
928  // pointers on input and output structures (will change for each dimension)
929  std::vector<unsigned>* preservedTrianglesInside =
930  &preservedTrianglesInside1;
931  std::vector<unsigned>* formerPreservedTriangles =
932  &preservedTrianglesInside2;
933  PointCloud* insideVertices = insideVertices1;
934  SimpleMesh* insideMesh = insideMesh1;
935  GenericIndexedMesh* sourceMesh = origMesh;
936  GenericIndexedCloudPersist* sourceVertices = origVertices;
937 
938  CCVector3d boxCenter = (ioParams.bbMin + ioParams.bbMax) / 2;
939  CCVector3d boxHalfSize = (ioParams.bbMax - ioParams.bbMin) / 2;
940  bool error = false;
941 
942  // for each triangle
943  try {
944  // for each plane
945  for (unsigned d = 0; d < 6; ++d) {
946  // Extract the 'plane' information corresponding to the input box
947  // faces -X,+X,-Y,+Y,-Z,+Z
948  unsigned char Z = static_cast<unsigned char>(d / 2);
949  double planeCoord = ((d & 1) ? bbMax : bbMin).u[Z];
950  bool keepBelow = ((d & 1) ? true : false);
951 
952  assert(preservedTrianglesInside && formerPreservedTriangles);
953  assert(insideVertices && insideMesh);
954  assert(sourceVertices && sourceMesh);
955  s_edgePoint.clear();
956 
957  std::vector<unsigned> origTriIndexesMapInsideBackup;
958  if (ioParams.trackOrigIndexes) {
959  origTriIndexesMapInsideBackup =
960  ioParams.origTriIndexesMapInside;
961  ioParams.origTriIndexesMapInside.resize(0);
962  }
963 
964  // look for original triangles
965  //(the first time they only come from the original mesh but
966  // afterwards
967  // they can come from the original mesh through the 'preserved'
968  // list or from the previous 'inside' mesh as we have to test those
969  // triangles against the new plane)
970  unsigned sourceTriCount =
971  sourceMesh ? sourceMesh->size()
972  : 0; // source: previous/original mesh
973  unsigned formerPreservedTriCount =
974  static_cast<unsigned>(formerPreservedTriangles->size());
975  unsigned triCount = sourceTriCount + formerPreservedTriCount;
976 
977  for (unsigned i = 0; i < triCount; ++i) {
978  bool triangleIsOriginal = false;
979  unsigned souceTriIndex = 0;
980  const VerticesIndexes* tsi = nullptr;
981  if (i < sourceTriCount) {
982  souceTriIndex = i;
983  triangleIsOriginal = (sourceMesh == origMesh);
984  tsi = sourceMesh->getTriangleVertIndexes(souceTriIndex);
985  } else {
986  souceTriIndex =
987  (*formerPreservedTriangles)[i - sourceTriCount];
988  triangleIsOriginal = true;
989  tsi = origMesh->getTriangleVertIndexes(souceTriIndex);
990  }
991 
992  // vertices indexes
993  unsigned vertIndexes[3] = {tsi->i1, tsi->i2, tsi->i3};
994  if (triangleIsOriginal) {
995  // we flag the vertices indexes as referring to the
996  // 'original' mesh
997  vertIndexes[0] |= c_origIndexFlag;
998  vertIndexes[1] |= c_origIndexFlag;
999  vertIndexes[2] |= c_origIndexFlag;
1000  } else {
1001  // we flag the vertices indexes as referring to the 'source'
1002  // mesh
1003  if ((vertIndexes[0] & c_origIndexFlag) == 0)
1004  vertIndexes[0] |= c_srcIndexFlag;
1005  if ((vertIndexes[1] & c_origIndexFlag) == 0)
1006  vertIndexes[1] |= c_srcIndexFlag;
1007  if ((vertIndexes[2] & c_origIndexFlag) == 0)
1008  vertIndexes[2] |= c_srcIndexFlag;
1009  }
1010 
1011  // get the vertices (from the right source!)
1013  ((vertIndexes[0] & c_origIndexFlag)
1014  ? origVertices
1015  : sourceVertices)
1016  ->getPoint(vertIndexes[0] &
1018  ->u),
1020  ((vertIndexes[1] & c_origIndexFlag)
1021  ? origVertices
1022  : sourceVertices)
1023  ->getPoint(vertIndexes[1] &
1025  ->u),
1027  ((vertIndexes[2] & c_origIndexFlag)
1028  ? origVertices
1029  : sourceVertices)
1030  ->getPoint(vertIndexes[2] &
1032  ->u)};
1033 
1034  if (d == 0) {
1035  // perform a triangle-box overlap test the first time!
1036  if (!CCMiscTools::TriBoxOverlapd(boxCenter, boxHalfSize,
1037  V)) {
1038  if (ioParams.generateOutsideMesh)
1039  preservedTrianglesOutside.push_back(i);
1040  continue;
1041  }
1042  }
1043 
1044  // test the position of each vertex relatively to the current
1045  // plane char relativePos[3] = { 1, 1, 1 }; bool insideXY[3] = {
1046  // false, false, false };
1047  std::vector<unsigned char> insideLocalVertIndexes,
1048  outsideLocalVertIndexes;
1049  for (unsigned char j = 0; j < 3; ++j) {
1050  const CCVector3d& v = V[j];
1051  if (std::abs(v.u[Z] - planeCoord) < epsilon) {
1052  // relativePos[j] = 0;
1053  } else {
1054  if (v.u[Z] < planeCoord) {
1055  insideLocalVertIndexes.push_back(j);
1056  // relativePos[j] = -1;
1057  } else {
1058  // relativePos is already equal to 1
1059  // relativePos[j] = 1;
1060  outsideLocalVertIndexes.push_back(j);
1061  }
1062  }
1063  }
1064 
1065  // depending on the number of entities on the plane
1066  // we'll process the triangles differently
1067  bool isFullyInside = false;
1068  bool isFullyOutside = false;
1069  switch (insideLocalVertIndexes.size() +
1070  outsideLocalVertIndexes.size()) {
1071  case 0: // all vertices 'in' the plane
1072  {
1073  // we arbitrarily decide that the triangle is inside!
1074  isFullyInside = true;
1075  } break;
1076 
1077  case 1: // 2 vertices 'in' the plane
1078  {
1079  // the triangle is either on one side or another ;)
1080  if (insideLocalVertIndexes.empty()) {
1081  // the only vertex far from the plane is on the
1082  // 'otuside'
1083  isFullyOutside = true;
1084  } else {
1085  // the only vertex far from the plane is on the
1086  // 'inside'
1087  isFullyInside = true;
1088  }
1089  } break;
1090 
1091  case 2: // 1 vertex 'in' the plane
1092  {
1093  // 3 cases:
1094  if (insideLocalVertIndexes.empty()) {
1095  // the two vertices far from the plane are 'outside'
1096  isFullyOutside = true;
1097  } else if (outsideLocalVertIndexes.empty()) {
1098  // the two vertices far from the plane are 'inside'
1099  isFullyInside = true;
1100  } else {
1101  // the two vertices far from the plane are on both
1102  // sides the plane will cut through the edge
1103  // connecting those two vertices
1104  unsigned char iInside =
1105  insideLocalVertIndexes.front();
1106  unsigned char iOuside =
1107  outsideLocalVertIndexes.front();
1108 
1109  unsigned char iCenter = 3 - iInside - iOuside;
1110  unsigned iCoutside, iCinside;
1111  // we can now create one vertex and two new
1112  // triangles
1113  if (!ComputeEdgePoint(
1114  V[iInside], vertIndexes[iInside],
1115  V[iOuside], vertIndexes[iOuside],
1116  iCoutside, iCinside, planeCoord, Z,
1117  outsideVertices, insideVertices)
1118 
1119  || !AddTriangle(
1120  vertIndexes[iCenter],
1121  vertIndexes[iInside],
1122  keepBelow ? iCinside : iCoutside,
1123  keepBelow ? insideMesh : outsideMesh,
1124  ((iCenter + 1) % 3) == iInside)
1125 
1126  || !AddTriangle(
1127  vertIndexes[iCenter],
1128  vertIndexes[iOuside],
1129  keepBelow ? iCoutside : iCinside,
1130  keepBelow ? outsideMesh : insideMesh,
1131  ((iCenter + 1) % 3) == iOuside)) {
1132  // early stop
1133  i = triCount;
1134  error = true;
1135  break;
1136  }
1137 
1138  // remember (origin) source triangle index
1139  if (ioParams.trackOrigIndexes) {
1140  assert(triangleIsOriginal ||
1141  souceTriIndex <
1142  origTriIndexesMapInsideBackup
1143  .size());
1144  unsigned origTriIndex =
1145  triangleIsOriginal
1146  ? souceTriIndex
1147  : origTriIndexesMapInsideBackup
1148  [souceTriIndex];
1149  // the source triangle is split in two so each
1150  // side get one new triangle
1151  ioParams.origTriIndexesMapInside.push_back(
1152  origTriIndex);
1153  if (ioParams.generateOutsideMesh)
1154  ioParams.origTriIndexesMapOutside.push_back(
1155  origTriIndex);
1156  }
1157  }
1158  } break;
1159 
1160  case 3: // no vertex 'in' the plane
1161  {
1162  if (insideLocalVertIndexes.empty()) {
1163  // all vertices are 'outside'
1164  isFullyOutside = true;
1165  } else if (outsideLocalVertIndexes.empty()) {
1166  // all vertices are 'inside'
1167  isFullyInside = true;
1168  } else {
1169  // we have one vertex on one side and two on the
1170  // other side
1171  unsigned char iLeft, iRight1, iRight2;
1172  bool leftIsInside = true;
1173  if (insideLocalVertIndexes.size() == 1) {
1174  assert(outsideLocalVertIndexes.size() == 2);
1175  iLeft = insideLocalVertIndexes.front();
1176  iRight1 = outsideLocalVertIndexes[0];
1177  iRight2 = outsideLocalVertIndexes[1];
1178  leftIsInside = keepBelow;
1179  } else {
1180  assert(insideLocalVertIndexes.size() == 2);
1181  iLeft = outsideLocalVertIndexes.front();
1182  iRight1 = insideLocalVertIndexes[0];
1183  iRight2 = insideLocalVertIndexes[1];
1184  leftIsInside = !keepBelow;
1185  }
1186 
1187  // the plane cuts through the two edges having the
1188  // 'single' vertex in common we are going to create
1189  // 3 triangles
1190  unsigned i1outside, i1inside;
1191  unsigned i2outside, i2inside;
1192  if (!ComputeEdgePoint(
1193  V[iRight1], vertIndexes[iRight1],
1194  V[iLeft], vertIndexes[iLeft], i1outside,
1195  i1inside, planeCoord, Z,
1196  outsideVertices, insideVertices)
1197 
1198  || !ComputeEdgePoint(
1199  V[iRight2], vertIndexes[iRight2],
1200  V[iLeft], vertIndexes[iLeft],
1201  i2outside, i2inside, planeCoord, Z,
1202  outsideVertices, insideVertices)
1203 
1204  ||
1205  !AddTriangle(
1206  vertIndexes[iLeft],
1207  leftIsInside ? i1inside : i1outside,
1208  leftIsInside ? i2inside : i2outside,
1209  leftIsInside ? insideMesh : outsideMesh,
1210  ((iLeft + 1) % 3) == iRight1)
1211 
1212  ||
1213  !AddTriangle(
1214  leftIsInside ? i1outside : i1inside,
1215  leftIsInside ? i2outside : i2inside,
1216  vertIndexes[iRight1],
1217  leftIsInside ? outsideMesh : insideMesh,
1218  ((iRight2 + 1) % 3) == iRight1)
1219 
1220  ||
1221  !AddTriangle(
1222  vertIndexes[iRight1],
1223  leftIsInside ? i2outside : i2inside,
1224  vertIndexes[iRight2],
1225  leftIsInside ? outsideMesh : insideMesh,
1226  ((iRight2 + 1) % 3) == iRight1)) {
1227  // early stop
1228  i = triCount;
1229  error = true;
1230  break;
1231  }
1232 
1233  // remember (origin) source triangle index
1234  if (ioParams.trackOrigIndexes) {
1235  assert(triangleIsOriginal ||
1236  souceTriIndex <
1237  origTriIndexesMapInsideBackup
1238  .size());
1239  unsigned origTriIndex =
1240  triangleIsOriginal
1241  ? souceTriIndex
1242  : origTriIndexesMapInsideBackup
1243  [souceTriIndex];
1244  // each side gets at least one new triangle
1245  ioParams.origTriIndexesMapInside.push_back(
1246  origTriIndex);
1247  if (ioParams.generateOutsideMesh)
1248  ioParams.origTriIndexesMapOutside.push_back(
1249  origTriIndex);
1250  // the third triangle has been added either to
1251  // the 'inside' or to the 'outside' mesh
1252  if (!leftIsInside)
1253  ioParams.origTriIndexesMapInside.push_back(
1254  origTriIndex);
1255  else if (ioParams.generateOutsideMesh)
1256  ioParams.origTriIndexesMapOutside.push_back(
1257  origTriIndex);
1258  }
1259  }
1260  } break;
1261  }
1262 
1263  if (isFullyInside || isFullyOutside) {
1264  // inverted selection?
1265  if (!keepBelow) std::swap(isFullyInside, isFullyOutside);
1266 
1267  if (triangleIsOriginal) {
1268  if (isFullyInside)
1269  preservedTrianglesInside->push_back(souceTriIndex);
1270  else if (ioParams.generateOutsideMesh)
1271  preservedTrianglesOutside.push_back(souceTriIndex);
1272  } else {
1273  // we import the former triangle
1274  if (!AddTriangle(
1275  vertIndexes[0], vertIndexes[1],
1276  vertIndexes[2],
1277  isFullyInside ? insideMesh : outsideMesh,
1278  true)) {
1279  // early stop
1280  error = true;
1281  break;
1282  }
1283  if (ioParams.trackOrigIndexes) {
1284  assert(souceTriIndex <
1285  origTriIndexesMapInsideBackup.size());
1286  unsigned origTriIndex =
1287  origTriIndexesMapInsideBackup
1288  [souceTriIndex];
1289  if (isFullyInside)
1290  ioParams.origTriIndexesMapInside.push_back(
1291  origTriIndex);
1292  else if (ioParams.generateOutsideMesh)
1293  ioParams.origTriIndexesMapOutside.push_back(
1294  origTriIndex);
1295  }
1296  }
1297  }
1298  }
1299  // end for each triangle
1300 
1301  if (!ImportSourceVertices(sourceVertices, insideMesh,
1302  insideVertices) ||
1303  (ioParams.generateOutsideMesh &&
1304  !ImportSourceVertices(sourceVertices, outsideMesh,
1305  outsideVertices))) {
1306  // early stop
1307  error = true;
1308  break;
1309  }
1310 
1311  if (insideMesh->size() == 0 && preservedTrianglesInside->empty()) {
1312  // no triangle inside!
1313  break;
1314  }
1315 
1316  if (d < 5) {
1317  // clear the source mesh and swap the buffers
1318  if (insideMesh == insideMesh1) {
1319  assert(sourceMesh == insideMesh2 || sourceMesh == origMesh);
1320  insideMesh2->clear();
1321  insideVertices2->reset();
1322  sourceMesh = insideMesh1;
1323  sourceVertices = insideVertices1;
1324  insideMesh = insideMesh2;
1325  insideVertices = insideVertices2;
1326  preservedTrianglesInside2.resize(0);
1327  preservedTrianglesInside = &preservedTrianglesInside2;
1328  formerPreservedTriangles = &preservedTrianglesInside1;
1329  } else {
1330  assert(sourceMesh == insideMesh1 || sourceMesh == origMesh);
1331  insideMesh1->clear();
1332  insideVertices1->reset();
1333  sourceMesh = insideMesh2;
1334  sourceVertices = insideVertices2;
1335  insideMesh = insideMesh1;
1336  insideVertices = insideVertices1;
1337  preservedTrianglesInside1.resize(0);
1338  preservedTrianglesInside = &preservedTrianglesInside1;
1339  formerPreservedTriangles = &preservedTrianglesInside2;
1340  }
1341  }
1342  }
1343  // end for each plane
1344 
1345  // now add the remaining triangles
1346  } catch (const std::bad_alloc&) {
1347  // not enough memory
1348  error = true;
1349  }
1350 
1351  // free some memory
1352  s_edgePoint.clear();
1353  formerPreservedTriangles->resize(0);
1354 
1355  if (!error) {
1356  // import the 'preserved' (original) triangles
1357  if (!MergeOldTriangles(origMesh, origVertices, insideMesh,
1358  insideVertices, *preservedTrianglesInside,
1359  ioParams.trackOrigIndexes
1360  ? &ioParams.origTriIndexesMapInside
1361  : 0) ||
1362  (ioParams.generateOutsideMesh &&
1363  !MergeOldTriangles(origMesh, origVertices, outsideMesh,
1364  outsideVertices, preservedTrianglesOutside,
1365  ioParams.trackOrigIndexes
1366  ? &ioParams.origTriIndexesMapOutside
1367  : 0))) {
1368  error = true;
1369  }
1370  }
1371 
1372  if (insideMesh == insideMesh1) {
1373  delete insideMesh2;
1374  insideMesh2 = nullptr;
1375  insideVertices2 = nullptr;
1376  } else {
1377  delete insideMesh1;
1378  insideMesh1 = nullptr;
1379  insideVertices1 = nullptr;
1380  }
1381 
1382  if (error) {
1383  delete insideMesh;
1384  delete outsideMesh;
1385  return false;
1386  }
1387 
1388  if (insideMesh) {
1389  insideMesh->resize(insideMesh->size());
1390  }
1391  if (outsideMesh) {
1392  outsideMesh->resize(outsideMesh->size());
1393  }
1394 
1395  ioParams.insideMesh = insideMesh;
1396  ioParams.outsideMesh = outsideMesh;
1397  return true;
1398 }
constexpr double EPSILON_VALUE
Definition: CVConst.h:87
Vector2Tpl< PointCoordinateType > CCVector2
Default 2D Vector.
Definition: CVGeom.h:780
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int size
int count
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:36
Type y
Definition: CVGeom.h:36
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
static bool TriBoxOverlapd(const CCVector3d &boxcenter, const CCVector3d &boxhalfsize, const CCVector3d triverts[3])
Ovelap test between a 3D box and a triangle (double version)
virtual unsigned size() const =0
Returns the number of points.
virtual ScalarType getPointScalarValue(unsigned pointIndex) const =0
Returns the ith point associated scalar value.
A generic 3D point cloud with index-based and presistent access to points.
A generic 3D point cloud with index-based point access.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
A generic mesh with index-based vertex access.
virtual VerticesIndexes * getNextTriangleVertIndexes()=0
virtual VerticesIndexes * getTriangleVertIndexes(unsigned triangleIndex)=0
Returns the indexes of the vertices of a given triangle.
virtual unsigned size() const =0
Returns the number of triangles.
virtual void placeIteratorAtBeginning()=0
Places the mesh iterator at the beginning.
virtual void setInfo(const char *infoStr)=0
Notifies some information about the ongoing process.
virtual void setMethodTitle(const char *methodTitle)=0
Notifies the algorithm title.
virtual bool textCanBeEdited() const
Returns whether the dialog title and info can be updated or not.
virtual void update(float percent)=0
Notifies the algorithm progress.
static ReferenceCloud * segment(GenericIndexedCloudPersist *aCloud, const Polyline *poly, bool keepInside, const float *viewMat=nullptr)
static bool isPointInsidePoly(const CCVector2 &P, const GenericIndexedCloud *polyVertices)
Tests if a point is inside a polygon (2D)
static GenericIndexedMesh * segmentMesh(GenericIndexedMesh *mesh, ReferenceCloud *selectedVertexIndexes, bool useSelectedVertices, GenericProgressCallback *progressCb=nullptr, GenericIndexedCloud *destCloud=nullptr, unsigned indexShift=0, std::vector< int > *triangleIndexMap=nullptr)
Segments a mesh knowing which vertices should be kept or not.
static bool segmentMeshWithAABox(GenericIndexedMesh *mesh, GenericIndexedCloudPersist *vertices, MeshCutterParams &ioParams, GenericProgressCallback *progressCb=nullptr)
static bool segmentMeshWithAAPlane(GenericIndexedMesh *mesh, GenericIndexedCloudPersist *vertices, MeshCutterParams &ioParams, GenericProgressCallback *progressCb=nullptr)
bool oneStep()
Increments total progress value of a single unit.
void reset()
Clears the cloud database.
virtual bool reserve(unsigned newCapacity)
Reserves memory for the point database.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Definition: PointCloudTpl.h:38
unsigned capacity() const
Returns cloud capacity (i.e. reserved size)
bool resize(unsigned newCount) override
Resizes the point database.
Definition: CVPointCloud.h:41
A simple polyline class.
Definition: Polyline.h:20
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
unsigned size() const override
Returns the number of points.
virtual unsigned getPointGlobalIndex(unsigned localIndex) const
A simple mesh structure, with index-based vertex access.
Definition: SimpleMesh.h:26
virtual bool resize(unsigned n)
Resizes the mesh database.
Definition: SimpleMesh.cpp:118
virtual unsigned size() const override
Returns the number of triangles.
Definition: SimpleMesh.h:47
unsigned capacity() const
Returns the mesh capacity.
Definition: SimpleMesh.h:62
void clear()
Clears the mesh.
Definition: SimpleMesh.h:70
virtual void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
Definition: SimpleMesh.cpp:103
VerticesIndexes * getTriangleVertIndexes(unsigned triangleIndex) override
Returns the indexes of the vertices of a given triangle.
Definition: SimpleMesh.cpp:180
virtual bool reserve(unsigned n)
Reserves the memory to store the triangles (as 3 indexes each)
Definition: SimpleMesh.cpp:109
bool AddTriangle(unsigned iA, unsigned iB, unsigned iC, SimpleMesh *mesh, bool directOrder)
bool AddVertex(CCVector3d &P, PointCloud *vertices, unsigned &index)
const unsigned c_srcIndexFlag
bool ImportSourceVertices(GenericIndexedCloudPersist *srcVertices, SimpleMesh *newMesh, PointCloud *newVertices)
static std::map< uint64_t, InsideOutsideIndexes > s_edgePoint
const unsigned c_defaultArrayGrowth
bool MergeOldTriangles(GenericIndexedMesh *origMesh, GenericIndexedCloudPersist *origVertices, SimpleMesh *newMesh, PointCloud *newVertices, const std::vector< unsigned > &preservedTriangleIndexes, std::vector< unsigned > *origTriIndexesMap=nullptr)
bool ComputeEdgePoint(const CCVector3d &A, unsigned iA, const CCVector3d &B, unsigned iB, unsigned &iCoutside, unsigned &iCinside, double planeCoord, unsigned char planeDim, PointCloud *outsideVertices, PointCloud *insideVertices)
const unsigned c_origIndexFlag
const unsigned c_realIndexMask
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
static double dist(double x1, double y1, double x2, double y2)
Definition: lsd.c:207
static void error(char *msg)
Definition: lsd.c:159
::ccPointCloud PointCloud
Definition: PointCloud.h:19
Generic file read and write utility for python interface.
SquareMatrixTpl< PointCoordinateType > SquareMatrix
Default CC square matrix type (PointCoordinateType)
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370
InsideOutsideIndexes(unsigned inside, unsigned outside)
Input/output parameters for the segmentMeshWithAAPlane method.
Triangle described by the indexes of its 3 vertices.