Skip to content

Commit 797e912

Browse files
committed
2 parents f141063 + d398b03 commit 797e912

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+995
-36957
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.16.)
2-
project(diffCheck VERSION 1.1.0 LANGUAGES CXX C)
2+
project(diffCheck VERSION 1.1.1 LANGUAGES CXX C)
33
set(CMAKE_CXX_STANDARD 17)
44

55
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

assets/icon_pool/icon_export_ply.xcf

10.4 KB
Binary file not shown.
10.4 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
8.62 KB
Binary file not shown.

assets/icon_pool/icon_results.xcf

11.6 KB
Binary file not shown.

assets/icon_pool/normal_v1.png

8.74 KB
Loading

doc/gh_DFExportCloudToFile.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.. image:: ../src/gh/components/DF_export_cloud_to_file/icon.png
2+
:align: left
3+
:width: 40px
4+
5+
``DFExportCloudToFile`` component
6+
=================================
7+
8+
.. ghcomponent_to_rst:: ../src/gh/components/DF_export_cloud_to_file

doc/gh_DFExportResults.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.. image:: ../src/gh/components/DF_export_results/icon.png
2+
:align: left
3+
:width: 40px
4+
5+
``DFExportResults`` component
6+
=============================
7+
8+
.. ghcomponent_to_rst:: ../src/gh/components/DF_export_results

doc/gh_DFImportResults.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.. image:: ../src/gh/components/DF_import_results/icon.png
2+
:align: left
3+
:width: 40px
4+
5+
``DFImportResults`` component
6+
=============================
7+
8+
.. ghcomponent_to_rst:: ../src/gh/components/DF_import_results

doc/gh_DFInspectResults.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.. image:: ../src/gh/components/DF_inspect_results/icon.png
2+
:align: left
3+
:width: 40px
4+
5+
``DFInspectResults`` component
6+
==============================
7+
8+
.. ghcomponent_to_rst:: ../src/gh/components/DF_inspect_results

doc/gh_components.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ DF has a Grasshopper_ plugin with a set of components that allows the user to in
8181
- .. image:: ../src/gh/components/DF_cloud_voxel_downsample/icon.png
8282
- `gh_DFCloudVoxelDownsample <gh_DFCloudVoxelDownsample.html>`_
8383

84+
* - .. image:: ../src/gh/components/DF_export_cloud_to_file/icon.png
85+
- `DFExportCloudToFile <gh_DFExportCloudToFile.html>`_
86+
- .. image:: ../src/gh/components/DF_export_results/icon.png
87+
- `DFExportResults <gh_DFExportResults.html>`_
88+
89+
* - .. image:: ../src/gh/components/DF_import_results/icon.png
90+
- `DFImportResults <gh_DFImportResults.html>`_
91+
- .. image:: ../src/gh/components/DF_inspect_results/icon.png
92+
- `DFInspectResults <gh_DFInspectResults.html>`_
93+
8494

8595
.. toctree::
8696
:maxdepth: 1
@@ -113,4 +123,8 @@ DF has a Grasshopper_ plugin with a set of components that allows the user to in
113123
gh_DFColorizeCloud
114124
gh_DFBrepToCloud
115125
gh_DFRemoveStatisticalOutliers
116-
gh_DFMergeAssemblies
126+
gh_DFMergeAssemblies
127+
gh_DFExportCloudToFile
128+
gh_DFExportResults
129+
gh_DFImportResults
130+
gh_DFInspectResults

invokes/yakerize.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#! python3
2-
2+
"""
3+
Yakerize.py was originally developed as part of the DiffCheck plugin by
4+
Andrea Settimi, Damien Gilliard, Eleni Skevaki, Marirena Kladeftira (IBOIS, CRCL, EPFL) in 2024.
5+
It is distributed under the MIT License, provided this attribution is retained.
6+
"""
37
import os
48
import sys
59
import argparse

manifest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: diffCheck
3-
version: 1.1.0
3+
version: 1.2.0
44
authors:
55
- Andrea Settimi
66
- Damien Gilliard

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ module = "pefile"
2929
ignore_missing_imports = true
3030

3131
[[tool.mypy.overrides]]
32-
module = "diffCheck"
33-
ignore_undefined_attributes = true
34-
32+
module = "df_geometries"
33+
disable_error_code = "annotation-unchecked"
34+
check_untyped_defs = false
3535

