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);
194 T sumSquaredForward = 0.0;
196 std::vector<T> targetDistances;
197 if (outputMeshTarget !=
nullptr) {
198 targetDistances.reserve(numTargetPoints);
201 for (
unsigned i = 0; i < numTargetPoints; ++i) {
202 auto nearest = sampleTree.findNearest(targetPoints[i]);
203 if (nearest.has_value()) {
204 T dist = Distance(targetPoints[i], samplePoints[nearest->first]);
206 sumSquaredForward += dist * dist;
207 maxForward = std::max(maxForward, dist);
208 if (outputMeshTarget !=
nullptr) {
209 targetDistances.push_back(dist);
214 forwardDistance = sumForward / numTargetPoints;
218 T sumSquaredBackward = 0.0;
220 std::vector<T> sampleDistances;
221 if (outputMeshSample !=
nullptr) {
222 sampleDistances.reserve(numSamplePoints);
225 for (
unsigned i = 0; i < numSamplePoints; ++i) {
226 auto nearest = targetTree.findNearest(samplePoints[i]);
227 if (nearest.has_value()) {
228 T dist = Distance(samplePoints[i], targetPoints[nearest->first]);
230 sumSquaredBackward += dist * dist;
231 maxBackward = std::max(maxBackward, dist);
232 if (outputMeshSample !=
nullptr) {
233 sampleDistances.push_back(dist);
238 backwardDistance = sumBackward / numSamplePoints;
242 (sumForward + sumBackward) / (numTargetPoints + numSamplePoints);
243 rmsChamferDistance = std::sqrt((sumSquaredForward + sumSquaredBackward) /
244 (numTargetPoints + numSamplePoints));
245 maxDistance = std::max(maxForward, maxBackward);
248 if (outputMeshTarget !=
nullptr && !targetDistances.empty()) {
249 outputMeshTarget->clear();
250 outputMeshTarget->nodes = targetNodes;
253 if constexpr (
D == 2) {
254 outputMeshTarget->lines = targetSurfaceMesh->lines;
256 outputMeshTarget->triangles = targetSurfaceMesh->triangles;
260 outputMeshTarget->pointData.insertNextScalarData(
261 std::move(targetDistances),
"DistanceToSample");
264 for (
unsigned d = 0; d < 3; ++d) {
265 outputMeshTarget->minimumExtent[d] =
266 (d < D) ? std::numeric_limits<T>::max() : 0.0;
267 outputMeshTarget->maximumExtent[d] =
268 (d < D) ? std::numeric_limits<T>::lowest() : 0.0;
270 for (
unsigned d = 0; d <
D; ++d) {
271 for (
const auto &node : targetNodes) {
272 outputMeshTarget->minimumExtent[d] =
273 std::min(outputMeshTarget->minimumExtent[d], node[d]);
274 outputMeshTarget->maximumExtent[d] =
275 std::max(outputMeshTarget->maximumExtent[d], node[d]);
280 if (outputMeshSample !=
nullptr && !sampleDistances.empty()) {
281 outputMeshSample->clear();
282 outputMeshSample->nodes = sampleNodes;
285 if constexpr (D == 2) {
286 outputMeshSample->lines = sampleSurfaceMesh->lines;
288 outputMeshSample->triangles = sampleSurfaceMesh->triangles;
292 outputMeshSample->pointData.insertNextScalarData(
293 std::move(sampleDistances),
"DistanceToTarget");
296 for (
unsigned d = 0; d < 3; ++d) {
297 outputMeshSample->minimumExtent[d] =
298 (d < D) ? std::numeric_limits<T>::max() : 0.0;
299 outputMeshSample->maximumExtent[d] =
300 (d < D) ? std::numeric_limits<T>::lowest() : 0.0;
302 for (
unsigned d = 0; d <
D; ++d) {
303 for (
const auto &node : sampleNodes) {
304 outputMeshSample->minimumExtent[d] =
305 std::min(outputMeshSample->minimumExtent[d], node[d]);
306 outputMeshSample->maximumExtent[d] =
307 std::max(outputMeshSample->maximumExtent[d], node[d]);