GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/test/integration/CompareGrids.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 61 145 42.1%
Functions: 246 309 79.6%
Branches: 112 388 28.9%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file test/integration/CompareGrids.cc
5
6 #include "CompareGrids.h"
7
8 #include <openvdb/points/PointDataGrid.h>
9 #include <tbb/concurrent_vector.h>
10
11 namespace unittest_util
12 {
13
14 using TypeList = openvdb::TypeList<
15 double,
16 float,
17 int64_t,
18 int32_t,
19 int16_t,
20 bool,
21 openvdb::math::Vec2<double>,
22 openvdb::math::Vec2<float>,
23 openvdb::math::Vec2<int32_t>,
24 openvdb::math::Vec3<double>,
25 openvdb::math::Vec3<float>,
26 openvdb::math::Vec3<int32_t>,
27 openvdb::math::Vec4<double>,
28 openvdb::math::Vec4<float>,
29 openvdb::math::Vec4<int32_t>,
30 openvdb::math::Mat3<double>,
31 openvdb::math::Mat3<float>,
32 openvdb::math::Mat4<double>,
33 openvdb::math::Mat4<float>,
34 std::string>;
35
36 struct DiagnosticArrayData
37 {
38 DiagnosticArrayData()
39 : mSizeMatch(true)
40 , mTypesMatch(true)
41 , mFlagsMatch(true)
42 , mArrayValueFlags() {}
43
44 inline void
45 flagArrayValue(const size_t idx) {
46 if (!mArrayValueFlags) mArrayValueFlags.reset(new std::vector<size_t>());
47 (*mArrayValueFlags).push_back(idx);
48 }
49
50 bool mSizeMatch;
51 bool mTypesMatch;
52 bool mFlagsMatch;
53 std::unique_ptr<std::vector<size_t>> mArrayValueFlags;
54 };
55
56 struct DiagnosticData
57 {
58 using Ptr = std::unique_ptr<DiagnosticData>;
59 virtual ~DiagnosticData() = default;
60
61 virtual void report(std::ostream&,
62 const openvdb::GridBase&,
63 const openvdb::GridBase&,
64 openvdb::MaskGrid::Accessor&,
65 openvdb::MaskGrid::Accessor&) = 0;
66 };
67
68 template <typename NodeT>
69 struct NodeDD : public DiagnosticData
70 {
71 using Ptr = std::unique_ptr<NodeDD<NodeT>>;
72 using GridT = typename openvdb::BoolGrid::ValueConverter<typename NodeT::ValueType>::Type;
73
74 7551 NodeDD(const openvdb::Coord& origin)
75 : mOrigin(origin)
76 , mValid(true)
77 , mBufferSizes(true)
78 , mTopologyFlags(true)
79 , mVoxelFlags(true)
80 , mDescriptorsMatch(true)
81
60/120
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 45 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 64 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 64 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 69 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 69 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 69 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 62 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 62 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 62 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 69 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 69 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 69 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 65 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 65 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 65 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 66 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 66 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 66 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 69 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 69 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 69 times.
✗ Branch 48 not taken.
✓ Branch 49 taken 75 times.
✗ Branch 50 not taken.
✓ Branch 51 taken 75 times.
✗ Branch 52 not taken.
✓ Branch 53 taken 75 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 116 times.
✗ Branch 56 not taken.
✓ Branch 57 taken 116 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 116 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 130 times.
✗ Branch 62 not taken.
✓ Branch 63 taken 130 times.
✗ Branch 64 not taken.
✓ Branch 65 taken 130 times.
✗ Branch 66 not taken.
✓ Branch 67 taken 49 times.
✗ Branch 68 not taken.
✓ Branch 69 taken 49 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 49 times.
✗ Branch 72 not taken.
✓ Branch 73 taken 49 times.
✗ Branch 74 not taken.
✓ Branch 75 taken 49 times.
✗ Branch 76 not taken.
✓ Branch 77 taken 49 times.
✗ Branch 78 not taken.
✓ Branch 79 taken 49 times.
✗ Branch 80 not taken.
✓ Branch 81 taken 49 times.
✗ Branch 82 not taken.
✓ Branch 83 taken 49 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 449 times.
✗ Branch 86 not taken.
✓ Branch 87 taken 449 times.
✗ Branch 88 not taken.
✓ Branch 89 taken 449 times.
✗ Branch 90 not taken.
✓ Branch 91 taken 34 times.
✗ Branch 92 not taken.
✓ Branch 93 taken 34 times.
✗ Branch 94 not taken.
✓ Branch 95 taken 34 times.
✗ Branch 96 not taken.
✓ Branch 97 taken 286 times.
✗ Branch 98 not taken.
✓ Branch 99 taken 286 times.
✗ Branch 100 not taken.
✓ Branch 101 taken 289 times.
✗ Branch 102 not taken.
✓ Branch 103 taken 99 times.
✗ Branch 104 not taken.
✓ Branch 105 taken 99 times.
✗ Branch 106 not taken.
✓ Branch 107 taken 99 times.
✗ Branch 108 not taken.
✓ Branch 109 taken 273 times.
✗ Branch 110 not taken.
✓ Branch 111 taken 273 times.
✗ Branch 112 not taken.
✓ Branch 113 taken 273 times.
✗ Branch 114 not taken.
✓ Branch 115 taken 398 times.
✗ Branch 116 not taken.
✓ Branch 117 taken 398 times.
✗ Branch 118 not taken.
✓ Branch 119 taken 398 times.
15102 , mAttributeArrayData() {}
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7551 times.
15102 ~NodeDD() override = default;
83
84 bool hasValueFlags() const { return !mVoxelFlags.isOn(); }
85 bool hasTopologyFlags() const { return !mTopologyFlags.isOn(); }
86 void flagVoxelTopology(const int16_t idx) { mTopologyFlags.setOff(idx); }
87 void flagVoxelValue(const int16_t idx) { mVoxelFlags.setOff(idx); }
88
89 inline DiagnosticArrayData&
90 getDiagnosticArrayData(const std::string& name)
91 {
92 if (!mAttributeArrayData) {
93 mAttributeArrayData.reset(new std::map<std::string, DiagnosticArrayData>());
94 }
95 return (*mAttributeArrayData)[name];
96 }
97
98 bool hasDiagnosticArrayData() const { return static_cast<bool>(mAttributeArrayData); }
99
100 inline bool
101 hasDiagnosticArrayData(const std::string& name) const {
102 return (hasDiagnosticArrayData() &&
103 mAttributeArrayData->find(name) != mAttributeArrayData->end());
104 }
105
106 inline void report(std::ostream& os,
107 const openvdb::GridBase& grid1,
108 const openvdb::GridBase& grid2,
109 openvdb::MaskGrid::Accessor& accessorTopology,
110 openvdb::MaskGrid::Accessor& accessorValues) override
111 {
112 struct Local {
113 // flag to string
114 static std::string fts(const bool flag) {
115 return (flag ? "[SUCCESS]" : "[FAILED]");
116 }
117 };
118
119 const GridT& g1 = static_cast<const GridT&>(grid1);
120 const GridT& g2 = static_cast<const GridT&>(grid2);
121
122 os << " Coord : " << mOrigin << std::endl;
123 os << " Both Valid : " << Local::fts(this->mValid) << std::endl;
124 if (!this->mValid) {
125 const bool second = g1.constTree().template probeConstNode<NodeT>(mOrigin);
126 os << " Missing in " << (second ? "second" : "first")
127 << " grid."
128 << std::endl;
129 return;
130 }
131
132 const auto& l1 = g1.constTree().template probeConstNode<NodeT>(mOrigin);
133 const auto& l2 = g2.constTree().template probeConstNode<NodeT>(mOrigin);
134 assert(l1 && l2);
135
136 os << " Buffer Sizes : " << Local::fts(this->mBufferSizes) << std::endl;
137
138 const bool topologyMatch = !this->hasTopologyFlags();
139 os << " Topology : " << Local::fts(topologyMatch) << std::endl;
140
141 if (!topologyMatch) {
142 os << " The following voxel topologies differ : " << std::endl;
143 for (auto iter = this->mTopologyFlags.beginOff(); iter; ++iter) {
144 const openvdb::Coord coord = l1->offsetToGlobalCoord(iter.pos());
145 os << " [" << iter.pos() << "] "<< coord
146 << " G1: " << l1->isValueOn(coord)
147 << " - G2: " << l2->isValueOn(coord)
148 << std::endl;
149 accessorTopology.setValue(coord, true);
150 }
151 }
152
153 const bool valueMatch = !this->hasValueFlags();
154 os << " Values : " << Local::fts(valueMatch) << std::endl;
155
156 if (!valueMatch) {
157 os << " The following voxel values differ : " << std::endl;
158 for (auto iter = this->mVoxelFlags.beginOff(); iter; ++iter) {
159 const openvdb::Coord coord = l1->offsetToGlobalCoord(iter.pos());
160 os << " [" << iter.pos() << "] "<< coord
161 << " G1: " << l1->getValue(coord)
162 << " - G2: " << l2->getValue(coord)
163 << std::endl;
164 accessorValues.setValue(coord, true);
165 }
166 }
167
168 if (g1.template isType<openvdb::points::PointDataGrid>()) {
169 os << " Descriptors : " << Local::fts(this->mDescriptorsMatch) << std::endl;
170 const bool attributesMatch = !static_cast<bool>(this->mAttributeArrayData);
171 os << " Array Data : " << Local::fts(attributesMatch) << std::endl;
172 if (!attributesMatch) {
173 os << " The following attribute values : " << std::endl;
174 for (const auto& iter : *(this->mAttributeArrayData)) {
175
176 const std::string& name = iter.first;
177 const DiagnosticArrayData& arrayData = iter.second;
178
179 os << " Attribute Array : [" << name << "] \n"
180 << " Size Match : " << Local::fts(arrayData.mSizeMatch) << "\n"
181 << " Type Match : " << Local::fts(arrayData.mTypesMatch) << "\n"
182 << " Flags Match : " << Local::fts(arrayData.mFlagsMatch)
183 << std::endl;
184
185 const bool arrayValuesMatch = !static_cast<bool>(arrayData.mArrayValueFlags);
186 os << " Array Values : " << Local::fts(arrayValuesMatch) << std::endl;
187 if (!arrayValuesMatch) {
188 for (size_t idx : *(arrayData.mArrayValueFlags)) {
189 os << " [" << idx << "] "
190 << std::endl;
191 }
192 }
193 }
194 }
195 }
196 }
197
198 openvdb::Coord mOrigin;
199 bool mValid;
200 bool mBufferSizes;
201 typename NodeT::NodeMaskType mTopologyFlags;
202 typename NodeT::NodeMaskType mVoxelFlags;
203 bool mDescriptorsMatch;
204 std::unique_ptr<std::map<std::string, DiagnosticArrayData>> mAttributeArrayData;
205 };
206
207 template <typename NodeT,
208 typename std::enable_if<(NodeT::LEVEL == 0)>::type* = nullptr>
209 5038 inline bool compareNodes(const NodeT& firstLeaf,
210 const NodeT& secondLeaf,
211 const typename NodeT::NodeMaskType& mask,
212 NodeDD<NodeT>& data,
213 const ComparisonSettings& settings,
214 const typename NodeT::ValueType& tolerance)
215 {
216 using BufferT = typename NodeT::Buffer;
217
218 const BufferT& firstBuffer = firstLeaf.buffer();
219 const BufferT& secondBuffer = secondLeaf.buffer();
220
221 // if the buffers are not the same size the buffer most likely isn't
222 // loaded or allocated
223
224 if (firstBuffer.size() != secondBuffer.size()) {
225 data.mBufferSizes = false;
226 return false;
227 }
228
229 const typename NodeT::NodeMaskType& firstMask = firstLeaf.getValueMask();
230 const typename NodeT::NodeMaskType& secondMask = secondLeaf.getValueMask();
231 5038 typename NodeT::NodeMaskType::OnIterator iter = mask.beginOn();
232
233
2/2
✓ Branch 0 taken 2519 times.
✓ Branch 1 taken 2519 times.
10076 for (; iter; ++iter) {
234 const openvdb::Index n = iter.pos();
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2519 times.
5038 assert(n < firstBuffer.size() && n < secondBuffer.size());
236
237
2/4
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2519 times.
10076 if (settings.mCheckActiveStates &&
238 5038 firstMask.isOn(n) ^ secondMask.isOn(n)) {
239 data.flagVoxelTopology(static_cast<int16_t>(n));
240 }
241
242
2/4
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1851 times.
8740 if (settings.mCheckBufferValues &&
243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
928 !openvdb::math::isApproxEqual(firstBuffer[n], secondBuffer[n], tolerance)) {
244 data.flagVoxelValue(static_cast<int16_t>(n));
245 }
246 }
247
248
2/4
✓ Branch 0 taken 2519 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2519 times.
10076 return !data.hasValueFlags() && !data.hasTopologyFlags();
249 }
250
251
252 template <typename NodeT,
253 typename std::enable_if<(NodeT::LEVEL != 0)>::type* = nullptr>
254 10064 inline bool compareNodes(const NodeT& n1,
255 const NodeT& n2,
256 const typename NodeT::NodeMaskType& mask,
257 NodeDD<NodeT>& data,
258 const ComparisonSettings& settings,
259 const typename NodeT::ValueType& tolerance)
260 {
261 const auto& vmask1 = n1.getValueMask();
262 const auto& vmask2 = n2.getValueMask();
263 const auto& cmask1 = n1.getChildMask();
264 const auto& cmask2 = n2.getChildMask();
265
266 auto* t1 = n1.getTable();
267 auto* t2 = n2.getTable();
268
269
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5032 times.
20128 for (auto iter = mask.beginOn(); iter; ++iter) {
270 const openvdb::Index n = iter.pos();
271
272 if ((vmask1.isOn(n) ^ vmask2.isOn(n)) ||
273 (cmask1.isOn(n) ^ cmask2.isOn(n))) {
274 data.flagVoxelTopology(static_cast<int16_t>(n));
275 continue; // can't check values if topology is different
276 }
277
278 if (cmask1.isOn(n) && cmask2.isOn(n)) continue;
279 assert(vmask1.isOn(n) && vmask2.isOn(n));
280
281 if (settings.mCheckBufferValues &&
282 !openvdb::math::isApproxEqual(t1[n].getValue(), t2[n].getValue(), tolerance)) {
283 data.flagVoxelValue(static_cast<int16_t>(n));
284 }
285 }
286
287
2/4
✓ Branch 0 taken 5032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5032 times.
20128 return !data.hasValueFlags() && !data.hasTopologyFlags();
288 }
289
290
291 void compareStringArrays(const openvdb::points::AttributeArray& a1,
292 const openvdb::points::AttributeArray& a2,
293 const openvdb::points::PointDataTree::LeafNodeType& leaf1,
294 const openvdb::points::PointDataTree::LeafNodeType& leaf2,
295 const std::string& name,
296 NodeDD<openvdb::points::PointDataTree::LeafNodeType>& data)
297 {
298 using LeafNodeT = openvdb::points::PointDataTree::LeafNodeType;
299
300 if (a1.size() != a2.size()) {
301 auto& arrayData = data.getDiagnosticArrayData(name);
302 arrayData.mSizeMatch = false;
303 }
304
305 const openvdb::points::AttributeSet::Descriptor& descriptor1 = leaf1.attributeSet().descriptor();
306 const openvdb::points::AttributeSet::Descriptor& descriptor2 = leaf2.attributeSet().descriptor();
307
308 openvdb::points::StringAttributeHandle h1(a1, descriptor1.getMetadata()), h2(a2, descriptor2.getMetadata());
309 auto iter = leaf1.beginIndexAll();
310
311 for (; iter; ++iter) {
312 if (h1.get(*iter) != h2.get(*iter)) break;
313 }
314
315 if (iter) {
316 auto& arrayData = data.getDiagnosticArrayData(name);
317 for (; iter; ++iter) {
318 const openvdb::Index i = *iter;
319 if (h1.get(i) != h2.get(i)) {
320 arrayData.flagArrayValue(i);
321 data.flagVoxelValue(static_cast<int16_t>(LeafNodeT::coordToOffset(iter.getCoord())));
322 }
323 }
324 }
325 }
326
327 template <typename ValueType>
328 inline void compareArrays(const openvdb::points::AttributeArray& a1,
329 const openvdb::points::AttributeArray& a2,
330 const openvdb::points::PointDataTree::LeafNodeType& leaf,
331 const std::string& name,
332 NodeDD<openvdb::points::PointDataTree::LeafNodeType>& data)
333 {
334 using LeafNodeT = openvdb::points::PointDataTree::LeafNodeType;
335
336 if (a1.size() != a2.size()) {
337 auto& arrayData = data.getDiagnosticArrayData(name);
338 arrayData.mSizeMatch = false;
339 }
340
341 openvdb::points::AttributeHandle<ValueType> h1(a1), h2(a2);
342 auto iter = leaf.beginIndexAll();
343
344 for (; iter; ++iter) {
345 if (h1.get(*iter) != h2.get(*iter)) break;
346 }
347
348 if (iter) {
349 auto& arrayData = data.getDiagnosticArrayData(name);
350 for (; iter; ++iter) {
351 const openvdb::Index i = *iter;
352 if (h1.get(i) != h2.get(i)) {
353 arrayData.flagArrayValue(i);
354 data.flagVoxelValue(static_cast<int16_t>(LeafNodeT::coordToOffset(iter.getCoord())));
355 }
356 }
357 }
358 }
359
360 template <typename LeafNodeType>
361 inline bool
362 compareAttributes(const LeafNodeType&,
363 const LeafNodeType&,
364 NodeDD<LeafNodeType>&,
365 const ComparisonSettings&) {
366 return true;
367 }
368
369 template <>
370 inline bool
371 compareAttributes<openvdb::points::PointDataTree::LeafNodeType>
372 (const openvdb::points::PointDataTree::LeafNodeType& firstLeaf,
373 const openvdb::points::PointDataTree::LeafNodeType& secondLeaf,
374 NodeDD<openvdb::points::PointDataTree::LeafNodeType>& data,
375 const ComparisonSettings& settings)
376 {
377 using Descriptor = openvdb::points::AttributeSet::Descriptor;
378
379 const Descriptor& firstDescriptor = firstLeaf.attributeSet().descriptor();
380 const Descriptor& secondDescriptor = secondLeaf.attributeSet().descriptor();
381
382 if (settings.mCheckDescriptors &&
383 !firstDescriptor.hasSameAttributes(secondDescriptor)) {
384 data.mDescriptorsMatch = false;
385 }
386
387 // check common/miss-matching attributes
388
389 std::set<std::string> attrs1, attrs2;
390 for (const auto& nameToPos : firstDescriptor.map()) {
391 attrs1.insert(nameToPos.first);
392 }
393 for (const auto& nameToPos : secondDescriptor.map()) {
394 attrs2.insert(nameToPos.first);
395 }
396
397 std::vector<std::string> commonAttributes;
398 std::set_intersection(attrs1.begin(),
399 attrs1.end(),
400 attrs2.begin(),
401 attrs2.end(),
402 std::back_inserter(commonAttributes));
403
404 for (const std::string& name : commonAttributes) {
405 const size_t pos1 = firstDescriptor.find(name);
406 const size_t pos2 = secondDescriptor.find(name);
407 const auto& array1 = firstLeaf.constAttributeArray(pos1);
408 const auto& array2 = secondLeaf.constAttributeArray(pos2);
409
410 const std::string& type = array1.type().first;
411 if (type != array2.type().first) {
412 // this mismatch is also loged by differing descriptors
413 auto& arrayData = data.getDiagnosticArrayData(name);
414 arrayData.mTypesMatch = false;
415 continue;
416 }
417
418 if (settings.mCheckArrayFlags &&
419 array1.flags() != array2.flags()) {
420 auto& arrayData = data.getDiagnosticArrayData(name);
421 arrayData.mFlagsMatch = false;
422 }
423
424 if (settings.mCheckArrayValues) {
425 if (array1.type().second == "str") {
426 compareStringArrays(array1, array2, firstLeaf, secondLeaf, name, data);
427 }
428 else {
429 bool success = false;
430 // Remove string types but add uint8_t types (used by group arrays)
431 TypeList::Remove<std::string>::Append<uint8_t>::foreach([&](auto x) {
432 if (type == openvdb::typeNameAsString<decltype(x)>()) {
433 compareArrays<decltype(x)>(array1, array2, firstLeaf, name, data);
434 success = true;
435 }
436 });
437
438 if (!success) {
439 throw std::runtime_error("Unsupported array type for comparison: " + type);
440 }
441 }
442 }
443 }
444
445 return !data.hasDiagnosticArrayData() && data.mDescriptorsMatch;
446 }
447
448 template<typename TreeType>
449 struct CompareNodes
450 {
451 using LeafManagerT = openvdb::tree::LeafManager<const openvdb::MaskTree>;
452 using LeafNodeType = typename TreeType::LeafNodeType;
453 using ConstGridAccessor = openvdb::tree::ValueAccessor<const TreeType>;
454
455 6466 CompareNodes(tbb::concurrent_vector<DiagnosticData::Ptr>& data,
456 const TreeType& firstTree,
457 const TreeType& secondTree,
458 const typename TreeType::ValueType tolerance,
459 const ComparisonSettings& settings,
460 const bool useVoxelMask = true)
461 : mDiagnosticData(data)
462 , mFirst(firstTree)
463 , mSecond(secondTree)
464 , mTolerance(tolerance)
465 , mSettings(settings)
466
1/2
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
12932 , mUseVoxelMask(useVoxelMask) {}
467
468 void operator()(const openvdb::MaskTree::RootNodeType&) const {}
469
470 template <typename MaskNodeT>
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2880 times.
20862 void operator()(MaskNodeT& node) const
472 {
473 using NodeT = typename MaskNodeT::template ValueConverter<typename TreeType::ValueType>::Type;
474
475 const openvdb::Coord& origin = node.origin();
476 15102 const NodeT* const n1 = mFirst.template probeConstNode<NodeT>(origin);
477 15102 const NodeT* const n2 = mSecond.template probeConstNode<NodeT>(origin);
478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7551 times.
15102 if (n1 == nullptr && n2 == nullptr) return;
479
480 15102 typename NodeDD<NodeT>::Ptr data(new NodeDD<NodeT>(origin));
481
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7551 times.
15102 if (static_cast<bool>(n1) ^ static_cast<bool>(n2)) {
483 data->mValid = false;
484 }
485 else {
486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7551 times.
15102 assert(n1 && n2);
487 const typename MaskNodeT::NodeMaskType
488
1/2
✓ Branch 0 taken 7551 times.
✗ Branch 1 not taken.
15102 mask(mUseVoxelMask ? node.getValueMask() : true);
489
2/4
✓ Branch 1 taken 7551 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2070 times.
✗ Branch 4 not taken.
15102 if (compareNodes(*n1, *n2, mask, *data, mSettings, mTolerance) &&
490 compareAttributes(*n1, *n2, *data, mSettings)) {
491 data.reset();
492 }
493 }
494
495
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7551 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
15102 if (data) mDiagnosticData.emplace_back(std::move(data));
496 }
497
498 private:
499 tbb::concurrent_vector<DiagnosticData::Ptr>& mDiagnosticData;
500 const ConstGridAccessor mFirst;
501 const ConstGridAccessor mSecond;
502 const typename TreeType::ValueType mTolerance;
503 const ComparisonSettings& mSettings;
504 const bool mUseVoxelMask;
505 };
506
507 template <typename GridType>
508 11488 bool compareGrids(ComparisonResult& resultData,
509 const GridType& firstGrid,
510 const GridType& secondGrid,
511 const ComparisonSettings& settings,
512 const openvdb::MaskGrid::ConstPtr maskGrid,
513 const typename GridType::ValueType tolerance)
514 {
515 using TreeType = typename GridType::TreeType;
516 using NodeManager = openvdb::tree::NodeManager<const openvdb::MaskTree,
517 openvdb::MaskTree::RootNodeType::LEVEL>;
518
519 struct Local {
520 // flag to string
521 static std::string fts(const bool flag) {
522
7/14
✗ Branch 0 not taken.
✓ Branch 1 taken 5744 times.
✓ Branch 4 taken 5744 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3233 times.
✓ Branch 10 taken 3233 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3233 times.
✓ Branch 15 taken 3233 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 3233 times.
✗ Branch 19 not taken.
24420 return (flag ? "[SUCCESS]" : "[FAILED]");
523 }
524 };
525
526 bool result = true;
527 bool flag = true;
528 11488 std::ostream& os = resultData.mOs;
529
530 os << "[Diagnostic : Compare Leaf Nodes Result]\n"
531 << " First Grid: \"" << firstGrid.getName() << "\"\n"
532
1/2
✓ Branch 2 taken 5744 times.
✗ Branch 3 not taken.
34464 << " Second Grid: \"" << secondGrid.getName() << "\"\n"
533 << std::endl;
534
535
3/4
✓ Branch 0 taken 3235 times.
✓ Branch 1 taken 2509 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3235 times.
17958 if (firstGrid.tree().hasActiveTiles() ||
536 secondGrid.tree().hasActiveTiles()) {
537 os << "[Diagnostic : WARNING]: Grids contain active tiles which will not be compared."
538 << std::endl;
539 }
540
541
1/2
✓ Branch 0 taken 5744 times.
✗ Branch 1 not taken.
11488 if (settings.mCheckTransforms) {
542 11488 flag = (firstGrid.constTransform() == secondGrid.constTransform());
543 result &= flag;
544 11488 os << "[Diagnostic]: Grid transformations: " << Local::fts(flag)
545 << std::endl;
546 }
547
548 11488 const openvdb::Index64 leafCount1 = firstGrid.tree().leafCount();
549 11488 const openvdb::Index64 leafCount2 = secondGrid.tree().leafCount();
550 flag = (leafCount1 == 0 && leafCount2 == 0);
551
2/2
✓ Branch 0 taken 2511 times.
✓ Branch 1 taken 3233 times.
11488 if (flag) {
552 os << "[Diagnostic]: Both grids contain 0 leaf nodes."
553 << std::endl;
554 5022 return result;
555 }
556
557
2/4
✓ Branch 0 taken 3233 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3233 times.
✗ Branch 3 not taken.
6466 if (settings.mCheckTopologyStructure && !maskGrid) {
558 flag = firstGrid.tree().hasSameTopology(secondGrid.tree());
559 result &= flag;
560 6466 os << "[Diagnostic]: Topology structures: " << Local::fts(flag)
561 << std::endl;
562 }
563
564 openvdb::MaskGrid::Ptr mask = openvdb::MaskGrid::create();
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3233 times.
6466 if (maskGrid) {
566 mask->topologyUnion(*maskGrid);
567 }
568 else {
569 mask->topologyUnion(firstGrid);
570 mask->topologyUnion(secondGrid);
571 }
572
573
1/2
✓ Branch 1 taken 3233 times.
✗ Branch 2 not taken.
6466 openvdb::tools::pruneInactive(mask->tree());
574
575
1/2
✓ Branch 1 taken 3233 times.
✗ Branch 2 not taken.
12932 NodeManager manager(mask->constTree());
576 6466 tbb::concurrent_vector<DiagnosticData::Ptr> data;
577
578 CompareNodes<TreeType>
579
2/4
✓ Branch 1 taken 3233 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
12932 op(data,
580 firstGrid.constTree(),
581 secondGrid.constTree(),
582 tolerance,
583 settings);
584
585
1/2
✓ Branch 1 taken 3233 times.
✗ Branch 2 not taken.
6466 manager.foreachBottomUp(op);
586
587 flag = data.empty();
588 result &= flag;
589 6466 os << "[Diagnostic]: Leaf Node Comparison: " << Local::fts(flag)
590 << std::endl;
591
592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3233 times.
6466 if (flag) return result;
593
594 openvdb::MaskGrid& differingTopology = *(resultData.mDifferingTopology);
595 openvdb::MaskGrid& differingValues = *(resultData.mDifferingValues);
596
597 differingTopology.setTransform(firstGrid.transform().copy());
598 differingValues.setTransform(firstGrid.transform().copy());
599 differingTopology.setName("different_topology");
600 differingValues.setName("different_values");
601
602 // Print diagnostic info to the stream and intialise the result topologies
603
604 openvdb::MaskGrid::Accessor accessorTopology = differingTopology.getAccessor();
605 openvdb::MaskGrid::Accessor accessorValues = differingValues.getAccessor();
606
607 os << "[Diagnostic]: Leaf Node Diagnostics:\n" << std::endl;
608
609 for (const auto& diag : data) {
610 assert(diag);
611 diag->report(os, firstGrid, secondGrid, accessorTopology, accessorValues);
612 }
613
614 return result;
615 }
616
617 template <typename ValueT>
618 using ConverterT = typename openvdb::BoolGrid::ValueConverter<ValueT>::Type;
619
620 5019 bool compareUntypedGrids(ComparisonResult &resultData,
621 const openvdb::GridBase &firstGrid,
622 const openvdb::GridBase &secondGrid,
623 const ComparisonSettings &settings,
624 const openvdb::MaskGrid::ConstPtr maskGrid)
625 {
626 5019 bool result = false, valid = false;;
627 205779 TypeList::foreach([&](auto x) {
628 using GridT = ConverterT<decltype(x)>;
629
2/2
✓ Branch 1 taken 5019 times.
✓ Branch 2 taken 95361 times.
200760 if (firstGrid.isType<GridT>()) {
630 10038 valid = true;
631 10038 const GridT& firstGridTyped = static_cast<const GridT&>(firstGrid);
632 10038 const GridT& secondGridTyped = static_cast<const GridT&>(secondGrid);
633
2/4
✓ Branch 2 taken 5019 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5019 times.
10038 result = compareGrids(resultData, firstGridTyped, secondGridTyped, settings, maskGrid);
634 }
635 200760 });
636
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5019 times.
5019 if (!valid) {
638 if (firstGrid.isType<openvdb::points::PointDataGrid>()) {
639 valid = true;
640 const openvdb::points::PointDataGrid& firstGridTyped =
641 static_cast<const openvdb::points::PointDataGrid&>(firstGrid);
642 const openvdb::points::PointDataGrid& secondGridTyped =
643 static_cast<const openvdb::points::PointDataGrid&>(secondGrid);
644 result = compareGrids(resultData, firstGridTyped, secondGridTyped, settings, maskGrid);
645 }
646 }
647
648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5019 times.
5019 if (!valid) {
649 OPENVDB_THROW(openvdb::TypeError, "Unsupported grid type: " + firstGrid.valueType());
650 }
651 5019 return result;
652 }
653
654
655 }
656
657
658