36+
[[tool.mypy.overrides]]
37+
module = "src.gh.diffCheck.diffCheck.df_geometries"
38+
disable_error_code = "annotation-unchecked"
3639

3740
[tool.ruff]
3841
exclude = [

src/diffCheck/IOManager.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ namespace diffCheck::io
2828
return mesh;
2929
}
3030

31+
void WritePLYPointCloud(const std::shared_ptr<diffCheck::geometry::DFPointCloud> &pointCloud, const std::string &filename)
32+
{
33+
auto open3dPointCloud = pointCloud->Cvt2O3DPointCloud();
34+
open3d::io::WritePointCloudToPLY(
35+
filename,
36+
*open3dPointCloud,
37+
open3d::io::WritePointCloudOption());
38+
}
39+
3140
std::string GetTestDataDir()
3241
{
3342
// for github action conviniency

src/diffCheck/IOManager.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ namespace diffCheck::io
2525
*/
2626
std::shared_ptr<diffCheck::geometry::DFMesh> ReadPLYMeshFromFile(const std::string &filename);
2727

28+
/**
29+
* @brief Write a point cloud to a file as a PLY
30+
*
31+
* @param pointCloud the point cloud to write
32+
* @param filename the path to the file with the extension
33+
*/
34+
void WritePLYPointCloud(const std::shared_ptr<diffCheck::geometry::DFPointCloud> &pointCloud, const std::string &filename);
2835

2936
//////////////////////////////////////////////////////////////////////////
3037
// IO for test suite and tests data

src/diffCheck/geometry/DFPointCloud.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ namespace diffCheck::geometry
277277
this->Normals = cloud->Normals;
278278
}
279279

