Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/diffCheck/geometry/DFPointCloud.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,14 @@ namespace diffCheck::geometry
DIFFCHECK_INFO("Default estimation of normals with knn = 30");
}
for (auto &normal : O3DPointCloud->normals_)
{
if(normal.z() < -0.8)
{
normal = -normal;
}
this->Normals.push_back(normal);
}

}
else
{
Expand All @@ -165,7 +172,13 @@ namespace diffCheck::geometry

this->Normals.clear();
for (int i = 0; i < cilantroPointCloud->normals.cols(); i++)
{
if(cilantroPointCloud->normals.col(i).z() < -0.8)
{
cilantroPointCloud->normals.col(i) = -cilantroPointCloud->normals.col(i);
}
this->Normals.push_back(cilantroPointCloud->normals.col(i).cast<double>());
}
DIFFCHECK_INFO(("Estimating normals with cilantro evaluator with knn = " + std::to_string(knn.value())).c_str());
}

Expand Down
23 changes: 18 additions & 5 deletions src/diffCheck/segmentation/DFSegmentation.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "DFSegmentation.hh"
#include <fstream>
#include <chrono>

#include <cilantro/utilities/point_cloud.hpp>
#include <cilantro/core/nearest_neighbors.hpp>
Expand Down Expand Up @@ -100,7 +102,8 @@ namespace diffCheck::segmentation
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
double angleThreshold,
double associationThreshold)
double associationThreshold,
double angleAssociationThreshold)
{
std::vector<std::shared_ptr<geometry::DFPointCloud>> faceSegments = std::vector<std::shared_ptr<geometry::DFPointCloud>>();

Expand Down Expand Up @@ -233,6 +236,12 @@ namespace diffCheck::segmentation
}
else
{
std::string timestamp = std::to_string(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count()
);
std::ofstream logFile("C:\\Users\\localuser\\Desktop\\association_log_" + timestamp + ".txt", std::ios::app);
for (std::shared_ptr<diffCheck::geometry::DFMesh> face : referenceMesh)
{
std::shared_ptr<geometry::DFPointCloud> correspondingSegment;
Expand Down Expand Up @@ -271,10 +280,12 @@ namespace diffCheck::segmentation
double currentDistance = (faceCenter - segmentCenter).norm();
double currentAngle = std::abs(sin(acos(faceNormal.dot(faceCenter - segmentCenter))));
// if the distance is smaller than the previous one, update the distance and the corresponding segment
if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold && currentDistance < faceDistance && std::abs(1 - currentAngle) < angleThreshold)
if (std::abs(sin(acos(faceNormal.dot(segmentNormal)))) < angleThreshold && currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - segmentCenter) / (faceCenter - segmentCenter).norm()))) < faceDistance)
{
logFile << std::abs(sin(acos(faceNormal.dot(segmentNormal)))) << " < " << angleThreshold << " and " << currentDistance << " * (" << angleAssociationThreshold << " + " << std::abs(faceNormal.dot((faceCenter - segmentCenter) / (faceCenter - segmentCenter).norm())) << ") < " << faceDistance << std::endl;
logFile << " considered face: Face normal: " << faceNormal.transpose() << ", Segment normal: " << segmentNormal.transpose() << ", Current distance: " << currentDistance << ", Face distance: " << faceDistance << std::endl;
correspondingSegment = segment;
faceDistance = currentDistance;
faceDistance = currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - segmentCenter) / (faceCenter - segmentCenter).norm())));
}
}

