106 if (!checkCompatibility()) {
108 forwardDistance = std::numeric_limits<T>::quiet_NaN();
109 backwardDistance = std::numeric_limits<T>::quiet_NaN();
110 chamferDistance = std::numeric_limits<T>::quiet_NaN();
111 rmsChamferDistance = std::numeric_limits<T>::quiet_NaN();
112 maxDistance = std::numeric_limits<T>::quiet_NaN();
119 constexpr int minimumWidth = 2;
121 auto workingTarget = levelSetTarget;
122 auto workingSample = levelSetSample;
124 if (levelSetTarget->getLevelSetWidth() < minimumWidth) {
125 workingTarget = SmartPointer<Domain<T, D>>::New(levelSetTarget);
128 "CompareChamfer: Expanded target level set to width " +
129 std::to_string(minimumWidth) +
" for surface extraction.");
132 if (levelSetSample->getLevelSetWidth() < minimumWidth) {
133 workingSample = SmartPointer<Domain<T, D>>::New(levelSetSample);
136 "CompareChamfer: Expanded sample level set to width " +
137 std::to_string(minimumWidth) +
" for surface extraction.");
141 auto targetSurfaceMesh = SmartPointer<Mesh<T>>::New();
142 auto sampleSurfaceMesh = SmartPointer<Mesh<T>>::New();
148 const auto &targetNodes = targetSurfaceMesh->getNodes();
149 const auto &sampleNodes = sampleSurfaceMesh->getNodes();
151 numTargetPoints = targetNodes.size();
152 numSamplePoints = sampleNodes.size();
154 if (numTargetPoints == 0 || numSamplePoints == 0) {
155 VIENNACORE_LOG_WARNING(
156 "CompareChamfer: One or both surfaces have no points. "
157 "Cannot compute Chamfer distance.");
158 forwardDistance = std::numeric_limits<T>::infinity();
159 backwardDistance = std::numeric_limits<T>::infinity();
160 chamferDistance = std::numeric_limits<T>::infinity();
161 rmsChamferDistance = std::numeric_limits<T>::infinity();
162 maxDistance = std::numeric_limits<T>::infinity();
167 std::vector<std::array<T, D>> targetPoints(numTargetPoints);
168 std::vector<std::array<T, D>> samplePoints(numSamplePoints);
170 for (
unsigned i = 0; i < numTargetPoints; ++i) {
171 for (
unsigned d = 0; d <
D; ++d) {
172 targetPoints[i][d] = targetNodes[i][d];
176 for (
unsigned i = 0; i < numSamplePoints; ++i) {
177 for (
unsigned d = 0; d <
D; ++d) {
178 samplePoints[i][d] = sampleNodes[i][d];
183 KDTree<T, std::array<T, D>> targetTree(targetPoints);
186 KDTree<T, std::array<T, D>> sampleTree(samplePoints);
191 T sumSquaredForward = 0.0;
193 std::vector<T> targetDistances;
194 if (outputMeshTarget !=
nullptr) {
195 targetDistances.reserve(numTargetPoints);
198 for (
unsigned i = 0; i < numTargetPoints; ++i) {
199 auto nearest = sampleTree.findNearest(targetPoints[i]);
200 if (nearest.has_value()) {
201 T dist = nearest.value().second;
203 sumSquaredForward += dist * dist;
204 maxForward = std::max(maxForward, dist);
205 if (outputMeshTarget !=
nullptr) {
206 targetDistances.push_back(dist);
211 forwardDistance = sumForward / numTargetPoints;
215 T sumSquaredBackward = 0.0;
217 std::vector<T> sampleDistances;
218 if (outputMeshSample !=
nullptr) {
219 sampleDistances.reserve(numSamplePoints);
222 for (
unsigned i = 0; i < numSamplePoints; ++i) {
223 auto nearest = targetTree.findNearest(samplePoints[i]);
224 if (nearest.has_value()) {
225 T dist = nearest.value().second;
227 sumSquaredBackward += dist * dist;
228 maxBackward = std::max(maxBackward, dist);
229 if (outputMeshSample !=
nullptr) {
230 sampleDistances.push_back(dist);
235 backwardDistance = sumBackward / numSamplePoints;
239 (sumForward + sumBackward) / (numTargetPoints + numSamplePoints);
240 rmsChamferDistance = std::sqrt((sumSquaredForward + sumSquaredBackward) /
241 (numTargetPoints + numSamplePoints));
242 maxDistance = std::max(maxForward, maxBackward);
245 if (outputMeshTarget !=
nullptr && !targetDistances.empty()) {
246 outputMeshTarget->clear();
247 outputMeshTarget->nodes = targetNodes;
250 if constexpr (
D == 2) {
251 outputMeshTarget->lines = targetSurfaceMesh->lines;
253 outputMeshTarget->triangles = targetSurfaceMesh->triangles;
257 outputMeshTarget->pointData.insertNextScalarData(
258 std::move(targetDistances),
"DistanceToSample");
261 for (
unsigned d = 0; d < 3; ++d) {
262 outputMeshTarget->minimumExtent[d] =
263 (d < D) ? std::numeric_limits<T>::max() : 0.0;
264 outputMeshTarget->maximumExtent[d] =
265 (d < D) ? std::numeric_limits<T>::lowest() : 0.0;
267 for (
unsigned d = 0; d <
D; ++d) {
268 for (
const auto &node : targetNodes) {
269 outputMeshTarget->minimumExtent[d] =
270 std::min(outputMeshTarget->minimumExtent[d], node[d]);
271 outputMeshTarget->maximumExtent[d] =
272 std::max(outputMeshTarget->maximumExtent[d], node[d]);
277 if (outputMeshSample !=
nullptr && !sampleDistances.empty()) {
278 outputMeshSample->clear();
279 outputMeshSample->nodes = sampleNodes;
282 if constexpr (D == 2) {
283 outputMeshSample->lines = sampleSurfaceMesh->lines;
285 outputMeshSample->triangles = sampleSurfaceMesh->triangles;
289 outputMeshSample->pointData.insertNextScalarData(
290 std::move(sampleDistances),
"DistanceToTarget");
293 for (
unsigned d = 0; d < 3; ++d) {
294 outputMeshSample->minimumExtent[d] =
295 (d < D) ? std::numeric_limits<T>::max() : 0.0;
296 outputMeshSample->maximumExtent[d] =
297 (d < D) ? std::numeric_limits<T>::lowest() : 0.0;
299 for (
unsigned d = 0; d <
D; ++d) {
300 for (
const auto &node : sampleNodes) {
301 outputMeshSample->minimumExtent[d] =
302 std::min(outputMeshSample->minimumExtent[d], node[d]);
303 outputMeshSample->maximumExtent[d] =
304 std::max(outputMeshSample->maximumExtent[d], node[d]);