280+
void DFPointCloud::SaveToPLY(const std::string &path)
281+
{
282+
auto cloud_ptr = std::make_shared<DFPointCloud>(this->Points, this->Colors, this->Normals);
283+
diffCheck::io::WritePLYPointCloud(cloud_ptr, path);
284+
}
285+
280286
std::vector<double> DFPointCloud::ComputeDistance(std::shared_ptr<geometry::DFPointCloud> target)
281287
{
282288
std::vector<double> errors;

src/diffCheck/geometry/DFPointCloud.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ namespace diffCheck::geometry
153153
*/
154154
void LoadFromPLY(const std::string &path);
155155

156+
/**
157+
* @brief Save a point cloud to a file as a PLY
158+
*
159+
* @param filename the path to the file with the extension
160+
*/
161+
void SaveToPLY(const std::string &path);
162+
156163
public: ///< Distance calculations
157164
/**
158165
* @brief Compute the distance between two point clouds.

src/diffCheckBindings.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ PYBIND11_MODULE(diffcheck_bindings, m) {
5656
py::arg("nb_neighbors"), py::arg("std_ratio"))
5757

5858
.def("load_from_PLY", &diffCheck::geometry::DFPointCloud::LoadFromPLY)
59+
.def("save_to_PLY", &diffCheck::geometry::DFPointCloud::SaveToPLY)
60+
5961
.def("add_points", &diffCheck::geometry::DFPointCloud::AddPoints)
6062

6163
.def("get_tight_bounding_box", &diffCheck::geometry::DFPointCloud::GetTightBoundingBox)

src/gh/components/DF_csv_exporter/code.py

Lines changed: 126 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
#! python3
22

3+
import System
4+
import csv
5+
import os
6+
import typing
37

48
from ghpythonlib.componentbase import executingcomponent as component
9+
import Grasshopper as gh
510

6-
from diffCheck.df_error_estimation import DFInvalidData
7-
import csv
8-
import os
11+
from diffCheck.df_error_estimation import DFInvalidData, DFVizResults
12+
13+
14+
def add_bool_toggle(self,
15+
nickname: str,
16+
indx: int,
17+
X_param_coord: float,
18+
Y_param_coord: float,
19+
X_offset: int=87
20+
) -> None:
21+
"""
22+
Adds a boolean toggle to the component input
23+
24+
:param nickname: the nickname of the value list
25+
:param indx: the index of the input parameter
26+
:param X_param_coord: the x coordinate of the input parameter
27+
:param Y_param_coord: the y coordinate of the input parameter
28+
:param X_offset: the offset of the value list from the input parameter
29+
"""
30+
param = ghenv.Component.Params.Input[indx] # noqa: F821
31+
if param.SourceCount == 0:
32+
toggle = gh.Kernel.Special.GH_BooleanToggle()
33+
toggle.NickName = nickname
34+
toggle.Description = "Toggle the value to use with DFVizSettings"
35+
toggle.CreateAttributes()
36+
toggle.Attributes.Pivot = System.Drawing.PointF(
37+
X_param_coord - (toggle.Attributes.Bounds.Width) - X_offset,
38+
Y_param_coord - (toggle.Attributes.Bounds.Height / 2 + 0.1)
39+
)
40+
toggle.Attributes.ExpireLayout()
41+
gh.Instances.ActiveCanvas.Document.AddObject(toggle, False)
42+
ghenv.Component.Params.Input[indx].AddSource(toggle) # noqa: F821
943

1044

1145
class DFCsvExporter(component):
@@ -14,7 +48,28 @@ def __init__(self):
1448
self.prefix = ""
1549
self.counter = 0
1650

17-
def _get_id(self, idx, i_result):
51+
ghenv.Component.ExpireSolution(True) # noqa: F821
52+
ghenv.Component.Attributes.PerformLayout() # noqa: F821
53+
params = getattr(ghenv.Component.Params, "Input") # noqa: F821
54+
for j in range(len(params)):
55+
Y_cord = params[j].Attributes.InputGrip.Y + 1
56+
X_cord = params[j].Attributes.Pivot.X + 10
57+
input_indx = j
58+
if "i_export_seperate_files" == params[j].NickName:
59+
add_bool_toggle(
60+
ghenv.Component, # noqa: F821
61+
"export_asfiles",
62+
input_indx, X_cord, Y_cord)
63+
if "i_export_distances" == params[j].NickName:
64+
add_bool_toggle(
65+
ghenv.Component, # noqa: F821
66+
"export_dist",
67+
input_indx, X_cord, Y_cord)
68+
69+
def _get_id(self,
70+
idx: int,
71+
i_result: DFVizResults
72+
) -> str:
1873
""" Get the ID of the element """
1974
counter = 0
2075

@@ -34,15 +89,18 @@ def _get_id(self, idx, i_result):
3489
return f"{idx_b}--{idx_j}--{idx_f}"
3590
counter += 1
3691

37-
def _write_csv(self, file_path, rows):
38-
""" Write the CSV file """
39-
with open(file_path, mode='w', newline='') as file:
40-
writer = csv.writer(file)
41-
writer.writerow([f"{self.prefix} id", "distances", "min_deviation", "max_deviation", "std_deviation", "rmse", "mean"])
42-
writer.writerows(rows)
92+
def _prepare_row(self,
93+
idx: int,
94+
i_result: DFVizResults
95+
) -> typing.Dict:
96+
"""
97+
Convert the results contained in the DFVizResults object to a dict to be written in the CSV file
4398
44-
def _prepare_row(self, idx, i_result):
45-
""" Prepare a row for the CSV file """
99+
:param idx: Index of the element
100+
:param i_result: DFVizResults object containing all the values
101+
102+
:return: Dict of values containng as keys the header and as items the values to be written in the CSV file
103+
"""
46104
if i_result.sanity_check[idx].value != DFInvalidData.VALID.value:
47105
invalid_type = i_result.sanity_check[idx].name
48106
return [self._get_id(idx, i_result), invalid_type, invalid_type, invalid_type, invalid_type, invalid_type, invalid_type]
@@ -53,16 +111,57 @@ def _prepare_row(self, idx, i_result):
53111
std_dev = round(i_result.distances_sd_deviation[idx], 4)
54112
rmse = round(i_result.distances_rmse[idx], 4)
55113
mean = round(i_result.distances_mean[idx], 4)
56-
distances_str = ";".join(map(str, distances))
57-
return [self._get_id(idx, i_result), distances_str, min_dev, max_dev, std_dev, rmse, mean]
114+
115+
row: typing.Dict = {
116+
f"{self.prefix} id": self._get_id(idx, i_result),
117+
"distances": distances,
118+
"min_deviation": min_dev,
119+
"max_deviation": max_dev,
120+
"std_deviation": std_dev,
121+
"rmse": rmse,
122+
"mean": mean
123+
}
124+
return row
125+
126+
def _write_csv(self,
127+
csv_path: str,
128+
rows: typing.List[typing.Dict],
129+
is_writing_only_distances: bool = False
130+
) -> None:
131+
"""
132+
Write the CSV file
133+
134+
:param csv_path: Path of the CSV file
135+
:param rows: Dict of values to be written in the CSV file
136+
:param is_writing_only_distances: Flag to check if to write ONLY distances or the whole analysis
137+
138+
:return: None
139+
"""
140+
with open(csv_path, mode='w', newline='') as file:
141+
writer = csv.writer(file, quoting=csv.QUOTE_MINIMAL)
142+
if is_writing_only_distances:
143+
writer.writerow(list(rows[0].keys())[:2]) # header
144+
element_id = [row[f"{self.prefix} id"] for row in rows]
145+
dist_rows = [row["distances"] for row in rows]
146+
for idx, dist_row in enumerate(dist_rows):
147+
for dist in dist_row:
148+
writer.writerow([element_id[idx], dist])
149+
else:
150+
rows = [{k: v for k, v in row.items() if k != "distances"} for row in rows] # no distances
151+
writer.writerow(list(rows[0].keys())) # header
152+
writer.writerows([list(row.values()) for row in rows])
58153

59154
def RunScript(self,
60155
i_dump: bool,
61156
i_export_dir: str,
62157
i_file_name: str,
63158
i_export_seperate_files: bool,
159+
i_export_distances: bool,
64160
i_result):
65161

162+
csv_analysis_path: str = None
163+
csv_distances_path: str = None
164+
66165
if i_dump:
67166
os.makedirs(i_export_dir, exist_ok=True)
68167

@@ -75,10 +174,17 @@ def RunScript(self,
75174

76175
if i_export_seperate_files:
77176
for idx in range(len(i_result.source)):
78-
element_id = self._get_id( idx, i_result)
79-
file_path = os.path.join(i_export_dir, f"{i_file_name}_{self.prefix}_{element_id}.csv")
80-
self._write_csv(file_path, [self._prepare_row(idx, i_result)])
177+
element_id = self._get_id(idx, i_result)
178+
csv_analysis_path = os.path.join(i_export_dir, f"{i_file_name}_{self.prefix}_{element_id}.csv")
179+
rows = [self._prepare_row(idx, i_result)]
180+
self._write_csv(csv_analysis_path, rows)
181+
if i_export_distances:
182+
csv_distances_path = os.path.join(i_export_dir, f"{i_file_name}_{self.prefix}_{element_id}_distances.csv")
183+
self._write_csv(csv_distances_path, rows, is_writing_only_distances=True)
81184
else:
82-
file_path = os.path.join(i_export_dir, f"{i_file_name}.csv")
83-
rows = [self._prepare_row(idx, i_result) for idx in range(len(i_result.source))]
84-
self._write_csv(file_path, rows)
185+
csv_analysis_path = os.path.join(i_export_dir, f"{i_file_name}.csv")
186+
merged_rows = [self._prepare_row(idx, i_result) for idx in range(len(i_result.source))]
187+
self._write_csv(csv_analysis_path, merged_rows)
188+
if i_export_distances:
189+
csv_distances_path = os.path.join(i_export_dir, f"{i_file_name}_distances.csv")
190+
self._write_csv(csv_distances_path, merged_rows, is_writing_only_distances=True)

src/gh/components/DF_csv_exporter/metadata.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@
6161
"sourceCount": 0,
6262
"typeHintID": "bool"
6363
},
64+
{
65+
"name": "i_export_distances",
66+
"nickname": "i_export_distances",
67+
"description": "Whether to export the calculated error distances for each point of the analysed point cloud.",
68+
"optional": true,
69+
"allowTreeAccess": true,
70+
"showTypeHints": true,
71+
"scriptParamAccess": "item",
72+
"wireDisplay": "default",
73+
"sourceCount": 0,
74+
"typeHintID": "bool"
75+
},
6476
{
6577
"name": "i_result",
6678
"nickname": "i_result",

0 commit comments

Comments
 (0)