@@ -16,24 +16,34 @@ namespace diffCheck::segmentation
1616 int radiusNeighborhoodSize)
1717 {
1818 std::vector<std::shared_ptr<geometry::DFPointCloud>> segments;
19+ open3d::geometry::PointCloud o3dPointCloud;
1920 cilantro::PointCloud3f cilantroPointCloud;
20-
21+
22+ // Convert the point cloud to open3d point cloud
23+ for (int i = 0 ; i < pointCloud.Points .size (); i++)
24+ {
25+ o3dPointCloud.points_ .push_back (pointCloud.Points [i]);
26+ }
27+
28+ // estimate normals
29+ o3dPointCloud.EstimateNormals (open3d::geometry::KDTreeSearchParamHybrid (50 * voxelSize, 80 ));
30+ o3dPointCloud.NormalizeNormals ();
31+ std::shared_ptr<open3d::geometry::PointCloud> voxelizedO3DPointCloud = o3dPointCloud.VoxelDownSample (voxelSize);
32+
2133 // Convert the point cloud to cilantro point cloud
22- for (int i = 0 ; i < pointCloud. Points .size (); i++)
34+ for (int i = 0 ; i < voxelizedO3DPointCloud-> points_ .size (); i++)
2335 {
2436 cilantroPointCloud.points .conservativeResize (3 , cilantroPointCloud.points .cols () + 1 );
25- cilantroPointCloud.points .rightCols (1 ) = pointCloud.Points [i].cast <float >();
37+ cilantroPointCloud.points .rightCols (1 ) = voxelizedO3DPointCloud->points_ [i].cast <float >();
38+ cilantroPointCloud.normals .conservativeResize (3 , cilantroPointCloud.normals .cols () + 1 );
39+ cilantroPointCloud.normals .rightCols (1 ) = voxelizedO3DPointCloud->normals_ [i].cast <float >();
2640 }
2741
2842 // segment the point cloud using knn or radius neighborhood
2943 if (useKnnNeighborhood)
3044 {
3145 cilantro::KNNNeighborhoodSpecification<int > neighborhood (knnNeighborhoodSize);
3246
33- // conpute the normals and downsample
34- cilantroPointCloud.estimateNormals (neighborhood, false );
35- cilantroPointCloud.gridDownsample (voxelSize);
36-
3747 // Similarity evaluator
3848 cilantro::NormalsProximityEvaluator<float , 3 > similarityEvaluator (
3949 cilantroPointCloud.normals ,
@@ -62,10 +72,6 @@ namespace diffCheck::segmentation
6272 else
6373 {
6474 cilantro::RadiusNeighborhoodSpecification<float > neighborhood (radiusNeighborhoodSize);
65-
66- // conpute the normals and downsample
67- cilantroPointCloud.estimateNormals (neighborhood, false );
68- cilantroPointCloud.gridDownsample (voxelSize);
6975
7076 // Similarity evaluator
7177 cilantro::NormalsProximityEvaluator<float , 3 > similarityEvaluator (
@@ -107,35 +113,34 @@ namespace diffCheck::segmentation
107113 std::vector<std::shared_ptr<geometry::DFPointCloud>> segmentsRemainder;
108114
109115 // iterate through the mesh faces given as function argument
110- for (auto face : meshFaces)
116+ for (std::shared_ptr<diffCheck::geometry::DFMesh> face : meshFaces)
111117 {
112118 std::shared_ptr<geometry::DFPointCloud> correspondingSegment;
113-
119+ std::shared_ptr<open3d::geometry::TriangleMesh> o3dFace;
120+ o3dFace = face->Cvt2O3DTriangleMesh ();
121+
114122 // Getting the center of the mesh face
115- Eigen::Vector3d faceCenter = Eigen::Vector3d::Zero () ;
116- for ( auto vertex : face-> Vertices ){faceCenter += vertex;}
117- faceCenter /= face-> GetNumVertices ();
123+ Eigen::Vector3d faceCenter;
124+ open3d::geometry::OrientedBoundingBox orientedBoundingBox = o3dFace-> GetMinimalOrientedBoundingBox ();
125+ faceCenter = orientedBoundingBox. GetCenter ();
118126
119127 if (face->NormalsFace .size () == 0 )
120128 {
121- std::cout << " face has no normals, computing normals" << std::endl;
122- std::shared_ptr<open3d::geometry::TriangleMesh> o3dFace = face->Cvt2O3DTriangleMesh ();
123129 o3dFace->ComputeTriangleNormals ();
124130 face->NormalsFace .clear ();
125131 for (auto normal : o3dFace->triangle_normals_ )
126132 {
127133 face->NormalsFace .push_back (normal.cast <double >());
128134 }
129135 }
130-
136+
131137 // Getting the normal of the mesh face
132138 Eigen::Vector3d faceNormal = face->NormalsFace [0 ];
133139
134140 // iterate through the segments to find the closest ones compared to the face center taking the normals into account
135- Eigen::Vector3d segmentCenter = Eigen::Vector3d::Zero ();
136- Eigen::Vector3d segmentNormal = Eigen::Vector3d::Zero ();
137- double faceDistance = (segments[0 ]->Points [0 ] - faceCenter).norm () / std::pow (std::abs (segments[0 ]->Normals [0 ].dot (faceNormal)), 2 );
138- int segmentIndex = 0 ;
141+ Eigen::Vector3d segmentCenter;
142+ Eigen::Vector3d segmentNormal;
143+ double faceDistance = std::numeric_limits<double >::max ();
139144 for (auto segment : segments)
140145 {
141146 for (auto point : segment->Points )
@@ -144,40 +149,66 @@ namespace diffCheck::segmentation
144149 }
145150 segmentCenter /= segment->GetNumPoints ();
146151
147- if (segment->Normals .size () == 0 )
148- {
149- std::shared_ptr<open3d::geometry::PointCloud> o3dSegment = segment->Cvt2O3DPointCloud ();
150- o3dSegment->EstimateNormals ();
151- segment->Normals .clear ();
152- for (auto normal : o3dSegment->normals_ )
153- {
154- segment->Normals .push_back (normal.cast <double >());
155- }
156- }
157152 for (auto normal : segment->Normals )
158153 {
159154 segmentNormal += normal;
160155 }
161156 segmentNormal.normalize ();
162157
163- double currentDistance = (faceCenter - segmentCenter).norm () / std::pow ( std:: abs (segmentNormal.dot (faceNormal)), 2 );
158+ double currentDistance = (faceCenter - segmentCenter).norm () / std::abs (segmentNormal.dot (faceNormal));
164159 // if the distance is smaller than the previous one, update the distance and the corresponding segment
165160 if (currentDistance < faceDistance)
166161 {
167162 correspondingSegment = segment;
168- // storing previous segment in the remainder vector
169163 faceDistance = currentDistance;
170164 }
171- segmentIndex++;
172165 }
173- // remove the segment fron the segments vector
174- segments.erase (std::remove (segments.begin (), segments.end (), correspondingSegment), segments.end ());
175166
176- // Add the closest points of the corresponding segment to the unified point cloud
177- for (auto point : correspondingSegment->Points )
167+ // get the triangles of the face. This is to check if the point is in the face
168+ std::vector<Eigen::Vector3i> faceTriangles = o3dFace->triangles_ ;
169+
170+ for (Eigen::Vector3d point : correspondingSegment->Points )
178171 {
179- unifiedPointCloud->Points .push_back (point);
180- correspondingSegment->Points .erase (std::remove (correspondingSegment->Points .begin (), correspondingSegment->Points .end (), point), correspondingSegment->Points .end ());
172+ bool pointInFace = false ;
173+ /*
174+ To check if the point is in the face, we take into account all the triangles forming the face.
175+ We calculate the area of each triangle, then check if the sum of the areas of the tree triangles
176+ formed by two of the points of the referencr triangle and our point is equal to the reference triangle area
177+ (within a user-defined margin). If it is the case, the triangle is in the face.
178+ */
179+ for (Eigen::Vector3i triangle : faceTriangles)
180+ {
181+ // reference triangle
182+ Eigen::Vector3d v0 = o3dFace->vertices_ [triangle[0 ]].cast <double >();
183+ Eigen::Vector3d v1 = o3dFace->vertices_ [triangle[1 ]].cast <double >();
184+ Eigen::Vector3d v2 = o3dFace->vertices_ [triangle[2 ]].cast <double >();
185+ Eigen::Vector3d n = (v1 - v0).cross (v2 - v0);
186+ double referenceTriangleArea = n.norm ()/2.0 ;
187+
188+ // triangle 1
189+ Eigen::Vector3d n1 = (v1 - v0).cross (point - v0);
190+ double area1 = n1.norm ()/2.0 ;
191+
192+ // triangle 2
193+ Eigen::Vector3d n2 = (v2 - v1).cross (point - v1);
194+ double area2 = n2.norm ()/2.0 ;
195+
196+ // triangle 3
197+ Eigen::Vector3d n3 = (v0 - v2).cross (point - v2);
198+ double area3 = n3.norm ()/2.0 ;
199+
200+ if (std::abs ((referenceTriangleArea - (area1 + area2 + area3)) / referenceTriangleArea) < associationThreshold)
201+ {
202+ pointInFace = true ;
203+ break ;
204+ }
205+ }
206+ if (pointInFace)
207+ {
208+ unifiedPointCloud->Points .push_back (point);
209+ correspondingSegment->Points .erase (std::remove (correspondingSegment->Points .begin (), correspondingSegment->Points .end (), point), correspondingSegment->Points .end ());
210+ }
211+ // correspondingSegment->Points.erase(std::remove(correspondingSegment->Points.begin(), correspondingSegment->Points.end(), point), correspondingSegment->Points.end());
181212 }
182213 }
183214 return std::make_tuple (unifiedPointCloud, segments);
0 commit comments