12 #include <Eigen/Dense>
32 typedef std::tuple<double, double, double> Coordinate3;
33 std::unordered_map<Coordinate3, size_t, utility::hash_tuple<Coordinate3>>
35 std::vector<int> index_old_to_new(getVerticeSize());
36 bool has_vert_normal = hasNormals();
37 bool has_vert_color = hasColors();
38 size_t old_vertex_num = getVerticeSize();
40 for (
size_t i = 0; i < old_vertex_num; i++) {
41 Coordinate3 coord = std::make_tuple(getVertice(i)(0), getVertice(i)(1),
43 if (point_to_old_index.find(coord) == point_to_old_index.end()) {
44 point_to_old_index[coord] = i;
45 setVertice(k, getVertice(i));
46 if (has_vert_normal) setVertexNormal(k, getVertexNormal(i));
47 if (has_vert_color) setVertexColor(k, getVertexColor(i));
48 index_old_to_new[i] = (int)k;
51 index_old_to_new[i] = index_old_to_new[point_to_old_index[coord]];
59 cloud->
resize(
static_cast<unsigned>(k));
62 "[RemoveUnreferencedVertices] ccMesh has not associated "
67 if (k < old_vertex_num) {
68 for (
auto &triangle : *getTrianglesPtr()) {
69 triangle.i1 =
static_cast<unsigned>(index_old_to_new[triangle.i1]);
70 triangle.i2 =
static_cast<unsigned>(index_old_to_new[triangle.i2]);
71 triangle.i3 =
static_cast<unsigned>(index_old_to_new[triangle.i3]);
73 if (hasAdjacencyList()) {
74 ComputeAdjacencyList();
78 "[RemoveDuplicatedVertices] {:d} vertices have been removed.",
79 (
int)(old_vertex_num - k));
85 if (hasTriangleUvs()) {
87 "[RemoveDuplicatedTriangles] This mesh contains triangle uvs "
88 "that are not handled in this function");
90 typedef std::tuple<int, int, int> Index3;
91 std::unordered_map<Index3, size_t, utility::hash_tuple<Index3>>
92 triangle_to_old_index;
93 bool has_tri_normal = hasTriNormals();
94 size_t old_triangle_num =
size();
96 for (
size_t i = 0; i < old_triangle_num; i++) {
101 if (triangleInd(0) <= triangleInd(1)) {
102 if (triangleInd(0) <= triangleInd(2)) {
103 index = std::make_tuple(triangleInd(0), triangleInd(1),
106 index = std::make_tuple(triangleInd(2), triangleInd(0),
110 if (triangleInd(1) <= triangleInd(2)) {
111 index = std::make_tuple(triangleInd(1), triangleInd(2),
114 index = std::make_tuple(triangleInd(2), triangleInd(0),
118 if (triangle_to_old_index.find(index) == triangle_to_old_index.end()) {
119 triangle_to_old_index[index] = i;
120 setTriangle(k, triangleInd);
121 if (has_tri_normal) setTriangleNorm(k, getTriangleNorm(i));
128 if (has_tri_normal) m_triNormals->resize(k);
129 if (k < old_triangle_num && hasAdjacencyList()) {
130 ComputeAdjacencyList();
133 "[RemoveDuplicatedTriangles] {:d} triangles have been removed.",
134 (
int)(old_triangle_num - k));
140 std::vector<bool> vertex_has_reference(getVerticeSize(),
false);
141 for (
const auto &triangle : *getTrianglesPtr()) {
142 vertex_has_reference[triangle.i1] =
true;
143 vertex_has_reference[triangle.i2] =
true;
144 vertex_has_reference[triangle.i3] =
true;
147 std::vector<int> index_old_to_new(getVerticeSize());
148 bool has_vert_normal = hasNormals();
149 bool has_vert_color = hasColors();
150 size_t old_vertex_num = getVerticeSize();
152 for (
size_t i = 0; i < old_vertex_num; i++) {
153 if (vertex_has_reference[i]) {
154 setVertice(k, getVertice(i));
155 if (has_vert_normal) setVertexNormal(k, getVertexNormal(i));
156 if (has_vert_color) setVertexColor(k, getVertexColor(i));
157 index_old_to_new[i] = (int)k;
160 index_old_to_new[i] = -1;
168 cloud->
resize(
static_cast<unsigned>(k));
171 "[RemoveUnreferencedVertices] ccMesh has not associated "
176 if (k < old_vertex_num) {
177 for (
auto &triangle : *getTrianglesPtr()) {
178 triangle.i1 =
static_cast<unsigned>(index_old_to_new[triangle.i1]);
179 triangle.i2 =
static_cast<unsigned>(index_old_to_new[triangle.i2]);
180 triangle.i3 =
static_cast<unsigned>(index_old_to_new[triangle.i3]);
182 if (hasAdjacencyList()) {
183 ComputeAdjacencyList();
187 "[RemoveUnreferencedVertices] {:d} vertices have been removed.",
188 (
int)(old_vertex_num - k));
194 if (hasTriangleUvs()) {
196 "[RemoveDegenerateTriangles] This mesh contains triangle uvs "
197 "that are not handled in this function");
199 bool has_tri_normal = hasTriNormals();
200 size_t old_triangle_num =
size();
202 for (
size_t i = 0; i < old_triangle_num; i++) {
203 auto triangle = getTriangle(i);
204 if (triangle(0) != triangle(1) && triangle(1) != triangle(2) &&
205 triangle(2) != triangle(0)) {
206 setTriangle(k, getTriangle(i));
207 if (has_tri_normal) setTriangleNorm(k, getTriangleNorm(i));
214 if (has_tri_normal) m_triNormals->resize(k);
215 if (k < old_triangle_num && hasAdjacencyList()) {
216 ComputeAdjacencyList();
219 "[RemoveDegenerateTriangles] {:d} triangles have been "
221 (
int)(old_triangle_num - k));
226 if (hasTriangleUvs()) {
228 "[RemoveNonManifoldEdges] This mesh contains triangle uvs that "
229 "are not handled in this function");
231 std::vector<double> triangle_areas;
232 GetSurfaceArea(triangle_areas);
234 bool mesh_is_edge_manifold =
false;
235 while (!mesh_is_edge_manifold) {
236 mesh_is_edge_manifold =
true;
239 for (
auto &kv : edges_to_triangles) {
240 size_t n_edge_triangle_refs = kv.second.size();
243 if (n_edge_triangle_refs == 1u || n_edge_triangle_refs == 2u) {
248 mesh_is_edge_manifold =
false;
257 for (
int tidx : kv.second) {
258 if (triangle_areas[tidx] > 0) {
264 int n_triangles_to_delete = n_triangles - 2;
265 while (n_triangles_to_delete > 0) {
268 double min_area = std::numeric_limits<double>::max();
269 for (
int tidx : kv.second) {
270 double area = triangle_areas[tidx];
271 if (area > 0 && area < min_area) {
278 triangle_areas[min_tidx] = -1;
279 n_triangles_to_delete--;
284 bool has_tri_normal = hasTriNormals();
286 for (
size_t from_tidx = 0; from_tidx <
size(); ++from_tidx) {
287 if (triangle_areas[from_tidx] > 0) {
288 setTriangle(to_tidx, getTriangle(from_tidx));
289 triangle_areas[to_tidx] = triangle_areas[from_tidx];
290 if (has_tri_normal) {
291 setTriangleNorm(to_tidx, getTriangleNorm(from_tidx));
300 triangle_areas.resize(to_tidx);
301 if (has_tri_normal) {
302 m_triNormals->resize(to_tidx);
313 std::vector<std::vector<int>> nbs(getVerticeSize());
315 #pragma omp parallel for schedule(static) \
316 num_threads(utility::EstimateMaxThreads())
318 for (
int idx = 0; idx < int(getVerticeSize()); ++idx) {
319 std::vector<double> dists2;
320 kdtree.
SearchRadius(getVertice(
static_cast<size_t>(idx)), eps, nbs[idx],
328 bool has_vertex_normals = hasNormals();
329 bool has_vertex_colors = hasColors();
330 std::vector<CCVector3> new_vertices;
331 std::vector<CCVector3> new_vertex_normals;
333 std::unordered_map<int, int> new_vert_mapping;
334 for (
int vidx = 0; vidx < int(getVerticeSize()); ++vidx) {
335 if (new_vert_mapping.count(vidx) > 0) {
339 int new_vidx = int(new_vertices.size());
340 new_vert_mapping[vidx] = new_vidx;
342 CCVector3 vertex = getVertice(
static_cast<size_t>(vidx));
344 if (has_vertex_normals) {
345 normal = getVertexNormal(
static_cast<size_t>(vidx));
347 Eigen::Vector3d
color;
348 if (has_vertex_colors) {
349 color = getVertexColor(
static_cast<size_t>(vidx));
352 for (
int nb : nbs[vidx]) {
353 if (vidx == nb || new_vert_mapping.count(nb) > 0) {
356 vertex += getVertice(
static_cast<size_t>(nb));
357 if (has_vertex_normals) {
358 normal += getVertexNormal(
static_cast<size_t>(nb));
360 if (has_vertex_colors) {
361 color += getVertexColor(
static_cast<size_t>(nb));
363 new_vert_mapping[nb] = new_vidx;
366 new_vertices.push_back(vertex / n);
367 if (has_vertex_normals) {
368 new_vertex_normals.push_back(
normal / n);
370 if (has_vertex_colors) {
375 getVerticeSize() - new_vertices.size());
378 if (has_vertex_normals) {
381 if (has_vertex_colors) {
385 for (
auto &triangle : *getTrianglesPtr()) {
386 triangle.i1 =
static_cast<unsigned>(new_vert_mapping[triangle.i1]);
387 triangle.i2 =
static_cast<unsigned>(new_vert_mapping[triangle.i2]);
388 triangle.i3 =
static_cast<unsigned>(new_vert_mapping[triangle.i3]);
391 if (hasTriNormals()) {
392 computePerTriangleNormals();
399 if (getAssociatedCloud() &&
408 std::tuple<std::shared_ptr<ccMesh>, std::vector<size_t>>
420 scope == FilterScope::All || scope == FilterScope::Vertex;
422 (scope == FilterScope::All || scope == FilterScope::Normal) &&
425 (scope == FilterScope::All || scope == FilterScope::Color) &&
428 std::vector<CCVector3> prev_vertices = cloud->
getPoints();
430 std::vector<CCVector3> prev_vertex_normals;
436 prev_vertex_colors = *cloud->
rgbColors();
440 assert(baseVertices);
444 std::shared_ptr<ccMesh> mesh = std::make_shared<ccMesh>(baseVertices);
445 mesh->addChild(baseVertices);
455 mesh->setTriangles(getTriangles());
456 mesh->adjacency_list_ = adjacency_list_;
457 if (!mesh->hasAdjacencyList()) {
458 mesh->ComputeAdjacencyList();
461 for (
int iter = 0; iter < number_of_iterations; ++iter) {
462 for (
size_t vidx = 0; vidx < baseVertices->
size(); ++vidx) {
465 Eigen::Vector3d color_sum(0, 0, 0);
466 for (
int nbidx : mesh->adjacency_list_[vidx]) {
468 vertex_sum += prev_vertices[nbidx];
471 normal_sum += prev_vertex_normals[nbidx];
476 static_cast<size_t>(nbidx)));
480 size_t nb_size = mesh->adjacency_list_[vidx].size();
483 static_cast<float>(strength) *
484 (prev_vertices[vidx] *
485 static_cast<float>(nb_size) -
491 CCVector3 p = prev_vertex_normals[vidx] +
492 static_cast<float>(strength) *
493 (prev_vertex_normals[vidx] *
494 static_cast<float>(nb_size) -
503 prev_vertex_colors[vidx]) *
508 if (iter < number_of_iterations - 1) {
519 if (hasTriNormals()) {
520 mesh->ComputeTriangleNormals();
541 scope == FilterScope::All || scope == FilterScope::Vertex;
543 (scope == FilterScope::All || scope == FilterScope::Normal) &&
546 (scope == FilterScope::All || scope == FilterScope::Color) &&
549 std::vector<CCVector3> prev_vertices = cloud->
getPoints();
550 std::vector<CCVector3> prev_vertex_normals;
556 prev_vertex_colors = *cloud->
rgbColors();
560 assert(baseVertices);
564 std::shared_ptr<ccMesh> mesh = std::make_shared<ccMesh>(baseVertices);
565 mesh->addChild(baseVertices);
575 mesh->setTriangles(getTriangles());
576 mesh->adjacency_list_ = adjacency_list_;
577 if (!mesh->hasAdjacencyList()) {
578 mesh->ComputeAdjacencyList();
581 for (
int iter = 0; iter < number_of_iterations; ++iter) {
582 for (
size_t vidx = 0; vidx < baseVertices->
size(); ++vidx) {
585 Eigen::Vector3d color_sum(0, 0, 0);
586 for (
int nbidx : mesh->adjacency_list_[vidx]) {
588 vertex_sum += prev_vertices[nbidx];
591 normal_sum += prev_vertex_normals[nbidx];
595 prev_vertex_colors.at(
static_cast<size_t>(nbidx)));
599 size_t nb_size = mesh->adjacency_list_[vidx].size();
603 (prev_vertices[vidx] + vertex_sum) / (1 + nb_size));
607 vidx, (prev_vertex_normals[vidx] + normal_sum) /
618 if (iter < number_of_iterations - 1) {
629 if (hasTriNormals()) {
630 mesh->ComputeTriangleNormals();
646 std::shared_ptr<ccMesh> &mesh,
647 const std::vector<CCVector3> &prev_vertices,
648 const std::vector<CCVector3> &prev_vertex_normals,
650 const std::vector<std::unordered_set<int>> &adjacency_list,
654 bool filter_color)
const {
659 for (
size_t vidx = 0; vidx < cloud->
size(); ++vidx) {
662 Eigen::Vector3d color_sum(0, 0, 0);
663 double total_weight = 0;
664 for (
int nbidx : mesh->adjacency_list_[vidx]) {
665 auto diff = prev_vertices[vidx] - prev_vertices[nbidx];
666 double dist = diff.norm();
667 double weight = 1. / (dist + 1
e-12);
668 total_weight += weight;
671 vertex_sum +=
static_cast<float>(weight) * prev_vertices[nbidx];
675 static_cast<float>(weight) * prev_vertex_normals[nbidx];
678 color_sum += weight *
684 cloud->
setPoint(vidx, prev_vertices[vidx] +
685 static_cast<float>(lambda) *
686 (vertex_sum / total_weight -
687 prev_vertices[vidx]));
691 prev_vertex_normals[vidx] +
692 static_cast<float>(lambda) *
693 (normal_sum / total_weight -
694 prev_vertex_normals[vidx]));
699 lambda * (color_sum / total_weight -
713 scope == FilterScope::All || scope == FilterScope::Vertex;
715 (scope == FilterScope::All || scope == FilterScope::Normal) &&
718 (scope == FilterScope::All || scope == FilterScope::Color) &&
721 std::vector<CCVector3> prev_vertices = cloud->
getPoints();
722 std::vector<CCVector3> prev_vertex_normals;
728 prev_vertex_colors = *cloud->
rgbColors();
732 assert(baseVertices);
736 std::shared_ptr<ccMesh> mesh = std::make_shared<ccMesh>(baseVertices);
737 mesh->addChild(baseVertices);
747 mesh->setTriangles(getTriangles());
748 mesh->adjacency_list_ = adjacency_list_;
749 if (!mesh->hasAdjacencyList()) {
750 mesh->ComputeAdjacencyList();
753 for (
int iter = 0; iter < number_of_iterations; ++iter) {
754 FilterSmoothLaplacianHelper(mesh, prev_vertices, prev_vertex_normals,
755 prev_vertex_colors, mesh->adjacency_list_,
756 lambda, filter_vertex, filter_normal,
758 if (iter < number_of_iterations - 1) {
769 if (hasTriNormals()) {
770 mesh->ComputeTriangleNormals();
793 scope == FilterScope::All || scope == FilterScope::Vertex;
795 (scope == FilterScope::All || scope == FilterScope::Normal) &&
798 (scope == FilterScope::All || scope == FilterScope::Color) &&
801 std::vector<CCVector3> prev_vertices = cloud->
getPoints();
802 std::vector<CCVector3> prev_vertex_normals;
808 prev_vertex_colors = *cloud->
rgbColors();
812 assert(baseVertices);
816 std::shared_ptr<ccMesh> mesh = std::make_shared<ccMesh>(baseVertices);
817 mesh->addChild(baseVertices);
827 mesh->setTriangles(getTriangles());
828 mesh->adjacency_list_ = adjacency_list_;
829 if (!mesh->hasAdjacencyList()) {
830 mesh->ComputeAdjacencyList();
833 for (
int iter = 0; iter < number_of_iterations; ++iter) {
834 FilterSmoothLaplacianHelper(mesh, prev_vertices, prev_vertex_normals,
835 prev_vertex_colors, mesh->adjacency_list_,
836 lambda, filter_vertex, filter_normal,
847 FilterSmoothLaplacianHelper(mesh, prev_vertices, prev_vertex_normals,
848 prev_vertex_colors, mesh->adjacency_list_,
849 mu, filter_vertex, filter_normal,
852 if (iter < number_of_iterations - 1) {
863 if (hasTriNormals()) {
864 mesh->ComputeTriangleNormals();
880 std::unordered_set<Eigen::Vector2i, utility::hash_eigen<Eigen::Vector2i>>
883 for (
auto triangle : getTriangles()) {
889 int E = int(edges.size());
890 int V = int(getVerticeSize());
896 bool allow_boundary_edges )
const {
898 std::vector<Eigen::Vector2i> non_manifold_edges;
899 for (
auto &kv : edges) {
900 if ((allow_boundary_edges &&
901 (kv.second.size() < 1 || kv.second.size() > 2)) ||
902 (!allow_boundary_edges && kv.second.size() != 2)) {
903 non_manifold_edges.push_back(kv.first);
906 return non_manifold_edges;
911 for (
auto &kv : edges) {
912 if ((allow_boundary_edges &&
913 (kv.second.size() < 1 || kv.second.size() > 2)) ||
914 (!allow_boundary_edges && kv.second.size() != 2)) {
922 std::vector<std::unordered_set<int>> vert_to_triangles(getVerticeSize());
923 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
924 const auto &tria = getTriangle(tidx);
925 vert_to_triangles[tria(0)].emplace(
int(tidx));
926 vert_to_triangles[tria(1)].emplace(
int(tidx));
927 vert_to_triangles[tria(2)].emplace(
int(tidx));
930 std::vector<int> non_manifold_verts;
931 for (
int vidx = 0; vidx < int(getVerticeSize()); ++vidx) {
932 const auto &triangles = vert_to_triangles[vidx];
933 if (triangles.size() == 0) {
938 std::unordered_map<int, std::unordered_set<int>> edges;
939 for (
int tidx : triangles) {
940 const auto &triangle = getTriangle(
static_cast<size_t>(tidx));
941 if (triangle(0) != vidx && triangle(1) != vidx) {
942 edges[triangle(0)].emplace(triangle(1));
943 edges[triangle(1)].emplace(triangle(0));
944 }
else if (triangle(0) != vidx && triangle(2) != vidx) {
945 edges[triangle(0)].emplace(triangle(2));
946 edges[triangle(2)].emplace(triangle(0));
947 }
else if (triangle(1) != vidx && triangle(2) != vidx) {
948 edges[triangle(1)].emplace(triangle(2));
949 edges[triangle(2)].emplace(triangle(1));
954 std::queue<int>
next;
955 std::unordered_set<int> visited;
956 next.push(edges.begin()->first);
957 visited.emplace(edges.begin()->first);
958 while (!
next.empty()) {
959 int vert =
next.front();
962 for (
auto nb : edges[vert]) {
963 if (visited.count(nb) == 0) {
969 if (visited.size() != edges.size()) {
970 non_manifold_verts.push_back(vidx);
974 return non_manifold_verts;
978 return GetNonManifoldVertices().empty();
982 std::vector<Eigen::Vector2i> self_intersecting_triangles;
983 for (
size_t tidx0 = 0; tidx0 <
size() - 1; ++tidx0) {
985 const Eigen::Vector3d &p0 = getVertice(
static_cast<size_t>(tria_p(0)));
986 const Eigen::Vector3d &p1 = getVertice(
static_cast<size_t>(tria_p(1)));
987 const Eigen::Vector3d &p2 = getVertice(
static_cast<size_t>(tria_p(2)));
988 for (
size_t tidx1 = tidx0 + 1; tidx1 <
size(); ++tidx1) {
991 if (tria_p(0) == tria_q(0) || tria_p(0) == tria_q(1) ||
992 tria_p(0) == tria_q(2) || tria_p(1) == tria_q(0) ||
993 tria_p(1) == tria_q(1) || tria_p(1) == tria_q(2) ||
994 tria_p(2) == tria_q(0) || tria_p(2) == tria_q(1) ||
995 tria_p(2) == tria_q(2)) {
1000 const Eigen::Vector3d &q0 =
1001 getVertice(
static_cast<size_t>(tria_q(0)));
1002 const Eigen::Vector3d &q1 =
1003 getVertice(
static_cast<size_t>(tria_q(1)));
1004 const Eigen::Vector3d &q2 =
1005 getVertice(
static_cast<size_t>(tria_q(2)));
1008 self_intersecting_triangles.push_back(
1013 return self_intersecting_triangles;
1017 return !GetSelfIntersectingTriangles().empty();
1027 if (!IsBoundingBoxIntersecting(other)) {
1030 for (
size_t tidx0 = 0; tidx0 <
size(); ++tidx0) {
1032 const Eigen::Vector3d &p0 = getVertice(
static_cast<size_t>(tria_p(0)));
1033 const Eigen::Vector3d &p1 = getVertice(
static_cast<size_t>(tria_p(1)));
1034 const Eigen::Vector3d &p2 = getVertice(
static_cast<size_t>(tria_p(2)));
1035 for (
size_t tidx1 = 0; tidx1 < other.
size(); ++tidx1) {
1037 const Eigen::Vector3d &q0 =
1038 other.
getVertice(
static_cast<size_t>(tria_q(0)));
1039 const Eigen::Vector3d &q1 =
1040 other.
getVertice(
static_cast<size_t>(tria_q(1)));
1041 const Eigen::Vector3d &q2 =
1042 other.
getVertice(
static_cast<size_t>(tria_q(2)));
1052 template <
typename F>
1057 edge_to_orientation;
1058 std::unordered_set<int> unvisited_triangles;
1059 std::unordered_map<Eigen::Vector2i, std::unordered_set<int>,
1062 std::queue<int> triangle_queue;
1064 auto VerifyAndAdd = [&](
int vidx0,
int vidx1) {
1066 if (edge_to_orientation.count(key) > 0) {
1067 if (edge_to_orientation.at(key)(0) == vidx0) {
1076 for (
int nb_tidx : adjacent_triangles[edge]) {
1077 triangle_queue.push(nb_tidx);
1081 for (
size_t tidx = 0; tidx < triangles.size(); ++tidx) {
1082 unvisited_triangles.insert(
int(tidx));
1083 const auto &triangle = triangles[tidx];
1084 int vidx0 = triangle(0);
1085 int vidx1 = triangle(1);
1086 int vidx2 = triangle(2);
1095 while (!unvisited_triangles.empty()) {
1097 if (triangle_queue.empty()) {
1098 tidx = *unvisited_triangles.begin();
1100 tidx = triangle_queue.front();
1101 triangle_queue.pop();
1103 if (unvisited_triangles.count(tidx) > 0) {
1104 unvisited_triangles.erase(tidx);
1109 const auto &triangle = triangles[tidx];
1110 int vidx0 = triangle(0);
1111 int vidx1 = triangle(1);
1112 int vidx2 = triangle(2);
1116 bool exist01 = edge_to_orientation.count(key01) > 0;
1117 bool exist12 = edge_to_orientation.count(key12) > 0;
1118 bool exist20 = edge_to_orientation.count(key20) > 0;
1120 if (!(exist01 || exist12 || exist20)) {
1126 if (exist01 && edge_to_orientation.at(key01)(0) == vidx0) {
1129 }
else if (exist12 && edge_to_orientation.at(key12)(0) == vidx1) {
1132 }
else if (exist20 && edge_to_orientation.at(key20)(0) == vidx2) {
1139 if (!VerifyAndAdd(vidx0, vidx1)) {
1142 if (!VerifyAndAdd(vidx1, vidx2)) {
1145 if (!VerifyAndAdd(vidx2, vidx0)) {
1150 AddTriangleNbsToQueue(key01);
1151 AddTriangleNbsToQueue(key12);
1152 AddTriangleNbsToQueue(key20);
1158 auto NoOp = [](int, int, int) {};
1163 return IsEdgeManifold(
false) && IsVertexManifold() && !IsSelfIntersecting();
1167 auto SwapTriangleOrder = [&](
int tidx,
int idx0,
int idx1) {
1168 std::swap(getTriangleVertIndexes(
static_cast<unsigned>(tidx))->i[idx0],
1169 getTriangleVertIndexes(
static_cast<unsigned>(tidx))->i[idx1]);
1174 std::tuple<std::vector<int>, std::vector<size_t>, std::vector<double>>
1176 std::vector<int> triangle_clusters(this->
size(), -1);
1177 std::vector<size_t> num_triangles;
1178 std::vector<double> areas;
1182 std::vector<std::unordered_set<int>> adjacency_list(this->
size());
1184 #pragma omp parallel for schedule(static) \
1185 num_threads(utility::EstimateMaxThreads())
1187 for (
int tidx = 0; tidx < int(
size()); ++tidx) {
1188 const auto &triangle = getTriangle(
static_cast<size_t>(tidx));
1191 adjacency_list[tidx].insert(tnb);
1195 adjacency_list[tidx].insert(tnb);
1199 adjacency_list[tidx].insert(tnb);
1203 "[ClusterConnectedTriangles] Done computing triangle adjacency");
1205 int cluster_idx = 0;
1206 for (
int tidx = 0; tidx < int(this->
size()); ++tidx) {
1207 if (triangle_clusters[tidx] != -1) {
1211 std::queue<int> triangle_queue;
1212 int cluster_n_triangles = 0;
1213 double cluster_area = 0;
1215 triangle_queue.push(tidx);
1216 triangle_clusters[tidx] = cluster_idx;
1217 while (!triangle_queue.empty()) {
1218 int cluster_tidx = triangle_queue.front();
1219 triangle_queue.pop();
1221 cluster_n_triangles++;
1222 cluster_area += GetTriangleArea(cluster_tidx);
1224 for (
auto tnb : adjacency_list[cluster_tidx]) {
1225 if (triangle_clusters[tnb] == -1) {
1226 triangle_queue.push(tnb);
1227 triangle_clusters[tnb] = cluster_idx;
1232 num_triangles.push_back(cluster_n_triangles);
1233 areas.push_back(cluster_area);
1238 "[ClusterConnectedTriangles] Done clustering, #clusters={}",
1240 return std::make_tuple(triangle_clusters, num_triangles, areas);
1244 const std::vector<size_t> &triangle_indices) {
1245 std::vector<bool> triangle_mask(
size(),
false);
1246 for (
auto tidx : triangle_indices) {
1247 if (tidx >= 0 && tidx <
size()) {
1248 triangle_mask[tidx] =
true;
1251 "[RemoveTriangles] contains triangle index {} that is not "
1252 "within the bounds",
1257 RemoveTrianglesByMask(triangle_mask);
1261 if (triangle_mask.size() != this->size()) {
1265 bool has_tri_normal = hasTriNormals();
1267 for (
size_t from_tidx = 0; from_tidx < this->
size(); ++from_tidx) {
1268 if (!triangle_mask[from_tidx]) {
1269 setTriangle(to_tidx, getTriangle(from_tidx));
1270 if (has_tri_normal) {
1271 setTriangleNorm(to_tidx, getTriangleNorm(from_tidx));
1277 this->resize(to_tidx);
1278 if (has_tri_normal) {
1279 getTriNormsTable()->resize(to_tidx);
1284 std::vector<bool> vertex_mask(getVerticeSize(),
false);
1285 for (
auto vidx : vertex_indices) {
1286 if (vidx >= 0 && vidx < getVerticeSize()) {
1287 vertex_mask[vidx] =
true;
1290 "[RemoveVerticessByIndex] contains vertex index {} that is "
1291 "not within the bounds",
1296 RemoveVerticesByMask(vertex_mask);
1303 if (vertex_mask.size() != cloud->
size()) {
1310 std::unordered_map<int, int> vertex_map;
1311 for (
unsigned from_vidx = 0; from_vidx < cloud->
size(); ++from_vidx) {
1312 if (!vertex_mask[from_vidx]) {
1313 vertex_map[
static_cast<int>(from_vidx)] =
static_cast<int>(to_vidx);
1328 std::vector<bool> triangle_mask(this->
size());
1329 for (
unsigned tidx = 0; tidx < this->
size(); ++tidx) {
1331 triangle_mask[tidx] = vertex_mask[tria->
i[0]] ||
1332 vertex_mask[tria->
i[1]] ||
1333 vertex_mask[tria->
i[2]];
1334 if (!triangle_mask[tidx]) {
1335 tria->
i[0] = vertex_map[tria->
i[0]];
1336 tria->
i[1] = vertex_map[tria->
i[1]];
1337 tria->
i[2] = vertex_map[tria->
i[2]];
1340 RemoveTrianglesByMask(triangle_mask);
1351 double min_weight)
const {
1356 for (
const auto &edge_v2s : edges_to_vertices) {
1358 double weight_sum = 0;
1360 for (
int v2 : edge_v2s.second) {
1361 Eigen::Vector3d
a = getVertice(
static_cast<size_t>(edge(0))) -
1362 getVertice(
static_cast<size_t>(v2));
1363 Eigen::Vector3d b = getVertice(
static_cast<size_t>(edge(1))) -
1364 getVertice(
static_cast<size_t>(v2));
1366 double weight =
a.dot(b) / (
a.cross(b)).norm();
1367 weight_sum += weight;
1370 double weight = N > 0 ? weight_sum / N : 0;
1371 if (weight < min_weight) {
1372 weights[edge] = min_weight;
1374 weights[edge] = weight;
1381 computePerTriangleNormals();
1389 if (!hasTriNormals()) {
1390 ComputeTriangleNormals(
false);
1392 computePerVertexNormals();
1406 if (hasTriNormals()) {
1407 for (
size_t i = 0; i < m_triNormals->size(); ++i) {
1417 adjacency_list_.
clear();
1418 adjacency_list_.resize(getVerticeSize());
1419 for (
size_t i = 0; i <
size(); ++i) {
1421 adjacency_list_[triangle(0)].insert(triangle(1));
1422 adjacency_list_[triangle(0)].insert(triangle(2));
1423 adjacency_list_[triangle(1)].insert(triangle(0));
1424 adjacency_list_[triangle(1)].insert(triangle(2));
1425 adjacency_list_[triangle(2)].insert(triangle(0));
1426 adjacency_list_[triangle(2)].insert(triangle(1));
1432 size_t number_of_points,
1433 double init_factor ,
1434 const std::shared_ptr<ccPointCloud> pcl_init ,
1435 bool use_triangle_normal ,
1437 if (number_of_points <= 0) {
1442 "[SamplePointsPoissonDisk] input mesh has no triangles");
1444 if (pcl_init ==
nullptr && init_factor < 1) {
1446 "[SamplePointsPoissonDisk] either pass pcl_init with #points "
1447 "> number_of_points or init_factor > 1");
1449 if (pcl_init !=
nullptr && pcl_init->size() < number_of_points) {
1451 "[SamplePointsPoissonDisk] either pass pcl_init with #points "
1452 "> number_of_points, or init_factor > 1");
1456 std::vector<double> triangle_areas;
1457 double surface_area = GetSurfaceArea(triangle_areas);
1460 std::shared_ptr<ccPointCloud>
pcl;
1461 if (pcl_init ==
nullptr) {
1462 pcl = SamplePointsUniformlyImpl(
size_t(init_factor * number_of_points),
1463 triangle_areas, surface_area,
1464 use_triangle_normal, seed);
1466 pcl = std::make_shared<ccPointCloud>();
1474 double ratio = double(number_of_points) / double(
pcl->size());
1475 double r_max = 2 * std::sqrt((surface_area / number_of_points) /
1476 (2 * std::sqrt(3.)));
1477 double r_min = r_max * beta * (1 - std::pow(ratio, gamma));
1479 std::vector<double> weights(
pcl->size());
1480 std::vector<bool> deleted(
pcl->size(),
false);
1483 auto WeightFcn = [&](
double d2) {
1484 double d = std::sqrt(d2);
1488 return std::pow(1 - d / r_max, alpha);
1491 auto ComputePointWeight = [&](
int pidx0) {
1492 std::vector<int> nbs;
1493 std::vector<double> dists2;
1495 r_max, nbs, dists2);
1497 for (
size_t nbidx = 0; nbidx < nbs.size(); ++nbidx) {
1498 int pidx1 = nbs[nbidx];
1500 if (pidx0 == pidx1 || deleted[pidx1]) {
1503 weight += WeightFcn(dists2[nbidx]);
1506 weights[pidx0] = weight;
1510 typedef std::tuple<int, double> QueueEntry;
1511 auto WeightCmp = [](
const QueueEntry &
a,
const QueueEntry &b) {
1512 return std::get<1>(
a) < std::get<1>(b);
1514 std::priority_queue<QueueEntry, std::vector<QueueEntry>,
1515 decltype(WeightCmp)>
1517 for (
size_t pidx0 = 0; pidx0 <
pcl->size(); ++pidx0) {
1518 ComputePointWeight(
int(pidx0));
1519 queue.push(QueueEntry(
int(pidx0), weights[pidx0]));
1523 size_t current_number_of_points =
pcl->size();
1524 while (current_number_of_points > number_of_points) {
1527 std::tie(pidx, weight) = queue.top();
1531 if (deleted[pidx] || weight != weights[pidx]) {
1536 deleted[pidx] =
true;
1537 current_number_of_points--;
1540 std::vector<int> nbs;
1541 std::vector<double> dists2;
1543 r_max, nbs, dists2);
1544 for (
int nb : nbs) {
1545 ComputePointWeight(nb);
1546 queue.push(QueueEntry(nb, weights[nb]));
1551 bool has_vert_normal =
pcl->hasNormals();
1552 bool has_vert_color =
pcl->hasColors();
1553 bool has_textures_ = hasTextures();
1554 bool has_triangle_uvs_ = hasTriangleUvs();
1555 size_t next_free = 0;
1556 for (
size_t idx = 0; idx <
pcl->size(); ++idx) {
1557 if (!deleted[idx]) {
1558 pcl->setPoint(next_free,
1559 *
pcl->getPoint(
static_cast<unsigned>(idx)));
1560 if (has_vert_normal) {
1561 pcl->setPointNormal(
1563 pcl->getPointNormal(
static_cast<unsigned>(idx)));
1565 if (has_vert_color || (has_textures_ && has_triangle_uvs_)) {
1567 static_cast<unsigned>(next_free),
1568 pcl->getPointColor(
static_cast<unsigned>(idx)));
1575 pcl->resize(
static_cast<unsigned>(next_free));
1576 if (has_vert_normal) {
1577 pcl->resizeTheNormsTable();
1579 if (has_vert_color) {
1580 pcl->resizeTheRGBTable();
1590 std::unordered_map<Eigen::Vector2i, std::vector<int>,
1593 auto AddEdge = [&](
int vidx0,
int vidx1,
int tidx) {
1598 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
1599 getTriangleVertIndexes(tidx, triangle);
1600 AddEdge(triangle(0), triangle(1),
int(tidx));
1601 AddEdge(triangle(1), triangle(2),
int(tidx));
1602 AddEdge(triangle(2), triangle(0),
int(tidx));
1604 return trias_per_edge;
1611 std::unordered_map<Eigen::Vector2i, std::vector<int>,
1614 auto AddEdge = [&](
int vidx0,
int vidx1,
int vidx2) {
1619 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
1620 getTriangleVertIndexes(tidx, triangle);
1621 AddEdge(triangle(0), triangle(1), triangle(2));
1622 AddEdge(triangle(1), triangle(2), triangle(0));
1623 AddEdge(triangle(2), triangle(0), triangle(1));
1625 return trias_per_edge;
1629 const Eigen::Vector3d &p1,
1630 const Eigen::Vector3d &p2) {
1631 const Eigen::Vector3d
x = p0 - p1;
1632 const Eigen::Vector3d
y = p0 - p2;
1633 double area = 0.5 *
x.cross(
y).norm();
1638 Eigen::Vector3d vertex0, vertex1, vertex2;
1639 getTriangleVertices(
static_cast<unsigned int>(triangle_idx), vertex0.data(),
1640 vertex1.data(), vertex2.data());
1641 return ComputeTriangleArea(vertex0, vertex1, vertex2);
1645 double surface_area = 0;
1646 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
1647 double triangle_area = GetTriangleArea(tidx);
1648 surface_area += triangle_area;
1650 return surface_area;
1654 double surface_area = 0;
1655 triangle_areas.resize(
size());
1656 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
1657 double triangle_area = GetTriangleArea(tidx);
1658 triangle_areas[tidx] = triangle_area;
1659 surface_area += triangle_area;
1661 return surface_area;
1669 auto GetSignedVolumeOfTriangle = [&](
size_t tidx) {
1671 const Eigen::Vector3d &vertex0 = getVertice(triangle(0));
1672 const Eigen::Vector3d &vertex1 = getVertice(triangle(1));
1673 const Eigen::Vector3d &vertex2 = getVertice(triangle(2));
1674 return vertex0.dot(vertex1.cross(vertex2)) / 6.0;
1677 if (!IsWatertight()) {
1679 "The mesh is not watertight, and the volume cannot be "
1682 if (!IsOrientable()) {
1684 "The mesh is not orientable, and the volume cannot be "
1689 std::int64_t num_triangles =
static_cast<std::int64_t
>(this->
size());
1690 #pragma omp parallel for reduction(+ : volume)
1691 for (std::int64_t tidx = 0; tidx < num_triangles; ++tidx) {
1692 volume += GetSignedVolumeOfTriangle(tidx);
1694 return std::abs(volume);
1698 const Eigen::Vector3d &p1,
1699 const Eigen::Vector3d &p2) {
1700 const Eigen::Vector3d e0 = p1 - p0;
1701 const Eigen::Vector3d e1 = p2 - p0;
1702 Eigen::Vector3d abc = e0.cross(e1);
1703 double norm = abc.norm();
1706 return Eigen::Vector4d(0, 0, 0, 0);
1709 double d = -abc.dot(p0);
1710 return Eigen::Vector4d(abc(0), abc(1), abc(2), d);
1714 Eigen::Vector3d vertex0, vertex1, vertex2;
1715 getTriangleVertices(
static_cast<unsigned int>(triangle_idx), vertex0.data(),
1716 vertex1.data(), vertex2.data());
1717 return ComputeTrianglePlane(vertex0, vertex1, vertex2);
1721 size_t number_of_points,
1722 std::vector<double> &triangle_areas,
1723 double surface_area,
1724 bool use_triangle_normal,
1727 triangle_areas[0] /= surface_area;
1728 for (
size_t tidx = 1; tidx <
size(); ++tidx) {
1729 triangle_areas[tidx] =
1730 triangle_areas[tidx] / surface_area + triangle_areas[tidx - 1];
1734 bool has_vert_normal = m_associatedCloud->hasNormals();
1735 bool has_vert_color = m_associatedCloud->hasColors();
1736 bool has_textures_ = hasTextures();
1737 bool has_triangle_uvs_ = hasTriangleUvs();
1738 bool has_triangle_material_ids_ = hasTriangleMaterialIds();
1740 std::random_device rd;
1743 std::mt19937 mt(seed);
1744 std::uniform_real_distribution<double> dist(0.0, 1.0);
1745 auto pcd = std::make_shared<ccPointCloud>();
1746 pcd->resize(
static_cast<unsigned>(number_of_points));
1747 if (has_vert_normal || use_triangle_normal) {
1748 pcd->resizeTheNormsTable();
1750 if (use_triangle_normal && !hasTriNormals()) {
1753 if (has_vert_color || (has_textures_ && has_triangle_uvs_)) {
1754 pcd->resizeTheRGBTable();
1756 size_t point_idx = 0;
1757 for (
size_t tidx = 0; tidx <
size(); ++tidx) {
1758 size_t n = size_t(std::round(triangle_areas[tidx] * number_of_points));
1759 while (point_idx < n) {
1760 double r1 = dist(mt);
1761 double r2 = dist(mt);
1762 double a = (1 - std::sqrt(r1));
1763 double b = std::sqrt(r1) * (1 - r2);
1764 double c = std::sqrt(r1) * r2;
1766 Eigen::Vector3d vert0, vert1, vert2;
1767 getTriangleVertices(
static_cast<unsigned int>(tidx), vert0.data(),
1768 vert1.data(), vert2.data());
1769 Eigen::Vector3d temp =
a * vert0 + b * vert1 + c * vert2;
1770 pcd->setPoint(point_idx, temp);
1772 assert(m_associatedCloud);
1775 getTriangleVertIndexes(
static_cast<unsigned int>(tidx));
1777 if (has_vert_normal && !use_triangle_normal) {
1781 pcd->setPointNormal(point_idx, N);
1783 if (use_triangle_normal) {
1784 pcd->setPointNormal(point_idx, getTriangleNorm(tidx));
1787 if (has_vert_color && !has_textures_ && !has_triangle_uvs_) {
1791 pcd->setPointColor(point_idx, C);
1795 if (has_textures_ && has_triangle_uvs_ &&
1796 has_triangle_material_ids_) {
1797 Eigen::Vector2d
uv =
a * triangle_uvs_[3 * tidx] +
1798 b * triangle_uvs_[3 * tidx + 1] +
1799 c * triangle_uvs_[3 * tidx + 2];
1800 int material_id = triangle_material_ids_[tidx];
1801 int w = textures_[material_id].width_;
1802 int h = textures_[material_id].height_;
1807 (
double)*(textures_[material_id]
1808 .PointerAt<uint8_t>(
uv(0) * w,
1812 (
double)*(textures_[material_id]
1813 .PointerAt<uint8_t>(
uv(0) * w,
1817 (
double)*(textures_[material_id]
1818 .PointerAt<uint8_t>(
uv(0) * w,
1832 size_t number_of_points,
1833 bool use_triangle_normal ,
1835 if (number_of_points <= 0) {
1840 "[SamplePointsUniformly] input mesh has no triangles");
1844 std::vector<double> triangle_areas;
1845 double surface_area = GetSurfaceArea(triangle_areas);
1847 return SamplePointsUniformlyImpl(number_of_points, triangle_areas,
1848 surface_area, use_triangle_normal, seed);
1852 double radius ,
bool create_uv_map ) {
1854 assert(baseVertices);
1855 auto mesh = std::make_shared<ccMesh>(baseVertices);
1862 radius * Eigen::Vector3d(std::sqrt(8. / 9.), 0, -1. / 3.));
1863 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-std::sqrt(2. / 9.),
1866 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-std::sqrt(2. / 9.),
1867 -std::sqrt(2. / 3.),
1869 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0., 0., 1.));
1878 if (create_uv_map) {
1879 mesh->triangle_uvs_ = {{0.866, 0.5}, {0.433, 0.75}, {0.433, 0.25},
1880 {0.866, 0.5}, {0.866, 1.0}, {0.433, 0.75},
1881 {0.866, 0.5}, {0.433, 0.25}, {0.866, 0.0},
1882 {0.433, 0.25}, {0.433, 0.75}, {0.0, 0.5}};
1888 mesh->shrinkToFit();
1898 mesh->addChild(baseVertices);
1903 double radius ,
bool create_uv_map ) {
1905 assert(baseVertices);
1906 auto mesh = std::make_shared<ccMesh>(baseVertices);
1913 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(1, 0, 0));
1914 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, 1, 0));
1915 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, 0, 1));
1916 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-1, 0, 0));
1917 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, -1, 0));
1918 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, 0, -1));
1931 if (create_uv_map) {
1932 mesh->triangle_uvs_ = {
1933 {0.0, 0.75}, {0.1444, 0.5}, {0.2887, 0.75}, {0.1444, 0.5},
1934 {0.433, 0.5}, {0.2887, 0.75}, {0.433, 0.5}, {0.5773, 0.75},
1935 {0.2887, 0.75}, {0.5773, 0.75}, {0.433, 1.0}, {0.2887, 0.75},
1936 {0.0, 0.25}, {0.2887, 0.25}, {0.1444, 0.5}, {0.1444, 0.5},
1937 {0.2887, 0.25}, {0.433, 0.5}, {0.433, 0.5}, {0.2887, 0.25},
1938 {0.5773, 0.25}, {0.5773, 0.25}, {0.2887, 0.25}, {0.433, 0.0}};
1944 mesh->shrinkToFit();
1954 mesh->addChild(baseVertices);
1960 double radius ,
bool create_uv_map ) {
1962 assert(baseVertices);
1963 auto mesh = std::make_shared<ccMesh>(baseVertices);
1967 const double p = (1. + std::sqrt(5.)) / 2.;
1970 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-1, 0, p));
1971 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(1, 0, p));
1972 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(1, 0, -p));
1973 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-1, 0, -p));
1974 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, -p, 1));
1975 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, p, 1));
1976 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, p, -1));
1977 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(0, -p, -1));
1978 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-p, -1, 0));
1979 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(p, -1, 0));
1980 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(p, 1, 0));
1981 baseVertices->
addEigenPoint(radius * Eigen::Vector3d(-p, 1, 0));
2006 if (create_uv_map) {
2007 mesh->triangle_uvs_ = {
2008 {0.0001, 0.1819}, {0.1575, 0.091}, {0.1575, 0.2728},
2009 {0.0001, 0.3637}, {0.1575, 0.2728}, {0.1575, 0.4546},
2010 {0.1575, 0.2728}, {0.1575, 0.091}, {0.3149, 0.1819},
2011 {0.1575, 0.2728}, {0.3149, 0.1819}, {0.3149, 0.3637},
2012 {0.1575, 0.2728}, {0.3149, 0.3637}, {0.1575, 0.4546},
2013 {0.0001, 0.909}, {0.1575, 0.8181}, {0.1575, 0.9999},
2014 {0.0001, 0.7272}, {0.1575, 0.6363}, {0.1575, 0.8181},
2015 {0.0001, 0.5454}, {0.1575, 0.4546}, {0.1575, 0.6363},
2016 {0.1575, 0.4546}, {0.3149, 0.5454}, {0.1575, 0.6363},
2017 {0.1575, 0.4546}, {0.3149, 0.3637}, {0.3149, 0.5454},
2018 {0.1575, 0.9999}, {0.1575, 0.8181}, {0.3149, 0.909},
2019 {0.1575, 0.091}, {0.3149, 0.0001}, {0.3149, 0.1819},
2020 {0.3149, 0.7272}, {0.3149, 0.5454}, {0.4724, 0.6363},
2021 {0.3149, 0.7272}, {0.4724, 0.8181}, {0.3149, 0.909},
2022 {0.4724, 0.4546}, {0.3149, 0.5454}, {0.3149, 0.3637},
2023 {0.4724, 0.2728}, {0.3149, 0.3637}, {0.3149, 0.1819},
2024 {0.4724, 0.091}, {0.3149, 0.1819}, {0.3149, 0.0001},
2025 {0.3149, 0.7272}, {0.1575, 0.6363}, {0.3149, 0.5454},
2026 {0.3149, 0.7272}, {0.1575, 0.8181}, {0.1575, 0.6363},
2027 {0.3149, 0.7272}, {0.3149, 0.909}, {0.1575, 0.8181}};
2033 mesh->shrinkToFit();
2043 mesh->addChild(baseVertices);
2049 bool create_uv_map ) {
2051 assert(baseVertices);
2052 auto mesh = std::make_shared<ccMesh>(baseVertices);
2063 if (!baseVertices->
resize(4)) {
2077 mesh->shrinkToFit();
2087 mesh->addChild(baseVertices);
2095 bool create_uv_map ,
2096 bool map_texture_to_each_face ) {
2098 assert(baseVertices);
2099 auto mesh = std::make_shared<ccMesh>(baseVertices);
2111 if (!baseVertices->
resize(8)) {
2114 *baseVertices->
getPointPtr(0) = Eigen::Vector3d(0.0, 0.0, 0.0);
2116 *baseVertices->
getPointPtr(2) = Eigen::Vector3d(0.0, 0.0, depth);
2138 if (create_uv_map) {
2139 if (map_texture_to_each_face) {
2140 mesh->triangle_uvs_ = {
2141 {0.0, 0.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}, {0.0, 1.0},
2142 {1.0, 1.0}, {0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {0.0, 1.0},
2143 {1.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0},
2144 {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}, {1.0, 0.0},
2145 {1.0, 1.0}, {0.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0},
2146 {1.0, 0.0}, {1.0, 1.0}, {0.0, 0.0}, {1.0, 1.0}, {0.0, 1.0},
2147 {0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 0.0}, {0.0, 1.0},
2150 mesh->triangle_uvs_ = {
2151 {0.5, 0.5}, {0.75, 0.75}, {0.5, 0.75}, {0.5, 0.5},
2152 {0.75, 0.5}, {0.75, 0.75}, {0.25, 0.5}, {0.25, 0.25},
2153 {0.5, 0.5}, {0.25, 0.25}, {0.5, 0.25}, {0.5, 0.5},
2154 {0.25, 0.5}, {0.25, 0.75}, {0.0, 0.5}, {0.25, 0.75},
2155 {0.0, 0.75}, {0.0, 0.5}, {0.25, 0.75}, {0.5, 0.75},
2156 {0.5, 1.0}, {0.25, 0.75}, {0.5, 1.0}, {0.25, 1.0},
2157 {0.25, 0.25}, {0.25, 0.0}, {0.5, 0.0}, {0.25, 0.25},
2158 {0.5, 0.0}, {0.5, 0.25}, {0.25, 0.5}, {0.5, 0.5},
2159 {0.25, 0.75}, {0.25, 0.75}, {0.5, 0.5}, {0.5, 0.75}};
2166 mesh->shrinkToFit();
2176 mesh->addChild(baseVertices);
2182 bool create_uv_map ) {
2184 assert(baseVertices);
2185 auto mesh = std::make_shared<ccMesh>(baseVertices);
2190 if (resolution <= 0) {
2194 if (!baseVertices->
resize(2 * resolution * (resolution - 1) + 2)) {
2198 std::unordered_map<int64_t, std::pair<double, double>> map_vertices_to_uv;
2199 std::unordered_map<int64_t, std::pair<double, double>>
2200 map_cut_vertices_to_uv;
2202 *baseVertices->
getPointPtr(0) = Eigen::Vector3d(0.0, 0.0, radius);
2203 *baseVertices->
getPointPtr(1) = Eigen::Vector3d(0.0, 0.0, -radius);
2204 double step =
M_PI / (double)resolution;
2205 for (
int i = 1; i < resolution; i++) {
2206 double alpha = step * i;
2207 double uv_row = (1.0 / (resolution)) * i;
2208 int base = 2 + 2 * resolution * (i - 1);
2209 for (
int j = 0; j < 2 * resolution; j++) {
2210 double theta = step * j;
2211 double uv_col = (1.0 / (2.0 * resolution)) * j;
2212 Eigen::Vector3d temp =
2213 Eigen::Vector3d(sin(alpha) * cos(theta),
2214 sin(alpha) * sin(theta), cos(alpha)) *
2216 baseVertices->
setEigenPoint(
static_cast<std::size_t
>(base + j),
2218 if (create_uv_map) {
2222 if (create_uv_map) {
2228 for (
int j = 0; j < 2 * resolution; j++) {
2229 int j1 = (j + 1) % (2 * resolution);
2232 base = 2 + 2 * resolution * (resolution - 2);
2237 if (create_uv_map) {
2238 for (
int j = 0; j < 2 * resolution - 1; j++) {
2239 int j1 = (j + 1) % (2 * resolution);
2241 double width = 1.0 / (2.0 * resolution);
2242 double base_offset =
width / 2.0;
2243 double uv_col = base_offset +
width * j;
2244 mesh->triangle_uvs_.emplace_back(0.0, uv_col);
2245 mesh->triangle_uvs_.emplace_back(
2246 Eigen::Vector2d(map_vertices_to_uv[base + j].first,
2247 map_vertices_to_uv[base + j].second));
2248 mesh->triangle_uvs_.emplace_back(
2249 Eigen::Vector2d(map_vertices_to_uv[base + j1].first,
2250 map_vertices_to_uv[base + j1].second));
2252 base = 2 + 2 * resolution * (resolution - 2);
2253 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(1.0, uv_col));
2254 mesh->triangle_uvs_.emplace_back(
2255 Eigen::Vector2d(map_vertices_to_uv[base + j1].first,
2256 map_vertices_to_uv[base + j1].second));
2257 mesh->triangle_uvs_.emplace_back(
2258 Eigen::Vector2d(map_vertices_to_uv[base + j].first,
2259 map_vertices_to_uv[base + j].second));
2263 int j = 2 * resolution - 1;
2265 double width = 1.0 / (2.0 * resolution);
2266 double base_offset =
width / 2.0;
2267 double uv_col = base_offset +
width * j;
2268 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(0.0, uv_col));
2269 mesh->triangle_uvs_.emplace_back(
2270 Eigen::Vector2d(map_vertices_to_uv[base + j].first,
2271 map_vertices_to_uv[base + j].second));
2272 mesh->triangle_uvs_.emplace_back(
2273 Eigen::Vector2d(map_cut_vertices_to_uv[base].first,
2274 map_cut_vertices_to_uv[base].second));
2276 base = 2 + 2 * resolution * (resolution - 2);
2277 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(1.0, uv_col));
2278 mesh->triangle_uvs_.emplace_back(
2279 Eigen::Vector2d(map_cut_vertices_to_uv[base].first,
2280 map_cut_vertices_to_uv[base].second));
2281 mesh->triangle_uvs_.emplace_back(
2282 Eigen::Vector2d(map_vertices_to_uv[base + j].first,
2283 map_vertices_to_uv[base + j].second));
2287 for (
int i = 1; i < resolution - 1; i++) {
2288 int base1 = 2 + 2 * resolution * (i - 1);
2289 int base2 = base1 + 2 * resolution;
2290 for (
int j = 0; j < 2 * resolution; j++) {
2291 int j1 = (j + 1) % (2 * resolution);
2300 if (create_uv_map) {
2301 for (
int i = 1; i < resolution - 1; i++) {
2302 int base1 = 2 + 2 * resolution * (i - 1);
2303 int base2 = base1 + 2 * resolution;
2304 for (
int j = 0; j < 2 * resolution - 1; j++) {
2305 int j1 = (j + 1) % (2 * resolution);
2306 mesh->triangle_uvs_.emplace_back(
2307 map_vertices_to_uv[base2 + j].first,
2308 map_vertices_to_uv[base2 + j].second);
2309 mesh->triangle_uvs_.emplace_back(
2310 Eigen::Vector2d(map_vertices_to_uv[base1 + j1].first,
2311 map_vertices_to_uv[base1 + j1].second));
2312 mesh->triangle_uvs_.emplace_back(
2313 Eigen::Vector2d(map_vertices_to_uv[base1 + j].first,
2314 map_vertices_to_uv[base1 + j].second));
2316 mesh->triangle_uvs_.emplace_back(
2317 Eigen::Vector2d(map_vertices_to_uv[base2 + j].first,
2318 map_vertices_to_uv[base2 + j].second));
2319 mesh->triangle_uvs_.emplace_back(
2320 Eigen::Vector2d(map_vertices_to_uv[base2 + j1].first,
2321 map_vertices_to_uv[base2 + j1].second));
2322 mesh->triangle_uvs_.emplace_back(
2323 Eigen::Vector2d(map_vertices_to_uv[base1 + j1].first,
2324 map_vertices_to_uv[base1 + j1].second));
2329 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2330 map_vertices_to_uv[base2 + 2 * resolution - 1].first,
2331 map_vertices_to_uv[base2 + 2 * resolution - 1].second));
2332 mesh->triangle_uvs_.emplace_back(
2333 Eigen::Vector2d(map_cut_vertices_to_uv[base1].first,
2334 map_cut_vertices_to_uv[base1].second));
2335 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2336 map_vertices_to_uv[base1 + 2 * resolution - 1].first,
2337 map_vertices_to_uv[base1 + 2 * resolution - 1].second));
2339 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2340 map_vertices_to_uv[base2 + 2 * resolution - 1].first,
2341 map_vertices_to_uv[base2 + 2 * resolution - 1].second));
2342 mesh->triangle_uvs_.emplace_back(
2343 Eigen::Vector2d(map_cut_vertices_to_uv[base2].first,
2344 map_cut_vertices_to_uv[base2].second));
2345 mesh->triangle_uvs_.emplace_back(
2346 Eigen::Vector2d(map_cut_vertices_to_uv[base1].first,
2347 map_cut_vertices_to_uv[base1].second));
2354 mesh->shrinkToFit();
2364 mesh->addChild(baseVertices);
2373 bool create_uv_map ) {
2375 assert(baseVertices);
2376 auto mesh = std::make_shared<ccMesh>(baseVertices);
2383 if (resolution <= 0) {
2390 if (!baseVertices->
resize(resolution * (split + 1) + 2)) {
2395 double step =
M_PI * 2.0 / (double)resolution;
2396 double h_step =
height / (double)split;
2397 for (
int i = 0; i <= split; i++) {
2398 for (
int j = 0; j < resolution; j++) {
2399 double theta = step * j;
2401 static_cast<std::size_t
>(2 + resolution * i + j),
2402 Eigen::Vector3d(cos(theta) * radius, sin(theta) * radius,
2403 height * 0.5 - h_step * i));
2407 std::unordered_map<int64_t, std::pair<double, double>> map_vertices_to_uv;
2408 std::unordered_map<int64_t, std::pair<double, double>>
2409 map_cut_vertices_to_uv;
2412 if (create_uv_map) {
2413 for (
int i = 0; i <= split; i++) {
2414 double uv_row = (1.0 / (double)split) * i;
2415 for (
int j = 0; j < resolution; j++) {
2417 double uv_col = (1.0 / (double)resolution) * j;
2418 map_vertices_to_uv[2 + resolution * i + j] =
2421 map_cut_vertices_to_uv[2 + resolution * i] =
2427 for (
int j = 0; j < resolution; j++) {
2428 int j1 = (j + 1) % resolution;
2431 base = 2 + resolution * split;
2436 if (create_uv_map) {
2437 for (
int j = 0; j < resolution; j++) {
2438 int j1 = (j + 1) % resolution;
2439 double theta = step * j;
2440 double theta1 = step * j1;
2441 double uv_radius = 0.25;
2443 mesh->triangle_uvs_.push_back(Eigen::Vector2d(0.75, 0.25));
2444 mesh->triangle_uvs_.push_back(
2445 Eigen::Vector2d(0.75 + uv_radius * cos(theta),
2446 0.25 + uv_radius * sin(theta)));
2447 mesh->triangle_uvs_.push_back(
2448 Eigen::Vector2d(0.75 + uv_radius * cos(theta1),
2449 0.25 + uv_radius * sin(theta1)));
2451 mesh->triangle_uvs_.push_back(Eigen::Vector2d(0.75, 0.75));
2452 mesh->triangle_uvs_.push_back(
2453 Eigen::Vector2d(0.75 + uv_radius * cos(theta1),
2454 0.75 + uv_radius * sin(theta1)));
2455 mesh->triangle_uvs_.push_back(
2456 Eigen::Vector2d(0.75 + uv_radius * cos(theta),
2457 0.75 + uv_radius * sin(theta)));
2462 for (
int i = 0; i < split; i++) {
2463 int base1 = 2 + resolution * i;
2464 int base2 = base1 + resolution;
2465 for (
int j = 0; j < resolution; j++) {
2466 int j1 = (j + 1) % resolution;
2475 if (create_uv_map) {
2476 for (
int i = 0; i < split; i++) {
2477 int base1 = 2 + resolution * i;
2478 int base2 = base1 + resolution;
2479 for (
int j = 0; j < resolution - 1; j++) {
2480 int j1 = (j + 1) % resolution;
2482 mesh->triangle_uvs_.emplace_back(
2483 map_vertices_to_uv[base2 + j].first,
2484 map_vertices_to_uv[base2 + j].second);
2485 mesh->triangle_uvs_.emplace_back(
2486 Eigen::Vector2d(map_vertices_to_uv[base1 + j1].first,
2487 map_vertices_to_uv[base1 + j1].second));
2488 mesh->triangle_uvs_.emplace_back(
2489 Eigen::Vector2d(map_vertices_to_uv[base1 + j].first,
2490 map_vertices_to_uv[base1 + j].second));
2492 mesh->triangle_uvs_.emplace_back(
2493 Eigen::Vector2d(map_vertices_to_uv[base2 + j].first,
2494 map_vertices_to_uv[base2 + j].second));
2495 mesh->triangle_uvs_.emplace_back(
2496 Eigen::Vector2d(map_vertices_to_uv[base2 + j1].first,
2497 map_vertices_to_uv[base2 + j1].second));
2498 mesh->triangle_uvs_.emplace_back(
2499 Eigen::Vector2d(map_vertices_to_uv[base1 + j1].first,
2500 map_vertices_to_uv[base1 + j1].second));
2505 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2506 map_vertices_to_uv[base2 + resolution - 1].first,
2507 map_vertices_to_uv[base2 + resolution - 1].second));
2508 mesh->triangle_uvs_.emplace_back(
2509 Eigen::Vector2d(map_cut_vertices_to_uv[base1].first,
2510 map_cut_vertices_to_uv[base1].second));
2511 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2512 map_vertices_to_uv[base1 + resolution - 1].first,
2513 map_vertices_to_uv[base1 + resolution - 1].second));
2515 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2516 map_vertices_to_uv[base2 + resolution - 1].first,
2517 map_vertices_to_uv[base2 + resolution - 1].second));
2518 mesh->triangle_uvs_.emplace_back(
2519 Eigen::Vector2d(map_cut_vertices_to_uv[base2].first,
2520 map_cut_vertices_to_uv[base2].second));
2521 mesh->triangle_uvs_.emplace_back(
2522 Eigen::Vector2d(map_cut_vertices_to_uv[base1].first,
2523 map_cut_vertices_to_uv[base1].second));
2530 mesh->shrinkToFit();
2540 mesh->addChild(baseVertices);
2548 bool create_uv_map ) {
2550 assert(baseVertices);
2551 auto mesh = std::make_shared<ccMesh>(baseVertices);
2559 if (resolution <= 0) {
2566 if (!baseVertices->
resize(resolution * split + 2)) {
2569 *baseVertices->
getPointPtr(0) = Eigen::Vector3d(0.0, 0.0, 0.0);
2571 double step =
M_PI * 2.0 / (double)resolution;
2572 double h_step =
height / (double)split;
2573 double r_step = radius / (double)split;
2574 std::unordered_map<int64_t, std::pair<double, double>> map_vertices_to_uv;
2575 for (
int i = 0; i < split; i++) {
2576 int base = 2 + resolution * i;
2577 double r = r_step * (split - i);
2578 for (
int j = 0; j < resolution; j++) {
2579 double theta = step * j;
2581 static_cast<std::size_t
>(base + j),
2582 Eigen::Vector3d(cos(theta) * r, sin(theta) * r,
2586 if (create_uv_map) {
2587 double factor = 0.25 * r / radius;
2589 factor * cos(theta), factor * sin(theta));
2594 for (
int j = 0; j < resolution; j++) {
2595 int j1 = (j + 1) % resolution;
2598 base = 2 + resolution * (split - 1);
2602 if (create_uv_map) {
2603 for (
int j = 0; j < resolution; j++) {
2604 int j1 = (j + 1) % resolution;
2607 mesh->triangle_uvs_.push_back(Eigen::Vector2d(0.5, 0.25));
2608 mesh->triangle_uvs_.push_back(Eigen::Vector2d(
2609 0.5 + map_vertices_to_uv[base + j1].first,
2610 0.25 + map_vertices_to_uv[base + j1].second));
2611 mesh->triangle_uvs_.push_back(Eigen::Vector2d(
2612 0.5 + map_vertices_to_uv[base + j].first,
2613 0.25 + map_vertices_to_uv[base + j].second));
2617 base = 2 + resolution * (split - 1);
2618 mesh->triangle_uvs_.push_back(Eigen::Vector2d(0.5, 0.75));
2619 mesh->triangle_uvs_.push_back(Eigen::Vector2d(
2620 0.5 + map_vertices_to_uv[base + j].first,
2621 0.75 + map_vertices_to_uv[base + j].second));
2622 mesh->triangle_uvs_.push_back(Eigen::Vector2d(
2623 0.5 + map_vertices_to_uv[base + j1].first,
2624 0.75 + map_vertices_to_uv[base + j1].second));
2629 for (
int i = 0; i < split - 1; i++) {
2630 int base1 = 2 + resolution * i;
2631 int base2 = base1 + resolution;
2632 for (
int j = 0; j < resolution; j++) {
2633 int j1 = (j + 1) % resolution;
2643 if (create_uv_map) {
2644 for (
int i = 0; i < split - 1; i++) {
2645 int base1 = 2 + resolution * i;
2646 int base2 = base1 + resolution;
2647 for (
int j = 0; j < resolution; j++) {
2648 int j1 = (j + 1) % resolution;
2649 mesh->triangle_uvs_.emplace_back(
2650 0.5 + map_vertices_to_uv[base2 + j1].first,
2651 0.75 + map_vertices_to_uv[base2 + j1].second);
2652 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2653 0.5 + map_vertices_to_uv[base1 + j].first,
2654 0.75 + map_vertices_to_uv[base1 + j].second));
2655 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2656 0.5 + map_vertices_to_uv[base1 + j1].first,
2657 0.75 + map_vertices_to_uv[base1 + j1].second));
2659 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2660 0.5 + map_vertices_to_uv[base2 + j1].first,
2661 0.75 + map_vertices_to_uv[base2 + j1].second));
2662 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2663 0.5 + map_vertices_to_uv[base2 + j].first,
2664 0.75 + map_vertices_to_uv[base2 + j].second));
2665 mesh->triangle_uvs_.emplace_back(Eigen::Vector2d(
2666 0.5 + map_vertices_to_uv[base1 + j].first,
2667 0.75 + map_vertices_to_uv[base1 + j].second));
2675 mesh->shrinkToFit();
2685 mesh->addChild(baseVertices);
2690 double tube_radius ,
2691 int radial_resolution ,
2692 int tubular_resolution ) {
2694 assert(baseVertices);
2695 auto mesh = std::make_shared<ccMesh>(baseVertices);
2697 if (torus_radius <= 0) {
2700 if (tube_radius <= 0) {
2703 if (radial_resolution <= 0) {
2706 if (tubular_resolution <= 0) {
2710 if (!baseVertices->
resize(radial_resolution * tubular_resolution) ||
2711 !mesh->resize(2 * radial_resolution * tubular_resolution)) {
2715 auto vert_idx = [&](
int uidx,
int vidx) {
2716 return uidx * tubular_resolution + vidx;
2718 double u_step = 2 *
M_PI / double(radial_resolution);
2719 double v_step = 2 *
M_PI / double(tubular_resolution);
2720 Eigen::Vector3d temp;
2721 for (
int uidx = 0; uidx < radial_resolution; ++uidx) {
2722 double u = uidx * u_step;
2723 Eigen::Vector3d w(cos(u), sin(u), 0);
2724 for (
int vidx = 0; vidx < tubular_resolution; ++vidx) {
2725 double v = vidx * v_step;
2726 temp = torus_radius * w + tube_radius * cos(v) * w +
2727 Eigen::Vector3d(0, 0, tube_radius * sin(v));
2729 static_cast<unsigned int>(vert_idx(uidx, vidx))) = temp;
2731 int tri_idx = (uidx * tubular_resolution + vidx) * 2;
2733 static_cast<unsigned int>(tri_idx + 0),
2735 vert_idx((uidx + 1) % radial_resolution, vidx),
2736 vert_idx((uidx + 1) % radial_resolution,
2737 (vidx + 1) % tubular_resolution),
2738 vert_idx(uidx, vidx)));
2740 static_cast<unsigned int>(tri_idx + 1),
2742 vert_idx(uidx, vidx),
2743 vert_idx((uidx + 1) % radial_resolution,
2744 (vidx + 1) % tubular_resolution),
2745 vert_idx(uidx, (vidx + 1) % tubular_resolution)));
2752 mesh->shrinkToFit();
2762 mesh->addChild(baseVertices);
2767 double cone_radius ,
2768 double cylinder_height ,
2769 double cone_height ,
2771 int cylinder_split ,
2773 if (cylinder_radius <= 0) {
2776 if (cone_radius <= 0) {
2779 if (cylinder_height <= 0) {
2782 if (cone_height <= 0) {
2785 if (resolution <= 0) {
2788 if (cylinder_split <= 0) {
2791 if (cone_split <= 0) {
2794 Eigen::Matrix4d transformation = Eigen::Matrix4d::Identity();
2795 auto mesh_cylinder = CreateCylinder(cylinder_radius, cylinder_height,
2796 resolution, cylinder_split);
2797 transformation(2, 3) = cylinder_height * 0.5;
2798 mesh_cylinder->Transform(transformation);
2800 CreateCone(cone_radius, cone_height, resolution, cone_split);
2801 transformation(2, 3) = cylinder_height;
2802 mesh_cone->Transform(transformation);
2803 auto mesh_arrow = mesh_cylinder;
2804 *mesh_arrow += *mesh_cone;
2810 const Eigen::Vector3d &
origin ) {
2814 auto mesh_frame = CreateSphere(0.06 *
size);
2815 mesh_frame->ComputeVertexNormals();
2816 mesh_frame->PaintUniformColor(Eigen::Vector3d(0.5, 0.5, 0.5));
2818 std::shared_ptr<ccMesh> mesh_arrow;
2819 Eigen::Matrix4d transformation;
2821 mesh_arrow = CreateArrow(0.035 *
size, 0.06 *
size, 0.8 *
size, 0.2 *
size);
2822 mesh_arrow->ComputeVertexNormals();
2823 mesh_arrow->PaintUniformColor(Eigen::Vector3d(1.0, 0.0, 0.0));
2824 mesh_arrow->showColors(
true);
2825 transformation << 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1;
2826 mesh_arrow->Transform(transformation);
2827 *mesh_frame += *mesh_arrow;
2829 mesh_arrow = CreateArrow(0.035 *
size, 0.06 *
size, 0.8 *
size, 0.2 *
size);
2830 mesh_arrow->ComputeVertexNormals();
2831 mesh_arrow->PaintUniformColor(Eigen::Vector3d(0.0, 1.0, 0.0));
2832 transformation << 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1;
2833 mesh_arrow->Transform(transformation);
2834 *mesh_frame += *mesh_arrow;
2836 mesh_arrow = CreateArrow(0.035 *
size, 0.06 *
size, 0.8 *
size, 0.2 *
size);
2837 mesh_arrow->ComputeVertexNormals();
2838 mesh_arrow->PaintUniformColor(Eigen::Vector3d(0.0, 0.0, 1.0));
2839 transformation << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1;
2840 mesh_arrow->Transform(transformation);
2841 *mesh_frame += *mesh_arrow;
2843 transformation = Eigen::Matrix4d::Identity();
2844 transformation.block<3, 1>(0, 3) =
origin;
2845 mesh_frame->Transform(transformation);
2858 assert(baseVertices);
2859 auto mesh = std::make_shared<ccMesh>(baseVertices);
2861 if (length_split <= 0) {
2864 if (width_split <= 0) {
2873 if (flatness == 0) {
2883 if (!baseVertices->
resize(length_split * width_split)) {
2887 double u_step = 2 *
M_PI / length_split;
2888 double v_step =
width / (width_split - 1);
2889 for (
int uidx = 0; uidx < length_split; ++uidx) {
2890 double u = uidx * u_step;
2891 double cos_u = std::cos(u);
2892 double sin_u = std::sin(u);
2893 for (
int vidx = 0; vidx < width_split; ++vidx) {
2895 static_cast<unsigned int>(uidx * width_split + vidx);
2896 double v = -
width / 2.0 + vidx * v_step;
2897 double alpha = twists * 0.5 * u;
2898 double cos_alpha = std::cos(alpha);
2899 double sin_alpha = std::sin(alpha);
2902 scale * ((cos_alpha * cos_u * v) + radius * cos_u));
2905 scale * ((cos_alpha * sin_u * v) + radius * sin_u));
2912 for (
int uidx = 0; uidx < length_split - 1; ++uidx) {
2913 for (
int vidx = 0; vidx < width_split - 1; ++vidx) {
2914 if ((uidx + vidx) % 2 == 0) {
2917 (uidx + 1) * width_split + vidx + 1,
2918 uidx * width_split + vidx + 1));
2921 (uidx + 1) * width_split + vidx,
2922 (uidx + 1) * width_split + vidx + 1));
2926 uidx * width_split + vidx,
2927 (uidx + 1) * width_split + vidx));
2930 (uidx + 1) * width_split + vidx,
2931 (uidx + 1) * width_split + vidx + 1));
2936 int uidx = length_split - 1;
2937 for (
int vidx = 0; vidx < width_split - 1; ++vidx) {
2938 if (twists % 2 == 1) {
2939 if ((uidx + vidx) % 2 == 0) {
2942 uidx * width_split + vidx,
2943 uidx * width_split + vidx + 1));
2945 (width_split - 1) - vidx, uidx * width_split + vidx,
2946 (width_split - 1) - (vidx + 1)));
2949 uidx * width_split + vidx + 1,
2950 (width_split - 1) - vidx));
2952 (width_split - 1) - vidx, uidx * width_split + vidx + 1,
2953 (width_split - 1) - (vidx + 1)));
2956 if ((uidx + vidx) % 2 == 0) {
2959 uidx * width_split + vidx + 1));
2965 uidx * width_split + vidx + 1));
2975 mesh->shrinkToFit();
2985 mesh->addChild(baseVertices);
float PointCoordinateType
Type of the coordinates of a (N-D) point.
bool OrientTriangleHelper(const std::vector< Eigen::Vector3i > &triangles, F &swap)
Array of RGB colors for each point.
Array of compressed 3D normals (single index)
void normalize()
Sets vector norm to unity.
Type & getValue(size_t index)
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
bool IsIntersecting(const ccMesh &other) const
std::shared_ptr< ccPointCloud > SamplePointsPoissonDisk(size_t number_of_points, double init_factor=5, const std::shared_ptr< ccPointCloud > pcl_init=nullptr, bool use_triangle_normal=false, int seed=-1)
double GetTriangleArea(size_t triangle_idx) const
std::vector< int > GetNonManifoldVertices() const
ccMesh & NormalizeNormals()
static std::shared_ptr< ccMesh > CreateBox(double width=1.0, double height=1.0, double depth=1.0, bool create_uv_map=false, bool map_texture_to_each_face=false)
static std::shared_ptr< ccMesh > CreateTorus(double torus_radius=1.0, double tube_radius=0.5, int radial_resolution=30, int tubular_resolution=20)
void RemoveTrianglesByMask(const std::vector< bool > &triangle_mask)
This function removes the triangles that are masked in triangle_mask. Call RemoveUnreferencedVertices...
ccMesh & PaintUniformColor(const Eigen::Vector3d &color)
Assigns each vertex in the ccMesh the same color.
virtual Eigen::Vector3d GetMaxBound() const override
Returns max bounds for geometry coordinates.
ccMesh & RemoveDegenerateTriangles()
Function that removes degenerate triangles, i.e., triangles that reference a single vertex multiple t...
ccMesh & RemoveDuplicatedTriangles()
Function that removes duplicated triangles, i.e., removes triangles that reference the same three ver...
bool IsVertexManifold() const
static std::shared_ptr< ccMesh > CreateCylinder(double radius=1.0, double height=2.0, int resolution=20, int split=4, bool create_uv_map=false)
int EulerPoincareCharacteristic() const
double GetSurfaceArea() const
virtual unsigned size() const override
Returns the number of triangles.
std::shared_ptr< ccMesh > FilterSmoothSimple(int number_of_iterations, FilterScope scope=FilterScope::All) const
Function to smooth triangle mesh with simple neighbour average.
static std::shared_ptr< ccMesh > CreateSphere(double radius=1.0, int resolution=20, bool create_uv_map=false)
static std::shared_ptr< ccMesh > CreateCoordinateFrame(double size=1.0, const Eigen::Vector3d &origin=Eigen::Vector3d(0.0, 0.0, 0.0))
ccMesh & ComputeTriangleNormals(bool normalized=true)
Function to compute triangle normals, usually called before rendering.
ccMesh & MergeCloseVertices(double eps)
Function that will merge close by vertices to a single one. The vertex position, normal and color wil...
ccMesh & RemoveUnreferencedVertices()
This function removes vertices from the triangle mesh that are not referenced in any triangle of the ...
bool IsSelfIntersecting() const
void RemoveTrianglesByIndex(const std::vector< size_t > &triangle_indices)
This function removes the triangles with index in triangle_indices. Call RemoveUnreferencedVertices t...
std::shared_ptr< ccMesh > FilterSmoothTaubin(int number_of_iterations, double lambda=0.5, double mu=-0.53, FilterScope scope=FilterScope::All) const
Function to smooth triangle mesh using method of Taubin, "Curve and Surface Smoothing Without Shrinka...
void FilterSmoothLaplacianHelper(std::shared_ptr< ccMesh > &mesh, const std::vector< CCVector3 > &prev_vertices, const std::vector< CCVector3 > &prev_vertex_normals, const ColorsTableType &prev_vertex_colors, const std::vector< std::unordered_set< int >> &adjacency_list, double lambda, bool filter_vertex, bool filter_normal, bool filter_color) const
static std::shared_ptr< ccMesh > CreateOctahedron(double radius=1.0, bool create_uv_map=false)
static std::shared_ptr< ccMesh > CreateTetrahedron(double radius=1.0, bool create_uv_map=false)
Eigen::Vector3d getVertice(size_t index) const
Eigen::Vector4d GetTrianglePlane(size_t triangle_idx) const
std::shared_ptr< ccPointCloud > SamplePointsUniformly(size_t number_of_points, bool use_triangle_normal=false, int seed=-1)
std::unordered_map< Eigen::Vector2i, std::vector< int >, cloudViewer::utility::hash_eigen< Eigen::Vector2i > > GetEdgeToVerticesMap() const
std::tuple< std::vector< int >, std::vector< size_t >, std::vector< double > > ClusterConnectedTriangles() const
Function that clusters connected triangles, i.e., triangles that are connected via edges are assigned...
std::vector< Eigen::Vector2i > GetNonManifoldEdges(bool allow_boundary_edges=true) const
void RemoveVerticesByIndex(const std::vector< size_t > &vertex_indices)
This function removes the vertices with index in vertex_indices. Note that also all triangles associa...
std::shared_ptr< ccMesh > FilterSharpen(int number_of_iterations, double strength, FilterScope scope=FilterScope::All) const
Function to sharpen triangle mesh.
std::tuple< std::shared_ptr< ccMesh >, std::vector< size_t > > ComputeConvexHull() const
static double ComputeTriangleArea(const Eigen::Vector3d &p0, const Eigen::Vector3d &p1, const Eigen::Vector3d &p2)
Function that computes the area of a mesh triangle.
std::shared_ptr< ccPointCloud > SamplePointsUniformlyImpl(size_t number_of_points, std::vector< double > &triangle_areas, double surface_area, bool use_triangle_normal, int seed)
static Eigen::Vector4d ComputeTrianglePlane(const Eigen::Vector3d &p0, const Eigen::Vector3d &p1, const Eigen::Vector3d &p2)
static std::shared_ptr< ccMesh > CreateArrow(double cylinder_radius=1.0, double cone_radius=1.5, double cylinder_height=5.0, double cone_height=4.0, int resolution=20, int cylinder_split=4, int cone_split=1)
static std::shared_ptr< ccMesh > CreateCone(double radius=1.0, double height=2.0, int resolution=20, int split=1, bool create_uv_map=false)
bool IsOrientable() const
bool IsWatertight() const
void RemoveVerticesByMask(const std::vector< bool > &vertex_mask)
This function removes the vertices that are masked in vertex_mask. Note that also all triangles assoc...
bool IsBoundingBoxIntersecting(const ccMesh &other) const
static std::shared_ptr< ccMesh > CreatePlane(double width=1.0, double height=1.0, bool create_uv_map=false)
bool IsEdgeManifold(bool allow_boundary_edges=true) const
Eigen::Vector3i getTriangle(size_t index) const
ccMesh & RemoveNonManifoldEdges()
Function that removes all non-manifold edges, by successively deleting triangles with the smallest su...
std::unordered_map< Eigen::Vector2i, double, cloudViewer::utility::hash_eigen< Eigen::Vector2i > > ComputeEdgeWeightsCot(const std::unordered_map< Eigen::Vector2i, std::vector< int >, cloudViewer::utility::hash_eigen< Eigen::Vector2i >> &edges_to_vertices, double min_weight=std::numeric_limits< double >::lowest()) const
Function that computes for each edge in the triangle mesh and passed as parameter edges_to_vertices t...
ccMesh & RemoveDuplicatedVertices()
Function that removes duplicated verties, i.e., vertices that have identical coordinates.
static std::shared_ptr< ccMesh > CreateMobius(int length_split=70, int width_split=15, int twists=1, double radius=1, double flatness=1, double width=1, double scale=1)
virtual Eigen::Vector3d GetMinBound() const override
Returns min bounds for geometry coordinates.
std::shared_ptr< ccMesh > FilterSmoothLaplacian(int number_of_iterations, double lambda, FilterScope scope=FilterScope::All) const
Function to smooth triangle mesh using Laplacian.
std::vector< Eigen::Vector2i > GetSelfIntersectingTriangles() const
static Eigen::Vector2i GetOrderedEdge(int vidx0, int vidx1)
Helper function to get an edge with ordered vertex indices.
ccMesh & ComputeAdjacencyList()
Function to compute adjacency list, call before adjacency list is.
ccMesh & ComputeVertexNormals(bool normalized=true)
Function to compute vertex normals, usually called before rendering.
static std::shared_ptr< ccMesh > CreateIcosahedron(double radius=1.0, bool create_uv_map=false)
std::unordered_map< Eigen::Vector2i, std::vector< int >, cloudViewer::utility::hash_eigen< Eigen::Vector2i > > GetEdgeToTrianglesMap() const
static CCVector3 & GetNormalPtr(unsigned normIndex)
virtual void setLocked(bool state)
Sets the "enabled" property.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
ColorsTableType * rgbColors() const
Returns pointer on RGB colors table.
bool resizeTheNormsTable()
Resizes the compressed normals array.
Eigen::Vector3d getEigenNormal(size_t index) const
std::vector< CCVector3 > getPointNormals() const
bool hasNormals() const override
Returns whether normals are enabled or not.
bool resizeTheRGBTable(bool fillWithWhite=false)
Resizes the RGB colors array.
bool hasColors() const override
Returns whether colors are enabled or not.
bool resize(unsigned numberOfPoints) override
Resizes all the active features arrays.
void setPointNormals(const std::vector< CCVector3 > &normals)
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
void setPointNormal(size_t pointIndex, const CCVector3 &N)
Sets a particular point normal (shortcut)
const CCVector3 & getPointNormal(unsigned pointIndex) const override
Returns normal corresponding to a given point.
Eigen::Vector3d getEigenColor(size_t index) const
void shrinkToFit()
Removes unused capacity.
ccPointCloud & PaintUniformColor(const Eigen::Vector3d &color)
Assigns each vertex in the ccMesh the same color.
ccPointCloud & NormalizeNormals()
Normalize point normals to length 1.`.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
FilterScope
Indicates the scope of filter operations.
void addEigenPoint(const Eigen::Vector3d &point)
std::vector< CCVector3 > & getPoints()
CCVector3 * getPointPtr(size_t index)
unsigned size() const override
void setEigenPoint(size_t index, const Eigen::Vector3d &point)
void setPoint(size_t index, const CCVector3 &P)
const CCVector3 * getPoint(unsigned index) const override
KDTree with FLANN for nearest neighbor search.
int SearchRadius(const T &query, double radius, std::vector< int > &indices, std::vector< double > &distance2) const
static std::tuple< std::shared_ptr< ccMesh >, std::vector< size_t > > ComputeConvexHull(const std::vector< Eigen::Vector3d > &points)
static bool TriangleTriangle3d(const Eigen::Vector3d &p0, const Eigen::Vector3d &p1, const Eigen::Vector3d &p2, const Eigen::Vector3d &q0, const Eigen::Vector3d &q1, const Eigen::Vector3d &q2)
static bool AABBAABB(const Eigen::Vector3d &min0, const Eigen::Vector3d &max0, const Eigen::Vector3d &min1, const Eigen::Vector3d &max1)
constexpr static RgbTpl FromEigen(const Eigen::Vector3d &t)
static Eigen::Vector3d ToEigen(const Type col[3])
bool computeNormals(const ccHObject::Container &selectedEntities, QWidget *parent)
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
static Edge< T > GetOrderedEdge(T vidx0, T vidx1)
brief Helper function to get an edge with ordered vertex indices.
static std::unordered_map< Edge< T >, std::vector< size_t >, utility::hash_tuple< Edge< T > > > GetEdgeToTrianglesMap(const core::Tensor &tris_cpu)
void swap(optional< T > &x, optional< T > &y) noexcept(noexcept(x.swap(y)))
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
Eigen::Matrix< Index, 2, 1 > Vector2i
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Triangle described by the indexes of its 3 vertices.