GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/math/Transform.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 146 210 69.5%
Functions: 26 32 81.2%
Branches: 94 304 30.9%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #include "Transform.h"
5 #include "LegacyFrustum.h"
6
7 #include <openvdb/version.h>
8 #include <sstream>
9 #include <string>
10 #include <vector>
11
12 namespace openvdb {
13 OPENVDB_USE_VERSION_NAMESPACE
14 namespace OPENVDB_VERSION_NAME {
15 namespace math {
16
17
18 ////////////////////////////////////////
19
20
21 53317 Transform::Transform(const MapBase::Ptr& map):
22
1/2
✓ Branch 1 taken 53317 times.
✗ Branch 2 not taken.
53317 mMap(ConstPtrCast</*to=*/MapBase, /*from=*/const MapBase>(map))
23 {
24 // auto-convert to simplest type
25
6/8
✓ Branch 1 taken 53317 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21801 times.
✓ Branch 4 taken 31516 times.
✓ Branch 6 taken 21801 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 67 times.
✓ Branch 9 taken 21734 times.
53317 if (!mMap->isType<UniformScaleMap>() && mMap->isLinear()) {
26
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 AffineMap::Ptr affine = mMap->getAffineMap();
27
3/8
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
201 mMap = simplify(affine);
28 }
29 53317 }
30
31 2486 Transform::Transform(const Transform& other):
32 2486 mMap(ConstPtrCast</*to=*/MapBase, /*from=*/const MapBase>(other.baseMap()))
33 {
34 2486 }
35
36
37 ////////////////////////////////////////
38
39
40 // Factory methods
41
42 Transform::Ptr
43 25676 Transform::createLinearTransform(double voxelDim)
44 {
45 return Transform::Ptr(new Transform(
46
2/4
✓ Branch 2 taken 25676 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25676 times.
✗ Branch 6 not taken.
77028 MapBase::Ptr(new UniformScaleMap(voxelDim))));
47 }
48
49 Transform::Ptr
50 20 Transform::createLinearTransform(const Mat4R& m)
51 {
52
3/6
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
60 return Transform::Ptr(new Transform(MapBase::Ptr(new AffineMap(m))));
53 }
54
55 Transform::Ptr
56 5 Transform::createFrustumTransform(const BBoxd& bbox, double taper,
57 double depth, double voxelDim)
58 {
59 return Transform::Ptr(new Transform(
60
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
10 NonlinearFrustumMap(bbox, taper, depth).preScale(Vec3d(voxelDim, voxelDim, voxelDim))));
61 }
62
63
64 ////////////////////////////////////////
65
66
67 void
68 140 Transform::read(std::istream& is)
69 {
70 // Read the type name.
71 140 Name type = readString(is);
72
73
3/4
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 137 times.
140 if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NEW_TRANSFORM) {
74 // Handle old-style transforms.
75
76
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (type == "LinearTransform") {
77 // First read in the old transform's base class.
78 Coord tmpMin, tmpMax;
79
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 is.read(reinterpret_cast<char*>(&tmpMin), sizeof(Coord::ValueType) * 3);
80
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 is.read(reinterpret_cast<char*>(&tmpMax), sizeof(Coord::ValueType) * 3);
81
82 // Second read in the old linear transform
83 Mat4d tmpLocalToWorld, tmpWorldToLocal, tmpVoxelToLocal, tmpLocalToVoxel;
84
85 tmpLocalToWorld.read(is);
86 tmpWorldToLocal.read(is);
87 tmpVoxelToLocal.read(is);
88 tmpLocalToVoxel.read(is);
89
90 // Convert and simplify
91
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
6 AffineMap::Ptr affineMap(new AffineMap(tmpVoxelToLocal*tmpLocalToWorld));
92
3/8
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
9 mMap = simplify(affineMap);
93
94 } else if (type == "FrustumTransform") {
95
96 internal::LegacyFrustum legacyFrustum(is);
97
98 CoordBBox bb = legacyFrustum.getBBox();
99 BBoxd bbox(bb.min().asVec3d(), bb.max().asVec3d()
100 /* -Vec3d(1,1,1) */
101 );
102 double taper = legacyFrustum.getTaper();
103 double depth = legacyFrustum.getDepth();
104
105 double nearPlaneWidth = legacyFrustum.getNearPlaneWidth();
106 double nearPlaneDist = legacyFrustum.getNearPlaneDist();
107 const Mat4d& camxform = legacyFrustum.getCamXForm();
108
109 // create the new frustum with these parameters
110 Mat4d xform(Mat4d::identity());
111 xform.setToTranslation(Vec3d(0,0, -nearPlaneDist));
112 xform.preScale(Vec3d(nearPlaneWidth, nearPlaneWidth, -nearPlaneWidth));
113
114 // create the linear part of the frustum (the second map)
115 Mat4d second = xform * camxform;
116
117 // we might have precision problems, the constructor for the
118 // affine map is not forgiving (so we fix here).
119 const Vec4d col3 = second.col(3);
120 const Vec4d ref(0, 0, 0, 1);
121
122 if (ref.eq(col3) ) {
123 second.setCol(3, ref);
124 }
125
126 MapBase::Ptr linearMap(simplify(AffineMap(second).getAffineMap()));
127
128 // note that the depth is scaled on the nearPlaneSize.
129 // the linearMap will uniformly scale the frustum to the correct size
130 // and rotate to align with the camera
131 mMap = MapBase::Ptr(new NonlinearFrustumMap(
132 bbox, taper, depth/nearPlaneWidth, linearMap));
133
134 } else {
135 OPENVDB_THROW(IoError, "Transforms of type " + type + " are no longer supported");
136 }
137 } else {
138 // Check if the map has been registered.
139
2/4
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 137 times.
137 if (!MapRegistry::isRegistered(type)) {
140 OPENVDB_THROW(KeyError, "Map " << type << " is not registered");
141 }
142
143 // Create the map of the type and then read it in.
144
2/4
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 137 times.
✗ Branch 5 not taken.
274 mMap = math::MapRegistry::createMap(type);
145
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
137 mMap->read(is);
146 }
147 140 }
148
149
150 void
151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166 times.
166 Transform::write(std::ostream& os) const
152 {
153
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 166 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
166 if (!mMap) OPENVDB_THROW(IoError, "Transform does not have a map");
154
155 // Write the type-name of the map.
156
1/2
✓ Branch 2 taken 166 times.
✗ Branch 3 not taken.
332 writeString(os, mMap->type());
157
158 166 mMap->write(os);
159 166 }
160
161
162 ////////////////////////////////////////
163
164
165 bool
166 6 Transform::isIdentity() const
167 {
168
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (mMap->isLinear()) {
169 6 return mMap->getAffineMap()->isIdentity();
170
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 } else if ( mMap->isType<NonlinearFrustumMap>() ) {
171 NonlinearFrustumMap::Ptr frustum =
172 3 StaticPtrCast<NonlinearFrustumMap, MapBase>(mMap);
173 3 return frustum->isIdentity();
174 }
175 // unknown nonlinear map type
176 return false;
177 }
178
179
180 ////////////////////////////////////////
181
182
183 void
184 6 Transform::preRotate(double radians, const Axis axis)
185 {
186 6 mMap = mMap->preRotate(radians, axis);
187 6 }
188
189 void
190 10 Transform::preTranslate(const Vec3d& t)
191 {
192 10 mMap = mMap->preTranslate(t);
193 10 }
194
195 void
196 10 Transform::preScale(const Vec3d& s)
197 {
198 10 mMap = mMap->preScale(s);
199 10 }
200
201 void
202 8 Transform::preScale(double s)
203 {
204 const Vec3d vec(s,s,s);
205 8 mMap = mMap->preScale(vec);
206 8 }
207
208 void
209 2 Transform::preShear(double shear, Axis axis0, Axis axis1)
210 {
211 2 mMap = mMap->preShear(shear, axis0, axis1);
212 2 }
213
214 void
215 4 Transform::preMult(const Mat4d& m)
216 {
217
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (mMap->isLinear()) {
218
219 2 const Mat4d currentMat4 = mMap->getAffineMap()->getMat4();
220 2 const Mat4d newMat4 = m * currentMat4;
221
222
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 AffineMap::Ptr affineMap( new AffineMap( newMat4) );
223
3/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
6 mMap = simplify(affineMap);
224
225
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 } else if (mMap->isType<NonlinearFrustumMap>() ) {
226
227 NonlinearFrustumMap::Ptr currentFrustum =
228 2 StaticPtrCast<NonlinearFrustumMap, MapBase>(mMap);
229
230 const Mat4d currentMat4 = currentFrustum->secondMap().getMat4();
231 2 const Mat4d newMat4 = m * currentMat4;
232
233
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 AffineMap affine{newMat4};
234
235 NonlinearFrustumMap::Ptr frustum{new NonlinearFrustumMap{
236 currentFrustum->getBBox(),
237 currentFrustum->getTaper(),
238 currentFrustum->getDepth(),
239
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 affine.copy()
240
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 }};
241
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mMap = StaticPtrCast<MapBase, NonlinearFrustumMap>(frustum);
242 }
243
244 4 }
245
246 void
247 Transform::preMult(const Mat3d& m)
248 {
249 Mat4d mat4 = Mat4d::identity();
250 mat4.setMat3(m);
251 preMult(mat4);
252 }
253
254 void
255 8 Transform::postRotate(double radians, const Axis axis)
256 {
257 8 mMap = mMap->postRotate(radians, axis);
258 8 }
259
260 void
261 8 Transform::postTranslate(const Vec3d& t)
262 {
263 8 mMap = mMap->postTranslate(t);
264 8 }
265
266 void
267 3 Transform::postScale(const Vec3d& s)
268 {
269 3 mMap = mMap->postScale(s);
270 3 }
271
272 void
273 Transform::postScale(double s)
274 {
275 const Vec3d vec(s,s,s);
276 mMap = mMap->postScale(vec);
277 }
278
279 void
280 2 Transform::postShear(double shear, Axis axis0, Axis axis1)
281 {
282 2 mMap = mMap->postShear(shear, axis0, axis1);
283 2 }
284
285
286 void
287 4 Transform::postMult(const Mat4d& m)
288 {
289
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (mMap->isLinear()) {
290
291 2 const Mat4d currentMat4 = mMap->getAffineMap()->getMat4();
292 2 const Mat4d newMat4 = currentMat4 * m;
293
294
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 AffineMap::Ptr affineMap{new AffineMap{newMat4}};
295
3/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
6 mMap = simplify(affineMap);
296
297
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 } else if (mMap->isType<NonlinearFrustumMap>()) {
298
299 NonlinearFrustumMap::Ptr currentFrustum =
300 2 StaticPtrCast<NonlinearFrustumMap, MapBase>(mMap);
301
302 const Mat4d currentMat4 = currentFrustum->secondMap().getMat4();
303 2 const Mat4d newMat4 = currentMat4 * m;
304
305
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 AffineMap affine{newMat4};
306
307 NonlinearFrustumMap::Ptr frustum{new NonlinearFrustumMap{
308 currentFrustum->getBBox(),
309 currentFrustum->getTaper(),
310 currentFrustum->getDepth(),
311
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 affine.copy()
312
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 }};
313
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mMap = StaticPtrCast<MapBase, NonlinearFrustumMap>(frustum);
314 }
315
316 4 }
317
318 void
319 Transform::postMult(const Mat3d& m)
320 {
321 Mat4d mat4 = Mat4d::identity();
322 mat4.setMat3(m);
323 postMult(mat4);
324 }
325
326
327 ////////////////////////////////////////
328
329
330 BBoxd
331 221 Transform::indexToWorld(const CoordBBox& indexBBox) const
332 {
333 221 return this->indexToWorld(BBoxd(indexBBox.min().asVec3d(), indexBBox.max().asVec3d()));
334 }
335
336
337 BBoxd
338 2618 Transform::indexToWorld(const BBoxd& indexBBox) const
339 {
340 const Vec3d &imin = indexBBox.min(), &imax = indexBBox.max();
341
342
2/2
✓ Branch 0 taken 20944 times.
✓ Branch 1 taken 2618 times.
23562 Vec3d corners[8];
343 2618 corners[0] = imin;
344 2618 corners[1] = Vec3d(imax(0), imin(1), imin(2));
345 2618 corners[2] = Vec3d(imax(0), imax(1), imin(2));
346 2618 corners[3] = Vec3d(imin(0), imax(1), imin(2));
347 2618 corners[4] = Vec3d(imin(0), imin(1), imax(2));
348 2618 corners[5] = Vec3d(imax(0), imin(1), imax(2));
349 2618 corners[6] = imax;
350 2618 corners[7] = Vec3d(imin(0), imax(1), imax(2));
351
352 BBoxd worldBBox;
353 Vec3d &wmin = worldBBox.min(), &wmax = worldBBox.max();
354
355 2618 wmin = wmax = this->indexToWorld(corners[0]);
356
2/2
✓ Branch 0 taken 18326 times.
✓ Branch 1 taken 2618 times.
20944 for (int i = 1; i < 8; ++i) {
357 18326 Vec3d image = this->indexToWorld(corners[i]);
358 18326 wmin = minComponent(wmin, image);
359 18326 wmax = maxComponent(wmax, image);
360 }
361 2618 return worldBBox;
362 }
363
364
365 BBoxd
366 8 Transform::worldToIndex(const BBoxd& worldBBox) const
367 {
368 Vec3d indexMin, indexMax;
369 8 calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax);
370 8 return BBoxd(indexMin, indexMax);
371 }
372
373
374 CoordBBox
375 2616 Transform::worldToIndexCellCentered(const BBoxd& worldBBox) const
376 {
377 Vec3d indexMin, indexMax;
378 2616 calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax);
379 2616 return CoordBBox(Coord::round(indexMin), Coord::round(indexMax));
380 }
381
382
383 CoordBBox
384 11 Transform::worldToIndexNodeCentered(const BBoxd& worldBBox) const
385 {
386 Vec3d indexMin, indexMax;
387 11 calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax);
388 11 return CoordBBox(Coord::floor(indexMin), Coord::floor(indexMax));
389 }
390
391
392 ////////////////////////////////////////
393
394 // Utility methods
395
396 void
397 9743661 calculateBounds(const Transform& t,
398 const Vec3d& minWS,
399 const Vec3d& maxWS,
400 Vec3d& minIS,
401 Vec3d& maxIS)
402 {
403 /// the pre-image of the 8 corners of the box
404
2/2
✓ Branch 0 taken 77949288 times.
✓ Branch 1 taken 9743661 times.
87692949 Vec3d corners[8];
405 9743661 corners[0] = minWS;
406 9743661 corners[1] = Vec3d(maxWS(0), minWS(1), minWS(2));
407 9743661 corners[2] = Vec3d(maxWS(0), maxWS(1), minWS(2));
408 9743661 corners[3] = Vec3d(minWS(0), maxWS(1), minWS(2));
409 9743661 corners[4] = Vec3d(minWS(0), minWS(1), maxWS(2));
410 9743661 corners[5] = Vec3d(maxWS(0), minWS(1), maxWS(2));
411 9743661 corners[6] = maxWS;
412 9743661 corners[7] = Vec3d(minWS(0), maxWS(1), maxWS(2));
413
414 Vec3d pre_image;
415 9743661 minIS = t.worldToIndex(corners[0]);
416 9743661 maxIS = minIS;
417
2/2
✓ Branch 0 taken 68205627 times.
✓ Branch 1 taken 9743661 times.
77949288 for (int i = 1; i < 8; ++i) {
418 68205627 pre_image = t.worldToIndex(corners[i]);
419
2/2
✓ Branch 0 taken 204616881 times.
✓ Branch 1 taken 68205627 times.
272822508 for (int j = 0; j < 3; ++j) {
420
2/2
✓ Branch 0 taken 38169665 times.
✓ Branch 1 taken 166447216 times.
204616881 minIS(j) = std::min(minIS(j), pre_image(j));
421 204616881 maxIS(j) = std::max(maxIS(j), pre_image(j));
422 }
423 }
424 9743661 }
425
426
427 ////////////////////////////////////////
428
429
430 bool
431 6309 Transform::operator==(const Transform& other) const
432 {
433
2/2
✓ Branch 0 taken 6251 times.
✓ Branch 1 taken 58 times.
6309 if (!this->voxelSize().eq(other.voxelSize())) return false;
434
435
2/2
✓ Branch 2 taken 6244 times.
✓ Branch 3 taken 7 times.
6251 if (this->mapType() == other.mapType()) {
436
2/6
✓ Branch 2 taken 6244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6244 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18732 return this->baseMap()->isEqual(*other.baseMap());
437 }
438
439
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
9 if (this->isLinear() && other.isLinear()) {
440 // promote both maps to mat4 form and compare
441
4/10
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
6 return ( *(this->baseMap()->getAffineMap()) ==
442
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6 *(other.baseMap()->getAffineMap()) );
443 }
444
445
2/6
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15 return this->baseMap()->isEqual(*other.baseMap());
446 }
447
448
449 ////////////////////////////////////////
450
451
452 void
453 Transform::print(std::ostream& os, const std::string& indent) const
454 {
455 struct Local {
456 // Print a Vec4d more compactly than Vec4d::str() does.
457 static std::string rowAsString(const Vec4d& row)
458 {
459 std::ostringstream ostr;
460 ostr << "[" << std::setprecision(3) << row[0] << ", "
461 << row[1] << ", " << row[2] << ", " << row[3] << "] ";
462 return ostr.str();
463 }
464 };
465
466 // Write to a string stream so that I/O manipulators don't affect the output stream.
467 std::ostringstream ostr;
468
469 {
470 Vec3d dim = this->voxelSize();
471 if (dim.eq(Vec3d(dim[0]))) {
472 ostr << indent << std::left << "voxel size: " << std::setprecision(3) << dim[0];
473 } else {
474 ostr << indent << std::left << "voxel dimensions: [" << std::setprecision(3)
475 << dim[0] << ", " << dim[1] << ", " << dim[2] << "]";
476 }
477 ostr << "\n";
478 }
479
480 if (this->isLinear()) {
481 openvdb::Mat4R v2w = this->baseMap()->getAffineMap()->getMat4();
482
483 ostr << indent << std::left << "index to world:\n";
484 for (int row = 0; row < 4; ++row) {
485 ostr << indent << " " << std::left << Local::rowAsString(v2w[row]) << "\n";
486 }
487
488 } else if (this->mapType() == NonlinearFrustumMap::mapType()) {
489 const NonlinearFrustumMap& frustum =
490 static_cast<const NonlinearFrustumMap&>(*this->baseMap());
491 const openvdb::Mat4R linear = this->baseMap()->getAffineMap()->getMat4();
492
493 std::vector<std::string> linearRow;
494 size_t w = 0;
495 for (int row = 0; row < 4; ++row) {
496 std::string str = Local::rowAsString(linear[row]);
497 w = std::max(w, str.size());
498 linearRow.push_back(str);
499 }
500 w = std::max<size_t>(w, 30);
501 const int iw = int(w);
502
503 // Print rows of the linear component matrix side-by-side with frustum parameters.
504 ostr << indent << std::left << std::setw(iw) << "linear:"
505 << " frustum:\n";
506 ostr << indent << " " << std::left << std::setw(iw) << linearRow[0]
507 << " taper: " << frustum.getTaper() << "\n";
508 ostr << indent << " " << std::left << std::setw(iw) << linearRow[1]
509 << " depth: " << frustum.getDepth() << "\n";
510
511 std::ostringstream ostmp;
512 ostmp << indent << " " << std::left << std::setw(iw) << linearRow[2]
513 << " bounds: " << frustum.getBBox();
514 if (ostmp.str().size() < 79) {
515 ostr << ostmp.str() << "\n";
516 ostr << indent << " " << std::left << std::setw(iw) << linearRow[3] << "\n";
517 } else {
518 // If the frustum bounding box doesn't fit on one line, split it into two lines.
519 ostr << indent << " " << std::left << std::setw(iw) << linearRow[2]
520 << " bounds: " << frustum.getBBox().min() << " ->\n";
521 ostr << indent << " " << std::left << std::setw(iw) << linearRow[3]
522 << " " << frustum.getBBox().max() << "\n";
523 }
524
525 } else {
526 /// @todo Handle other map types.
527 }
528
529 os << ostr.str();
530 }
531
532
533 ////////////////////////////////////////
534
535
536 std::ostream&
537 operator<<(std::ostream& os, const Transform& t)
538 {
539 os << "Transform type: " << t.baseMap()->type() << std::endl;
540 os << t.baseMap()->str() << std::endl;
541 return os;
542 }
543
544
545 } // namespace math
546 } // namespace OPENVDB_VERSION_NAME
547 } // namespace openvdb
548