Expand Down Expand Up @@ -323,6 +334,7 @@ namespace diffCheck::segmentation
}
faceSegments.push_back(facePoints);
}
logFile.close();
}
return faceSegments;
}
Expand All @@ -333,7 +345,8 @@ namespace diffCheck::segmentation
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
double angleThreshold,
double associationThreshold)
double associationThreshold,
double angleAssociationThreshold)
{
if (unassociatedClusters.size() == 0)
{
Expand Down Expand Up @@ -441,7 +454,7 @@ namespace diffCheck::segmentation

double currentDistance = (clusterCenter - faceCenter).norm() * std::abs(std::cos(clusterNormalToJunctionLineAngle))
/ std::min(std::abs(clusterNormal.dot(faceNormal)), 0.05) ;
if (std::abs(sin(acos(faceNormal.dot(clusterNormal)))) < angleThreshold && currentDistance < distance && std::abs(1 - std::sin(clusterNormalToJunctionLineAngle)) < associationThreshold)
if (std::abs(sin(acos(faceNormal.dot(clusterNormal)))) < angleThreshold && currentDistance * (angleAssociationThreshold + std::abs(faceNormal.dot((faceCenter - clusterCenter) / (faceCenter - clusterCenter).norm()))) < distance)
{
goodMeshIndex = meshIndex;
goodFaceIndex = faceIndex;
Expand Down
11 changes: 8 additions & 3 deletions src/diffCheck/segmentation/DFSegmentation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,34 @@ namespace diffCheck::segmentation
* @param clusters the vector of clusters from cilantro to associate with the mesh faces of the reference mesh
* @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
* @param associationThreshold the threshold to consider the points of a segment and a mesh face as associable. It is the ratio between the surface of the closest mesh triangle and the sum of the areas of the three triangles that form the rest of the pyramid described by the mesh triangle and the point we want to associate or not. The lower the number, the more strict the association will be and some poinnts on the mesh face might be wrongfully excluded.
* @param angleAssociationThreshold a number to indicate how much distance in the plane of the face should be favored, compared to distance orthogonal to the face normal. If set to 0, any face in the same plane as the face will be considered as having a distance of 0. If set to a high value (e.g. 1000000), no difference will be made between distance in the plane of the face and orthogonal to it. Default is 0.5
* @return std::shared_ptr<geometry::DFPointCloud> The unified segments
*/
static std::vector<std::shared_ptr<geometry::DFPointCloud>> DFSegmentation::AssociateClustersToMeshes(
bool isCylinder,
std::vector<std::shared_ptr<geometry::DFMesh>> referenceMesh,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &clusters,
double angleThreshold = 0.1,
double associationThreshold = 0.1);
double associationThreshold = 0.1,
double angleAssociationThreshold = 0.5);

/** @brief Iterated through clusters and finds the corresponding mesh face. It then associates the points of the cluster that are on the mesh face to the segment already associated with the mesh face.
* @param isCylinder a boolean to indicate if the model is a cylinder. If true, the method will use the GetCenterAndAxis method of the mesh to find the center and axis of the mesh. based on that, we only want points that have normals more or less perpendicular to the cylinder axis.
* @param unassociatedClusters the clusters from the normal-based segmentatinon that haven't been associated yet.
* @param existingPointCloudSegments the already associated segments per mesh face.
* @param meshes the mesh faces for all the model. This is used to associate the clusters to the mesh faces.
* * @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
* @param angleThreshold the threshold to consider the a cluster as potential candidate for association. the value passed is the minimum sine of the angles. A value of 0 requires perfect alignment (angle = 0), while a value of 0.1 allows an angle of 5.7 degrees.
* @param associationThreshold the threshold to consider the points of a segment and a mesh face as associable. It is the ratio between the surface of the closest mesh triangle and the sum of the areas of the three triangles that form the rest of the pyramid described by the mesh triangle and the point we want to associate or not. The lower the number, the more strict the association will be and some poinnts on the mesh face might be wrongfully excluded.
* @param angleAssociationThreshold a number to indicate how much distance in the plane of the face should be favored, compared to distance orthogonal to the face normal. If set to 0, any face in the same plane as the face will be considered as having a distance of 0. If set to a high value (e.g. 1000000), no difference will be made between distance in the plane of the face and orthogonal to it. Default is 0.5
* @return void
*/
static void DFSegmentation::CleanUnassociatedClusters(
bool isCylinder,
std::vector<std::shared_ptr<geometry::DFPointCloud>> &unassociatedClusters,
std::vector<std::vector<std::shared_ptr<geometry::DFPointCloud>>> &existingPointCloudSegments,
std::vector<std::vector<std::shared_ptr<geometry::DFMesh>>> meshes,
double angleThreshold = 0.1,
double associationThreshold = 0.1);
double associationThreshold = 0.1,
double angleAssociationThreshold = 0.5);
};
} // namespace diffCheck::segmentation
6 changes: 4 additions & 2 deletions src/diffCheckBindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,15 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
py::arg("reference_mesh"),
py::arg("unassociated_clusters"),
py::arg("angle_threshold") = 0.1,
py::arg("association_threshold") = 0.1)
py::arg("association_threshold") = 0.1,
py::arg("angle_association_threshold") = 0.5)

