@@ -94,4 +94,119 @@ namespace diffCheck::segmentation
9494
9595 return segments;
9696 }
97+
98+ std::tuple<std::shared_ptr<geometry::DFPointCloud>, std::vector<std::shared_ptr<geometry::DFPointCloud>>> DFSegmentation::AssociateSegments (
99+ std::vector<std::shared_ptr<geometry::DFMesh>> meshFaces,
100+ std::vector<std::shared_ptr<geometry::DFPointCloud>> segments,
101+ double associationThreshold)
102+ {
103+ std::shared_ptr<geometry::DFPointCloud> unifiedPointCloud = std::make_shared<geometry::DFPointCloud>();
104+ std::vector<std::shared_ptr<geometry::DFPointCloud>> segmentsRemainder;
105+
106+ // iterate through the mesh faces given as function argument
107+ for (std::shared_ptr<diffCheck::geometry::DFMesh> face : meshFaces)
108+ {
109+ std::shared_ptr<geometry::DFPointCloud> correspondingSegment;
110+ std::shared_ptr<open3d::geometry::TriangleMesh> o3dFace;
111+ o3dFace = face->Cvt2O3DTriangleMesh ();
112+
113+ // Getting the center of the mesh face
114+ Eigen::Vector3d faceCenter;
115+ open3d::geometry::OrientedBoundingBox orientedBoundingBox = o3dFace->GetMinimalOrientedBoundingBox ();
116+ faceCenter = orientedBoundingBox.GetCenter ();
117+
118+ if (face->NormalsFace .size () == 0 )
119+ {
120+ o3dFace->ComputeTriangleNormals ();
121+ face->NormalsFace .clear ();
122+ for (auto normal : o3dFace->triangle_normals_ )
123+ {
124+ face->NormalsFace .push_back (normal.cast <double >());
125+ }
126+ }
127+
128+ // Getting the normal of the mesh face
129+ Eigen::Vector3d faceNormal = face->NormalsFace [0 ];
130+
131+ // iterate through the segments to find the closest ones compared to the face center taking the normals into account
132+ Eigen::Vector3d segmentCenter;
133+ Eigen::Vector3d segmentNormal;
134+ double faceDistance = std::numeric_limits<double >::max ();
135+ for (auto segment : segments)
136+ {
137+ for (auto point : segment->Points )
138+ {
139+ segmentCenter += point;
140+ }
141+ segmentCenter /= segment->GetNumPoints ();
142+
143+ for (auto normal : segment->Normals )
144+ {
145+ segmentNormal += normal;
146+ }
147+ segmentNormal.normalize ();
148+
149+ double currentDistance = (faceCenter - segmentCenter).norm () / std::abs (segmentNormal.dot (faceNormal));
150+ // if the distance is smaller than the previous one, update the distance and the corresponding segment
151+ if (currentDistance < faceDistance)
152+ {
153+ correspondingSegment = segment;
154+ faceDistance = currentDistance;
155+ }
156+ }
157+
158+ // get the triangles of the face. This is to check if the point is in the face
159+ std::vector<Eigen::Vector3i> faceTriangles = o3dFace->triangles_ ;
160+
161+ for (Eigen::Vector3d point : correspondingSegment->Points )
162+ {
163+ bool pointInFace = false ;
164+ /*
165+ To check if the point is in the face, we take into account all the triangles forming the face.
166+ We calculate the area of each triangle, then check if the sum of the areas of the tree triangles
167+ formed by two of the points of the referencr triangle and our point is equal to the reference triangle area
168+ (within a user-defined margin). If it is the case, the triangle is in the face.
169+ */
170+ for (Eigen::Vector3i triangle : faceTriangles)
171+ {
172+ // reference triangle
173+ Eigen::Vector3d v0 = o3dFace->vertices_ [triangle[0 ]];
174+ Eigen::Vector3d v1 = o3dFace->vertices_ [triangle[1 ]];
175+ Eigen::Vector3d v2 = o3dFace->vertices_ [triangle[2 ]];
176+ Eigen::Vector3d n = (v1 - v0).cross (v2 - v0);
177+ double referenceTriangleArea = n.norm ()*0.5 ;
178+
179+ // triangle 1
180+ Eigen::Vector3d n1 = (v1 - v0).cross (point - v0);
181+ double area1 = n1.norm ()*0.5 ;
182+
183+ // triangle 2
184+ Eigen::Vector3d n2 = (v2 - v1).cross (point - v1);
185+ double area2 = n2.norm ()*0.5 ;
186+
187+ // triangle 3
188+ Eigen::Vector3d n3 = (v0 - v2).cross (point - v2);
189+ double area3 = n3.norm ()*0.5 ;
190+
191+ double res = ( area1 + area2 + area3 - referenceTriangleArea) / referenceTriangleArea;
192+ if (res < associationThreshold)
193+ {
194+ pointInFace = true ;
195+ break ;
196+ }
197+ }
198+ if (pointInFace)
199+ {
200+ unifiedPointCloud->Points .push_back (point);
201+ }
202+ }
203+ // removing points from the segment that are in the face
204+ for (Eigen::Vector3d point : unifiedPointCloud->Points )
205+ {
206+ correspondingSegment->Points .erase (std::remove (correspondingSegment->Points .begin (), correspondingSegment->Points .end (), point), correspondingSegment->Points .end ());
207+ }
208+ }
209+ return std::make_tuple (unifiedPointCloud, segments);
210+ }
211+
97212} // namespace diffCheck::segmentation
0 commit comments