.def_static("clean_unassociated_clusters", &diffCheck::segmentation::DFSegmentation::CleanUnassociatedClusters,
py::arg("is_roundwood"),
py::arg("unassociated_clusters"),
py::arg("associated_clusters"),
py::arg("reference_mesh"),
py::arg("angle_threshold") = 0.1,
py::arg("association_threshold") = 0.1);
py::arg("association_threshold") = 0.1,
py::arg("angle_association_threshold") = 0.5);
}
24 changes: 17 additions & 7 deletions src/gh/components/DF_CAD_segmentator/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def RunScript(self,
i_clouds: System.Collections.Generic.IList[Rhino.Geometry.PointCloud],
i_assembly,
i_angle_threshold: float = 0.1,
i_association_threshold: float = 0.1):
i_association_threshold: float = 0.1,
i_angle_association_threshold: float = 0.5):

if i_clouds is None or i_assembly is None:
self.AddRuntimeMessage(RML.Warning, "Please provide a cloud and an assembly to segment.")
Expand All @@ -29,13 +30,15 @@ def RunScript(self,
i_angle_threshold = 0.1
if i_association_threshold is None:
i_association_threshold = 0.1

if i_angle_association_threshold is None:
i_angle_association_threshold = 0.5
o_face_clusters = []
df_clusters = []
# we make a deepcopy of the input clouds
df_clouds = [df_cvt_bindings.cvt_rhcloud_2_dfcloud(cloud.Duplicate()) for cloud in i_clouds]

df_beams = i_assembly.beams
df_asssociated_cluster_faces_per_beam = []

for df_b in df_beams:
o_face_clusters.append([])
Expand All @@ -49,22 +52,29 @@ def RunScript(self,
reference_mesh=df_b_mesh_faces,
unassociated_clusters=df_clouds,
angle_threshold=i_angle_threshold,
association_threshold=i_association_threshold
association_threshold=i_association_threshold,
angle_association_threshold=i_angle_association_threshold
)
df_asssociated_cluster_faces_per_beam.append(df_asssociated_cluster_faces)

for i, df_b in enumerate(df_beams):
rh_b_mesh_faces = [df_b_f.to_mesh() for df_b_f in df_b.side_faces]
df_b_mesh_faces = [df_cvt_bindings.cvt_rhmesh_2_dfmesh(rh_b_mesh_face) for rh_b_mesh_face in rh_b_mesh_faces]

dfb_segmentation.DFSegmentation.clean_unassociated_clusters(
is_roundwood=df_b.is_roundwood,
unassociated_clusters=df_clouds,
associated_clusters=[df_asssociated_cluster_faces],
associated_clusters=[df_asssociated_cluster_faces_per_beam[i]],
reference_mesh=[df_b_mesh_faces],
angle_threshold=i_angle_threshold,
association_threshold=i_association_threshold
association_threshold=i_association_threshold,
angle_association_threshold=i_angle_association_threshold
)

o_face_clusters[-1] = [df_cvt_bindings.cvt_dfcloud_2_rhcloud(cluster) for cluster in df_asssociated_cluster_faces]
o_face_clusters[-1] = [df_cvt_bindings.cvt_dfcloud_2_rhcloud(cluster) for cluster in df_asssociated_cluster_faces_per_beam[i]]

df_asssociated_cluster = dfb_geometry.DFPointCloud()
for df_associated_face in df_asssociated_cluster_faces:
for df_associated_face in df_asssociated_cluster_faces_per_beam[i]:
df_asssociated_cluster.add_points(df_associated_face)

df_clusters.append(df_asssociated_cluster)
Expand Down
12 changes: 12 additions & 0 deletions src/gh/components/DF_CAD_segmentator/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "float"
},
{
"name": "i_angle_association_threshold",
"nickname": "i_angle_association_threshold",
"description": "A number to indicate how much distance in the plane of the face should be favored, compared to distance orthogonal to the face normal. Default is 0.5",
"optional": true,
"allowTreeAccess": true,
"showTypeHints": true,
"scriptParamAccess": "item",
"wireDisplay": "default",
"sourceCount": 0,
"typeHintID": "float"
}
],
"outputParameters": [
Expand Down
Loading