diff --git a/openvdb_3_0_0_library/CHANGES b/openvdb_3_0_0_library/CHANGES deleted file mode 100755 index bc75798..0000000 --- a/openvdb_3_0_0_library/CHANGES +++ /dev/null @@ -1,1082 +0,0 @@ -OpenVDB Version History -======================= - -Version 3.0.0 - January 14, 2015 - - The io::File class now supports delayed loading of .vdb files, - meaning that memory is not allocated for voxel values until the values - are actually accessed. (This feature is enabled by default.) - Until a grid has been fully loaded, its source .vdb file must not be - modified or deleted, so for safety, io::File::open() automatically makes - private copies of source files that are smaller than a user-specified - limit (see io::File::setCopyMaxBytes()). The limit can be set to zero - to disable copying, but if it cannot be guaranteed that a file will not - be modified, then it is best not to enable delayed loading for that file. - - .vdb files can now optionally be compressed with the Blosc LZ4 codec. - Blosc compresses almost as well as ZLIB, but it is much faster. - - Added tools::PointPartitioner, a tool for fast spatial sorting - of points stored in an external array, and tools::PointIndexGrid, - an acceleration structure for fast range and nearest-neighbor searches. - - Added tree::NodeManager, which linearizes a tree to facilitate - efficient multithreading across all tree levels. - - Added tools::prune() (and other variants), which replaces and - outperforms Tree::prune(). - - Added tools::signedFloodFill(), which replaces and outperforms - Tree::signedFloodFill(). - - Added tools::changeBackground (and other variants), which replaces - and outperforms Tree::setBackground(). - - Added a fast but approximate narrow-band level set dilation method, - a fast narrow-band level set erosion method, - and a masked normalization method to tools::LevelSetTracker. - - Added tools::Diagnose, which performs multithreaded diagnostics on grids - to identify issues like values that are NaNs or out-of-range. - It optionally generates a boolean grid of all values that fail - user-defined tests. - - Added optional alpha masks to tools::LevelSetMorphing. - - Fixed an intermittent crash in tools::LevelSetMorphing. - - Added tools::topologyToLevelSet(), which generates a level set - from the implicit boundary between active and inactive voxels - in an arbitrary input grid. - [DWA internal] - - Improved the performance of point scattering (by orders of magnitude) - and added a DenseUniformPointScatter class as well as support for - fractional numbers of particles per voxel. - - Added edge-adjacent (6+12=18 neighbors) and vertex-adjacent (6+12+8=26 - neighbors) dilation algorithms to tools::Morphology::dilateVoxels(). - The default dilation pattern is still face-adjacent (6 neighbors). - - Improved the performance and memory footprint of the ParticlesToLevelSet - tool for large numbers (tens to hundreds of millions) of particles. - - Added Tree::getNodes(), which allows for fast construction of - linear arrays of tree nodes for use in multithreaded code - such as the LeafManager or NodeManager. - - Added math::Extrema and tools::extrema() to efficiently compute - minimum and maximum values in a grid. - - Added support for material color grids to all level set shaders, - and added an option to vdb_render that allows one to specify a - reference grid to be used for material color lookups. - - Added openvdb::getLibraryVersionString() and - OPENVDB_LIBRARY_VERSION_STRING. - - Modified the mesh to volume converter to always set the grid background - value to the exterior narrow-band width, and added finite value checks - to narrow band parameters. - - tools::volumeToMesh() now compiles for all grid types but throws an - exception if the input grid does not have a scalar value type. - - Added an io::File::readGrid() overload and readBuffers() overloads - to the grid, tree and node classes that allow one to specify - a bounding box against which to clip a grid while reading it. - For large grids, clipping while reading can result in significantly - lower memory usage than clipping after reading. - - Added Grid::clipGrid(), which clips a grid against a world-space - bounding box, and Grid::clip() and Tree::clip(), which clip against - an index-space bounding box. - - Added tools::clip(), which clips a grid either against a bounding box - or against the active voxels of a mask grid. - - io::File::readGridPartial() allocates the nodes of a grid's tree - as before, but it now allocates leaf nodes without data buffers. - (This feature is mainly for internal use; partially-read grids should be - used with care if at all, and they should be treated as read-only.) - - Grid names retrieved using an io::File::NameIterator now always uniquely - identify grids; they no longer generate 'more than one grid named "x"' - warnings when there are multiple grids of the same name in a file - (for files written starting with this version of the OpenVDB library). - - Fixed a bug in Tree::ValueOffIter that could cause depth-bounded - iterators to return incorrect values. - - Eliminated a recursive call in TreeValueIteratorBase::advance() that - could cause crashes on systems with a limited stack size. - - Fixed memory leaks in RootNode::topologyDifference() and - RootNode::topologyIntersection(). - - Fixed a memory leak in io::Queue when the queue was full and - a write task could not be added within the timeout interval. - - Fixed a potential division by zero crash in tools::compDiv() - with integer-valued grids. - - Fixed kernel normalization in tools::Filter so that it is correct - for integer-valued grids. - - Fixed a bug in LeafNode::Buffer::getValue() whereby Visual C++ - would return a reference to a temporary. - [Contributed by SESI] - - Fixed a bug in tools::ParticlesToLevelSet related to attribute transfer - when leaf nodes are produced without active values. - - Added util/CpuTimer.h and removed the more simplistic CpuTimer - from unittest/util.h. - - Eliminated the use of getopt() for command-line argument parsing - in vdb_test. - - openvdb::initialize() now properly initializes log4cplus if it is - enabled, eliminating "No appenders could be found" errors. - - Fixed a bug in the QuantizedUnitVec::pack() method that caused - quantization artifacts. - - Added convenience class tools::AlphaMask to tools/Interpolation.h - - Added constructors and methods to both math::RandInt and math::Rand01 - to set and reset the random seed value. - - Added convenience methods for transforming bounding boxes to - math::Transform. - - vdb_view is now compatible with both GLFW 2 and GLFW 3. - - Made many small changes to address type conversion and other warnings - reported by newer compilers like GCC 4.8 and ICC 14. - - Replaced the HALF_INCL_DIR and HALF_LIB_DIR Makefile variables - with ILMBASE_INCL_DIR and ILMBASE_LIB_DIR and added ILMBASE_LIB, - to match OpenEXR's library organization. - [Contributed by Double Negative] - - Eliminated most local (function-scope) static variables, because - Visual C++ doesn't guarantee thread-safe initialization of local statics. - [Contributed by SESI] - - Fixed a bug in readString() related to empty strings. - [Contributed by Fabio Piparo] - - Fixed a bug in the tools::VolumeToMesh simplification scheme that - was creating visual artifacts. - - API changes: - - The addition of a GridBase::readBuffers() virtual function overload - and the GridBase::clip(), GridBase::readNonresidentBuffers() and - Tree::clipUnallocatedNodes() virtual functions changes the grid ABI - so that it is incompatible with earlier versions of the OpenVDB library - (such as the ones in Houdini 12.5 and 13). Define the macro - OPENVDB_2_ABI_COMPATIBLE when compiling OpenVDB to disable these changes - and preserve ABI compatibility. - - All shaders now have a template argument to specify the type of - an optional material color grid, but the default type mimics - the old, uniform color behavior. - - Removed a deprecated io::Stream::write() overload. - - The point counts in the UniformPointScatter and NonUniformPointScatter - tools are now specified and returned as Index64. - - math::RandInt has an extra template argument to specify the integer - type. The RandomInt typedef is unchanged. - - io::readData(), io::HalfReader::read() and io::HalfWriter::write() now - take a uint32_t argument indicating the type of compression instead of - a bool indicating whether compression is enabled. - - Removed io::Archive::isCompressionEnabled() and - io::Archive::setCompressionEnabled() and renamed - io::Archive::compressionFlags() and io::Archive::setCompressionFlags() - to io::Archive::compression() and io::Archive::setCompression(). - - Internal and leaf node classes are now required to provide - "PartialCreate" constructors that optionally bypass the allocation - of voxel buffers. Leaf node classes must now also provide allocate() - and isAllocated() methods to manage the allocation of their buffers. - - Removed pruneInactive() and pruneLevelSet() methods from the Tree - and various node classes. These methods have been replaced by - the much faster pruning functions found in tools/Prune.h. - - Removed signedFloodFill() methods from the Grid, Tree and various - node classes. These methods have been replaced by the much faster - functions found in tools/SignedFloodFill.h. - - Removed Grid::setBackground() and Tree::setBackground() (use the faster - changeBackground() tool instead), and removed the default argument - from RootNode::setBackground(). - - Python: - - Added grid methods convertToPolygons() and convertToQuads(), - which convert volumes to meshes, and createLevelSetFromPolygons(), - which converts meshes to volumes. NumPy is required. - - Maya: - - Added an adaptive polygonal surface extraction node. - - Houdini: - - Added a new Resize Narrow Band SOP that can efficiently adjust the width - of a level set's narrow band. This allows, for example, for a level set - to be created quickly from points or polygons with a very narrow band - that is then quickly resized to a desired width. - - Fixed bugs in the Smooth Level Set and Reshape Level Set SOPs that - caused them to ignore the selected discretization scheme. - - Added a Morph Level Set SOP. - - Added a From Points SOP to very quickly generate a level set - from a point cloud, ignoring any radius attribute. - [DWA internal] - - Added a Voxel Scale mode to the Resample SOP. - - Improved the performance and memory footprint of the From Particles SOP - for large numbers (tens to hundreds of millions) of particles. - - The Scatter SOP now accepts fractional numbers of particles per voxel. - - Improved the performance of the Scatter SOP by more than an order - of magnitude. - - The Clip SOP now has a toggle to choose explicitly between a mask grid - or a bounding box as the clipping region. As a consequence, the - mask grid can now be unnamed. - - Added the OpenVDB library version number to the Extended Operator - Information for all SOPs. - - SOPs are now linked with an rpath to the directory containing the - OpenVDB library. - - Like the native Houdini file SOP, the Read SOP now allows missing frames - to be reported either as errors or as warnings. - - The Read SOP now has an optional input for geometry, the bounding box - of which can be used to clip grids as they are read. For large grids, - clipping while reading can result in significantly lower memory usage - than clipping after reading. - - The From Polygons and Convert SOPs now default to using the polygon soup - mesh representation, which uses less memory. - -Version 2.3.0 - April 23, 2014 - - Added tools::extractSparseTree(), which selectively extracts and - transforms data from a dense grid to produce a sparse tree, - and tools::extractSparseTreeWithMask(), which copies data from - the index-space intersection of a sparse tree and a dense input grid. - - Added copy constructors to the Grid, Tree, RootNode, InternalNode - and LeafNode classes, and an assignment operator overload to RootNode, - that allow the source and destination to have different value types. - - Modified Tree::combine2() to permit combination of trees with different - value types. - - Added CanConvertType and RootNode::SameConfiguration metafunctions, - which perform compile-time tests for value type and tree type - compatibility, and a RootNode::hasCompatibleValueType() method, - which does runtime checking. - - Added optional support for logging using log4cplus. See logging.h - and the INSTALL file for details. - - Added VolumeRayIntersector::hits(), which returns all the hit segments - along a ray. This is generally more efficient than repeated calls - to VolumeRayIntersector::march(). - - Added member class Ray::TimeSpan and method Ray::valid(), and - deprecated method Ray::test(). - - Fixed a bug in VolumeHDDA that could cause rendering artifacts - when a ray's start time was zero. - [Contributed by Mike Farnsworth] - - Added tools::compositeToDense(), which composites data from a - sparse tree into a dense array, using a sparse alpha mask. - Over, Add, Sub, Min, Max, Mult, and Set are supported operations. - - Added tools::transformDense(), which applies a functor to the value - of each voxel of a dense grid within a given bounding box. - - Improved the performance of node iterators. - - API changes: - - Collected the digital differential analyzer code from math/Ray.h - and tools/RayIntersector.h into a new header file, math/DDA.h. - - Rewrote VolumeHDDA and made several changes to its API. (VolumeHDDA - is used internally by VolumeRayIntersector, whose API is unchanged.) - - Tree::combine2(), RootNode::combine2(), InternalNode::combine2(), - LeafNode::combine2() and CombineArgs all now require an additional - template argument, which determines the type of the other tree. - - Assignment operators for LeafManager::LeafRange::Iterator, - BaseMaskIterator, NodeMask and RootNodeMask now return references - to the respective objects. - - Removed a number of methods that were deprecated in version 2.0.0 - or earlier. - - Houdini: - - Added a Clip SOP, which does volumetric clipping. - - Added an Occlusion Mask SOP, which generates a mask of the voxels - inside a camera frustum that are occluded by objects in an input grid. - - The Combine SOP now applies the optional signed flood fill only to - level set grids, since that operation isn't meaningful for other grids. - - The Filter SOP now processes all grid types, not just scalar grids. - -Version 2.2.0 - February 20, 2014 - - Added a simple, multithreaded volume renderer, and added volume - rendering support to the vdb_render command-line renderer. - - Added an option to the LevelSetRayIntersector and to vdb_render - to specify the isovalue of the level set. - - Added methods to the LevelSetRayIntersector to return the time of - intersection along a world or index ray and to return the level set - isovalue. - - Improved the performance of the VolumeRayIntersector and added - support for voxel dilation to account for interpolation kernels. - - Added a section to the Cookbook on interpolation using BoxSampler, - GridSampler, DualGridSampler, et al. - - Added a section to the Overview on grids and grid metadata. - - Modified tools::DualGridSampler so it is more consistent with - tools::GridSampler. - - tools::cpt(), tools::curl(), tools::laplacian(), tools::meanCurvature() - and tools::normalize() now output grids with appropriate vector types - (covariant, contravariant, etc.). - - Added tools::transformVectors(), which applies an affine transformation - to the voxel values of a vector-valued grid in accordance with the - grid's Vector Type and World Space/Local Space metadata setting. - - Added tools::compDiv(), which combines grids by dividing the values - of corresponding voxels. - - Fixed a bug in the mean curvature computation that could produce NaNs - in regions with constant values. - - Added a Grid::topologyDifference() method. - - Added exp() and sum() methods to math::Vec2, math::Vec3 and math::Vec4. - - Improved tools::fillWithSpheres() for small volumes that are just a few - voxels across. - - Improved the accuracy of the mesh to volume converter. - - Fixed a bug in the mesh to volume converter that caused incorrect sign - classifications for narrow-band level sets. - - Fixed a bug in NonlinearFrustumMap::applyIJT() that resulted in incorrect - values when computing the gradient of a grid with a frustum transform. - - Fixed a file I/O bug whereby some .vdb files could not be read correctly - if they contained grids with more than two distinct inactive values. - - Fixed an off-by-one bug in the numbering of unnamed grids in .vdb files. - The first unnamed grid in a file is now retrieved using the name "[0]", - instead of "[1]". - - Fixed a build issue reported by Clang 3.2 in tools/GridOperators.h. - - Fixed a memory leak in tools::Film. - - Added library and file format version number constants to the - Python module. - - Improved convergence in the volume renderer. - [Contributed by Jerry Tessendorf and Mark Matthews] - - Made various changes for compatibility with Houdini 13 and with - C++11 compilers. - [Contributed by SESI] - - API changes: - - tools::VolumeRayIntersector::march() no longer returns an int - to distinguish tile vs. voxel hits. Instead, it now returns false - if no intersection is detected and true otherwise. Also, t0 and t1 - might now correspond to the first and last hits of multiple adjacent - leaf nodes and/or active tiles. - - tools::DualGridSampler is no longer templated on the target grid type, - and the value accessor is now passed as an argument. - - The .vdb file format has changed slightly. Tools built with older - versions of OpenVDB should be recompiled to ensure that they can read - files in the new format. - - Houdini: - - Added topology union, intersection and difference operations to - the Combine SOP. These operations combine the active voxel topologies - of grids that may have different value types. - - Added a Divide operation to the Combine SOP. - - Added support for boolean grids to the Combine, Resample, Scatter, Prune - and Visualize SOPs. - - The Fill SOP now accepts a vector as the fill value, and it allows - the fill region bounds to be specified either in index space (as before), - in world space, or using the bounds of geometry connected to an optional - new reference input. - - Added a toggle to the Offset Level Set SOP to specify the offset in - either world or voxel units. - - Added a toggle to the Transform and Resample SOPs to apply the - transform to the voxel values of vector-valued grids, in accordance with - those grids' Vector Type and World Space/Local Space metadata settings. - - Added a Vector Type menu to the Vector Merge SOP. - - Removed masking options from the Renormalize SOP (since masking is - not supported yet). - - Reimplemented the Vector Merge SOP for better performance and - interruptibility and to fix a bug in the handling of tile values. - -Version 2.1.0 - December 12, 2013 - - Added a small number of Maya nodes, primarily for conversion of geometry - to and from OpenVDB volumes and for visualization of volumes. - - Added an initial implementation of level set morphing (with improvements - to follow soon). - - Added tools::LevelSetMeasure, which efficiently computes the surface area, - volume and average mean-curvature of narrow-band level sets, in both - world and voxel units. Those quantities are now exposed as intrinsic - attributes on the Houdini VDB primitive and can be queried using the - native Measure SOP. - - tools::Dense now supports the XYZ memory layout used by Houdini and Maya - in addition to the ZYX layout used in OpenVDB trees. - - Improved the performance of masking in the level set filter tool and - added inversion and scaling of the mask input, so that any scalar-valued - volume can be used as a mask, not just volumes with a [0, 1] range. - - Added optional masking to the non-level-set filters, to the grid - operators (CPT, curl, divergence, gradient, Laplacian, mean curvature, - magnitude, and normalize) and to the Analysis and Filter SOPs. - - Added more narrow band controls to the Rebuild Level Set SOP. - - Improved the accuracy of the level set rebuild tool. - - Added tools::activate() and tools::deactivate(), which set the active - states of tiles and voxels whose values are equal to or approximately - equal to a given value, and added a Deactivate Background Voxels toggle - to the Combine SOP. - - Added math::BBox::applyMap() and math::BBox::applyInverseMap(), which - allow for transformation of axis-aligned bounding boxes. - - Added a position shader to the level set ray-tracer (primarily for - debugging purposes). - - Added an io::Queue class that manages a concurrent queue for - asynchronous serialization of grids to files or streams. - - Fixed a bug in io::Archive whereby writing unnamed, instanced grids - (i.e., grids sharing a tree) to a file rendered the file unreadable. - - Fixed a bug in the volume to mesh converter that caused it to generate - invalid polygons when the zero crossing lay between active and inactive - regions. - - Fixed a bug in the point scatter tool (and the Scatter SOP) whereby - the last voxel always remained empty. - - Fixed a bug in the Read SOP that caused grids with the same name - to be renamed with a numeric suffix (e.g., "grid[1]", "grid[2]", etc.). - - Fixed some unit test failures on 64-bit Itanium machines. - - API changes: - - The Filter tool is now templated on a mask grid, and threading is - controlled using a grain size, for consistency with most of the - other level set tools. - - The level set filter tool is now templated on a mask grid. - - All shaders now take a ray direction instead of a ray. - -Version 2.0.0 - October 31, 2013 - - Added a Python module with functions for basic manipulation of grids - (but no tools, yet). - - Added ray intersector tools for efficient, hierarchical intersection - of rays with level-set and generic volumes. - - Added a Ray class and a hierarchical Digital Differential Analyzer - for fast ray traversal. - - Added a fully multithreaded level set ray tracer and camera classes - that mimic Houdini's cameras. - - Added a simple, command-line renderer (currently for level sets only). - - Implemented a new meshing scheme that produces topologically robust - two-manifold meshes and is twice as fast as the previous scheme. - - Implemented a new, topologically robust (producing two-manifold meshes) - level-set-based seamless fracture scheme. The new scheme eliminates - visible scarring seen in the previous implementation by subdividing - internal, nonplanar quads near fracture seams. In addition, - fracture seam points are now tagged, allowing them to be used - to drive pre-fracture dynamics such as local surface buckling. - - Improved the performance of Tree::evalActiveVoxelBoundingBox() and - Tree::activeVoxelCount(), and significantly improved the performance - of Tree::evalLeafBoundingBox() (by about 30x). - - Added a tool (and a Houdini SOP) that fills a volume with - adaptively-sized overlapping or non-overlapping spheres. - - Added a Ray SOP that can be used to perform geometry projections - using level-set ray intersections or closest-point queries. - - Added a tool that performs accelerated closest surface point queries - from arbitrary points in world space to narrow-band level sets. - - Increased the speed of masked level set filtering by 20% for - the most common cases. - - Added math::BoxStencil, with support for trilinear interpolation - and gradient computation. - - Added Tree::topologyIntersection(), which intersects a tree's active - values with those of another tree, and Tree::topologyDifference(), - which performs topological subtraction of one tree's active values - from another's. In both cases, the ValueTypes of the two trees - need not be the same. - - Added Tree::activeTileCount(), which returns the number of active tiles - in a tree. - - Added math::MinIndex() and math::MaxIndex(), which find the minimum - and maximum components of a vector without any branching. - - Added math::BBox::minExtent(), which returns a bounding box's - shortest axis. - - The default math::BBox constructor now generates an invalid bounding - box rather than an empty bounding box positioned at the origin. - The new behavior is consistent with math::CoordBBox. - [Thanks to Rick Hankins for suggesting this fix.] - - Added CoordBBox::reset(), which resets a bounding box to its initial, - invalid state. - - Fixed a bug in the default ScaleMap constructor that left some data - used in the inverse uninitialized. - - Added MapBase::applyJT(), which applies the Jacobian transpose to - a vector (the Jacobian transpose takes a range-space vector to a - domain-space vector, e.g., world to index), and added - MapBase::inverseMap(), which returns a new map representing - the inverse of the original map (except for NonlinearFrustumMap, - which does not currently have a defined inverse map). - Note: Houdini 12.5 uses an earlier version of OpenVDB, and maps - created with that version lack virtual table entries for these - new methods, so do not call these methods from Houdini 12.5. - - Reimplemented math::RandomInt using Boost.Random instead of rand() - (which is not thread-safe), and deprecated math::randUniform() - and added math::Random01 to replace it. - - Modified tools::copyFromDense() and tools::copyToDense() to allow - for implicit type conversion (e.g., between a Dense and a - FloatTree) and fixed several bugs in tools::CopyFromDense. - - Fixed bugs in math::Stats and math::Histogram that could produce - NaNs or other incorrect behavior if certain methods were called - on populations of size zero. - - Renamed tolerance to math::Tolerance and negative() to - math::negative() and removed math::toleranceValue(). - - Implemented a closest point on line segment algorithm, - math::closestPointOnSegmentToPoint(). - - Fixed meshing issues relating to masking and automatic partitioning. - - Grid::merge() and Tree::merge() now accept an optional MergePolicy - argument that specifies one of three new merging schemes. (The old - merging scheme, which is no longer available, used logic for each tree - level that was inconsistent with the other levels and that could result - in active tiles being replaced with nodes having only inactive values.) - - Renamed LeafNode::coord2offset(), LeafNode::offset2coord() and - LeafNode::offset2globalCoord() to coordToOffset(), offsetToLocalCoord() - and offsetToGlobalCoord(), respectively, and likewise for InternalNode. - [Thanks to Rick Hankins for suggesting this change.] - - Replaced Tree methods setValueOnMin(), setValueOnMax() and - setValueOnSum() with tools::setValueOnMin(), tools::setValueOnMax() and - tools::setValueOnSum() (and a new tools::setValueOnMult()) and added - Tree::modifyValue() and Tree::modifyValueAndActiveState(), which modify - voxel values in place via user-supplied functors. Similarly, replaced - ValueAccessor::setValueOnSum() with ValueAccessor::modifyValue() - and ValueAccessor::modifyValueAndActiveState(), and added a modifyValue() - method to all value iterators. - - Removed LeafNode::addValue() and LeafNode::scaleValue(). - - Added convenience classes Tree3 and Tree5 for custom tree configurations. - - Added an option to the From Particles SOP to generate an alpha mask, - which can be used to constrain level set filtering so as to preserve - surface details. - - The mesh to volume converter now handles point-degenerate polygons. - - Fixed a bug in the Level Set Smooth, Level Set Renormalize and - Level Set Offset SOPs that caused the group name to be ignored. - - Fixed various OS X and Windows build issues. - [Contributions from SESI and DD] - -Version 1.2.0 - June 28, 2013 - - Level set filters now accept an optional alpha mask grid. - - Implemented sharp feature extraction for level set surfacing. - This enhances the quality of the output mesh and reduces aliasing - artifacts. - - Added masking options to the meshing tools, as well as a spatial - multiplier for the adaptivity threshold, automatic partitioning, - and the ability to preserve edges and corners when mesh adaptivity - is applied. - - The mesh to volume attribute transfer scheme now takes surface - orientation into account, which improves accuracy in proximity to - edges and corners. - - Added a foreach() method to tools::LeafManager that, like - tools::foreach(), applies a user-supplied functor to each leaf node - in parallel. - - Rewrote the particle to level set converter, simplifying the API, - improving performance (especially when particles have a fixed radius), - adding the capability to transfer arbitrary point attributes, - and fixing a velocity trail bug. - - Added utility methods Sign(), SignChange(), isApproxZero(), Cbrt() - and ZeroCrossing() to math/Math.h. - - Added a probeNode() method to the value accessor and to tree nodes - that returns a pointer to the node that contains a given voxel. - - Deprecated LeafNode::addValue() and LeafNode::scaleValue(). - - Doubled the speed of the mesh to volume converter (which also improves - the performance of the fracture and level set rebuild tools) and - improved its inside/outside voxel classification near edges and corners. - - tools::GridSampler now accepts either a grid, a tree or a value accessor, - and it offers faster index-based access methods and much better - performance in cases where many instances are allocated. - - Extended tools::Dense to make it more compatible with existing tools. - - Fixed a crash in io::Archive whenever the library was unloaded - from memory and then reloaded. - [Contributed by Ollie Harding] - - Fixed a bug in GU_PrimVDB::buildFromPrimVolume(), seen during the - conversion from Houdini volumes to OpenVDB grids, that could cause - signed flood fill to be applied to non-level set grids, resulting in - active tiles with incorrect values. - - Added a Prune SOP with several pruning schemes. - -Version 1.1.1 - May 10 2013 - - Added a simple dense grid class and tools to copy data from - dense voxel arrays into OpenVDB grids and vice-versa. - - Starting with Houdini 12.5.396, plugins built with this version - of OpenVDB can coexist with native Houdini OpenVDB nodes. - - The level set fracture tool now smooths seam line edges during - mesh extraction, eliminating staircase artifacts. - - Significantly improved the performance of the - util::leafTopologyIntersection() and util::leafTopologyDifference() - utilities and added a LeafNode::topologyDifference() method. - - Added convenience functions that provide simplified interfaces - to the mesh to volume and volume to mesh converters. - - Added a tools::accumulate() function that is similar to tools::foreach() - but can be used to accumulate the results of computations over - the values of a grid. - - Added tools::statistics(), tools::opStatistics() and tools::histogram(), - which efficiently compute statistics (mean, variance, etc.) and - histograms of grid values (using math::Stats and math::Histogram). - - Modified CoordBBox to adhere to TBB's splittable type requirements, - so that, for example, a CoordBBox can be used as a blocked - iteration range. - - Added Tree::addTile(), Tree::addLeaf() and Tree::stealNode(), for - fine control over tree construction. - - Addressed a numerical stability issue when performing Gaussian - filtering of level set grids. - - Changed the return type of CoordBBox::volume() to reduce the risk - of overflow. - - When the input mesh is self-intersecting, the mesh to volume converter - now produces a level set with a monotonic gradient field. - - Fixed a threading bug in the mesh to volume converter that caused it - to produce different results for the same input. - - Fixed a bug in the particle to level set converter that prevented - particles with zero velocity from being rasterized in Trail mode. - - Added an optional input to the Create SOP into which to merge - newly-created grids. - - Fixed a bug in the Resample SOP that caused it to produce incorrect - narrow-band widths when resampling level set grids. - - Fixed a bug in the To Polygons SOP that caused intermittent crashes - when the optional reference input was connected. - - Fixed a bug in the Advect Level Set SOP that caused a crash - when the velocity input was connected but empty. - - The Scatter and Sample Point SOPs now warn instead of erroring - when given empty grids. - - Fixed a crash in vdb_view when stepping through multiple grids - after changing render modes. - - vdb_view can now render fog volumes and vector fields, and it now - features interactively adjustable clipping planes that enable - one to view the interior of a volume. - -Version 1.1.0 - April 4 2013 - - The resampleToMatch() tool, the Resample SOP and the Combine SOP - now use level set rebuild to correctly and safely resample level sets. - Previously, scaling a level set would invalidate the signed distance - field, leading to holes and other artifacts. - - Added a mask-based topological erosion tool, and rewrote and simplified - the dilation tool. - - The LevelSetAdvection tool can now advect forward or backward in time. - - Tree::pruneLevelSet() now replaces each pruned node with a tile having - the inside or outside background value, instead of arbitrarily selecting - one of the node's tile or voxel values. - - When a grid is saved to a file with saveFloatAsHalf() set to true, - the grid's background value is now also quantized to 16 bits. - (Not quantizing the background value caused a mismatch with the values - of background tiles.) - - As with tools::foreach(), it is now possible to specify whether functors - passed to tools::transformValues() should be shared across threads. - - tree::LeafManager can now be instantiated with a const tree, - although buffer swapping with const trees is disabled. - - Added a Grid::signedFloodFill() overload that allows one to specify - inside and outside values. - - Fixed a bug in Grid::setBackground() so that now only the values of - inactive voxels change. - - Fixed Grid::topologyUnion() so that it actually unions tree topology, - instead of just the active states of tiles and voxels. The previous - behavior broke multithreaded code that relied on input and output grids - having compatible tree topology. - - math::Transform now includes an isIdentity() predicate and methods - to pre- and postmultiply by a matrix. - - Modified the node mask classes to permit octree-like tree configurations - (i.e., with a branching factor of two) and to use 64-bit operations - instead of 32-bit operations. - - Implemented a new, more efficient closest point on triangle algorithm. - - Implemented a new vertex normal scheme in the volume to mesh - converter, and resolved some overlapping polygon issues. - - The volume to mesh converter now meshes not just active voxels - but also active tiles. - - Fixed a bug in the mesh to volume converter that caused unsigned - distance field conversion to produce empty grids. - - Fixed a bug in the level set fracture tool whereby the cutter overlap - toggle was ignored. - - Fixed an infinite loop bug in vdb_view. - - Updated vdb_view to use the faster and less memory-intensive - OpenVDB volume to mesh converter instead of marching cubes, - and rewrote the shader to be OpenGL 3.2 and GLSL 1.2 compatible. - - Given multiple input files or a file containing multiple grids, - vdb_view now displays one grid at a time. The left and right - arrow keys cycle between grids. - - The To Polygons SOP now has an option to associate the input grid's - name with each output polygon. - -Version 1.0.0 - March 14 2013 - - tools::levelSetRebuild() now throws an exception when given a - non-scalar or non-floating-point grid. - - The tools in tools/GridOperators.h are now interruptible, as is - the Analysis SOP. - - Added a leaf node iterator and a TBB-compatible range class to - the LeafManager. - - Modified the VolumeToMesh tool to handle surface topology issues - around fracture seam lines. - - Modified the Makefile to allow vdb_view to compile on OS X systems - (provided that GLFW is available). - - Fixed a bug in the Create SOP that resulted in "invalid parameter name" - warnings. - - The Combine SOP now optionally resamples the A grid into the B grid's - index space (or vice-versa) if the A and B transforms differ. - - The Vector Split and Vector Merge SOPs now skip inactive voxels - by default, but they can optionally be made to include inactive voxels, - as they did before. - - The LevelSetFracture tool now supports custom rotations for each - cutter instance, and the Fracture SOP now uses quaternions to generate - uniformly-distributed random rotations. - -Version 0.104.0 - February 15 2013 - - Added a tool and a SOP to rebuild a level set from any scalar volume. - - .vdb files are now saved using a mask-based compression scheme - that is an order of magnitude faster than ZLIB and produces comparable - file sizes for level set and fog volume grids. (ZLIB compression - is still enabled by default for other classes of grids). - - The Filter and LevelSetFilter tools now include a Gaussian filter, - and mean (box) filtering is now 10-50x faster. - - The isosurface meshing tool is now more robust (to level sets - with one voxel wide narrow bands, for example). - - Mesh to volume conversion is on average 1.5x faster and up to 5.5x - faster for high-resolution meshes where the polygon/voxel size ratio - is small. - - Added createLevelSet() and createLevelSetSphere() factory functions - for level set grids. - - tree::ValueAccessor is now faster for trees of height 2, 3 and 4 - (the latter is the default), and it now allows one to specify, - via a template argument, the number of node levels to be cached, - which can also improve performance in special cases. - - Added a toggle to tools::foreach() to specify whether or not - the functor should be shared across threads. - - Added Mat4s and Mat4d metadata types. - - Added explicit pre- and postmultiplication methods to the Transform, - Map and Mat4 classes and deprecated the old accumulation methods. - - Modified NonlinearFrustumMap to be more compatible with Houdini's - frustum transform. - - Fixed a GridTransformer bug that caused it to translate the - output grid incorrectly in some cases. - - Fixed a bug in the tree-level LeafIterator that resulted in - intermittent crashes in tools::dilateVoxels(). - - The Hermite data type and Hermite grids are no longer supported. - - Added tools/GridOperators.h, which includes new, cleaner implementations - of the Cpt, Curl, Divergence, Gradient, Laplacian, Magnitude, - MeanCurvature and Normalize tools. - - Interrupt support has been improved in several tools, including - tools::ParticlesToLevelSet. - - Simplified the API of the Stencil class and added an intersects() - method to test for intersection with a specified isovalue. - - Renamed voxelDimensions to voxelSize in transform classes and elsewhere. - - Deprecated houdini_utils::ParmFactory::setChoiceList() in favor of - houdini_utils::ParmFactory::setChoiceListItems(), which requires - a list of token, label string pairs. - - Made various changes for Visual C++ compatibility. - [Contributed by SESI] - - Fixed a bug in houdini_utils::getNodeChain() that caused the - Offset Level Set, Smooth Level Set and Renormalize Level Set SOPs - to ignore frame changes. - [Contributed by SESI] - - The From Particles SOP now provides the option to write into - an existing grid. - - Added a SOP to edit grid metadata. - - The Fracture SOP now supports multiple cutter objects. - - Added a To Polygons SOP that complements the Fracture SOP and allows - for elimination of seam lines, generation of correct vertex normals - and grouping of polygons when surfacing fracture fragments, using - the original level set or mesh as a reference. - -Version 0.103.1 - January 15 2013 - - tree::ValueAccessor read operations are now faster for four-level trees. - (Preliminary benchmark tests suggest a 30-40% improvement.) - - For vector-valued grids, tools::compMin() and tools::compMax() - now compare vector magnitudes instead of individual components. - - Migrated grid sampling code to a new file, Interpolation.h, - and deprecated old files and classes. - - Added a level-set fracture tool and a Fracture SOP. - - Added tools::sdfInteriorMask(), which creates a mask of the - interior region of a level set grid. - - Fixed a bug in the mesh to volume converter that produced unexpected - nonzero values for voxels at the intersection of two polygons, - and another bug that produced narrow-band widths that didn't respect - the background value when the half-band width was less than three voxels. - - houdini_utils::ParmFactory can now correctly generate ramp multi-parms. - - Made various changes for Visual C++ compatibility. - [Contributed by SESI] - - The Convert SOP can now convert between signed distance fields and - fog volumes and from volumes to meshes. - [Contributed by SESI] - - For level sets, the From Mesh and From Particles SOPs now match - the reference grid's narrow-band width. - - The Scatter SOP can now optionally scatter points in the interior - of a level set. - -Version 0.103.0 - December 21 2012 - - The mesh to volume converter is now 60% faster at generating - level sets with wide bands, and the From Mesh SOP is now interruptible. - - Fixed a threading bug in the recently-added compReplace() tool - that caused it to produce incorrect output. - - Added a probeConstLeaf() method to the Tree, ValueAccessor and - node classes. - - The Houdini VDB primitive doesn't create a "name" attribute - unnecessarily (i.e., if its grid's name is empty), but it now - correctly allows the name to be changed to the empty string. - - Fixed a crash in the Vector Merge SOP when fewer than three grids - were merged. - - The From Particles SOP now features a "maximum half-width" parameter - to help avoid runaway computations. - -Version 0.102.0 - December 13 2012 - - Added tools::compReplace(), which copies the active values of one grid - into another, and added a "Replace A With Active B" mode to the - Combine SOP. - - Grid::signedFloodFill() no longer enters an infinite loop when - filling an empty grid. - - Fixed a bug in the particle to level set converter that sometimes - produced level sets with holes, and fixed a bug in the SOP that - could result in random output. - - Fixed an issue in the frustum preview feature of the Create SOP - whereby rendering very large frustums could cause high CPU usage. - - Added streamline support to the constrained advection scheme - in the Advect Points SOP. - - Added an Advect Level Set SOP. - -Version 0.101.1 - December 11 2012 (DWA internal release) - - Partially reverted the Houdini VDB primitive's grid accessor methods - to their pre-0.98.0 behavior. A primitive's grid can once again - be accessed by shared pointer, but now also by reference. - Accessor methods for grid metadata have also been added, and the - primitive now ensures that metadata and transforms are never shared. - - Fixed an intermittent crash in the From Particles SOP. - -Version 0.101.0 - December 6 2012 (DWA internal release) - - Partially reverted the Grid's tree and transform accessor methods - to their pre-0.98.0 behavior, eliminating copy-on-write but - preserving their return-by-reference semantics. These methods - are now supplemented with a suite of shared pointer accessors. - - Restructured the mesh to volume converter for a 40% speedup - and to be more robust to non-manifold geometry, to better preserve - sharp features, to support arbitrary tree configurations and - to respect narrow-band limits. - - Added a getNodeBoundingBox() method to RootNode, InternalNode - and LeafNode that returns the index space spanned by a node. - - Made various changes for Visual C++ compatibility. - [Contributed by SESI] - - Renamed the Reshape Level Set SOP to Offset Level Set. - - Fixed a crash in the Convert SOP and added support for conversion - of empty grids. - -Version 0.100.0 - November 30 2012 (DWA internal release) - - Greatly improved the performance of the level set to fog volume - converter. - - Improved the performance of the median filter and of level set - CSG operations. - - Reintroduced Tree::pruneLevelSet(), a specialized pruneInactive() - for level-set grids. - - Added utilities to the houdini_utils library to facilitate the - collection of a chain of adjacent nodes of a particular type - so that they can be cooked in a single step. (For example, - adjacent xform SOPs could be collapsed by composing their - transformation matrices into a single matrix.) - - Added pruning and flood-filling options to the Convert SOP. - - Reimplemented the Filter SOP, omitting level-set-specific filters - and adding node chaining (to reduce memory usage when applying - several filters in sequence). - - Added a toggle to the Read SOP to read grid metadata and - transforms only. - - Changed the attribute transfer scheme on the From Mesh and - From Particles SOPs to allow for custom grid names and - vector type metadata. - -Version 0.99.0 - November 21 2012 - - Added Grid methods that return non-const Tree and Transform - references without triggering deep copies, as well as const - methods that return const shared pointers. - - Added Grid methods to populate a grid's metadata with statistics - like the active voxel count, and to retrieve that metadata. - By default, statistics are now computed and added to grids - whenever they are written to .vdb files. - - Added io::File::readGridMetadata() and io::File::readAllGridMetadata() - methods to read just the grid metadata and transforms from a .vdb file. - - Fixed numerical precision issues in the csgUnion, csgIntersection - and csgDifference tools, and added toggles to optionally disable - postprocess pruning. - - Fixed an issue in vdb_view with the ordering of GL vertex buffer calls. - [Contributed by Bill Katz] - - Fixed an intermittent crash in the ParticlesToLevelSet tool, - as well as a race condition that could cause data corruption. - - The ParticlesToLevelSet tool and From Particles SOP can now - transfer arbitrary point attribute values from the input particles - to output voxels. - - Fixed a bug in the Convert SOP whereby the names of primitives - were lost during conversion, and another bug that resulted in - an arithmetic error when converting an empty grid. - - Fixed a bug in the Combine SOP that caused the Operation selection - to be lost. - -Version 0.98.0 - November 16 2012 - - Tree and Transform objects (and Grid objects in the context of - Houdini SOPs) are now passed and accessed primarily by reference - rather than by shared pointer. See the online documentation for - details about this important API change. - [Contributed by SESI] - - Reimplemented CoordBBox to address several off-by-one bugs - related to bounding box dimensions. - - Fixed an off-by-one bug in Grid::evalActiveVoxelBoundingBox(). - - Introduced the LeafManager class, which will eventually replace the - LeafArray class. LeafManager supports dynamic buffers stored as - a structure of arrays (SOA), unlike LeafArray, which supports only - static buffers stored as an array of structures (AOS). - - Improved the performance of the LevelSetFilter and LevelSetTracker - tools by rewriting them to use the new LeafManager class. - - Added Tree and ValueAccessor setValueOnly() methods, which change - the value of a voxel without changing its active state, and - Tree and ValueAccessor probeLeaf() methods that return the leaf node - that contains a given voxel (unless the voxel is represented by a tile). - - Added a LevelSetAdvection tool that propagates and tracks - narrow-band level sets. - - Introduced a new GridSampler class that supports world-space - (or index-space) sampling of grid values. - - Changed the interpretation of the NonlinearFrustumMap's taper - parameter to be the ratio of the near and far plane depths. - - Added a ParmFactory::setChoiceList() overload that accepts - (token, label) string pairs, and a setDefault() overload that - accepts an STL string. - - Fixed a crash in the Combine SOP in Copy B mode. - - Split the Level Set Filter SOP into three separate SOPs, - Level Set Smooth, Level Set Reshape and Level Set Renormalize. - When two or more of these nodes are connected in sequence, they interact - to reduce memory usage: the last node in the sequence performs - all of the operations in one step. - - The Advect Points SOP can now output polyline streamlines - that trace the paths of the points. - - Added an option to the Analysis SOP to specify names for output grids. - - Added camera-derived frustum transform support to the Create SOP. - -Version 0.97.0 - October 18 2012 - - Added a narrow-band level set interface tracking tool (up to - fifth-order in space but currently only first-order in time, - with higher temporal orders to be added soon). - - Added a level set filter tool to perform unrestricted surface - smoothing (e.g., Laplacian flow), filtering (e.g., mean value) - and morphological operations (e.g., morphological opening). - - Added adaptivity to the level set meshing tool for faster mesh - extraction with fewer polygons, without postprocessing. - - Added a ValueAccessor::touchLeaf() method that creates (if necessary) - and returns the leaf node containing a given voxel. It can be used - to preallocate leaf nodes over which to run parallel algorithms. - - Fixed a bug in Grid::merge() whereby active tiles were sometimes lost. - - Added LeafManager, which is similar to LeafArray but supports a - dynamic buffer count and allocates buffers more efficiently. - Useful for temporal integration (e.g., for level set propagation - and interface tracking), LeafManager is meant to replace LeafArray, - which will be deprecated in the next release. - - Added a LeafNode::fill() method to efficiently populate leaf nodes - with constant values. - - Added a Tree::visitActiveBBox() method that applies a functor to the - bounding boxes of all active tiles and leaf nodes and that can be used - to improve the performance of ray intersection tests, rendering of - bounding boxes, etc. - - Added a Tree::voxelizeActiveTiles() method to densify active tiles. - While convenient and fast, this can produce large dense grids, - so use it with caution. - - Repackaged Tree::pruneLevelSet() as a Tree::pruneOp()-compatible - functor. LevelSetPrune is a specialized pruneInactive() for - level-set grids and is used in interface tracking. - - Added a GridBase::pruneGrid() method. - - Added a Grid:hasUniformVoxels() method. - - Renamed tools::dilate() to tools::dilateVoxels() and improved its - performance. The new name reflects the fact that the current - implementation ignores active tiles. - - Added a tools::resampleToMatch() function that resamples an input - grid into an output grid with a different transform such that, after - resampling, the input and output grids coincide, but the output - grid's transform is preserved. - - Significantly improved the performance of depth-bounded value - iterators (ValueOnIter, ValueAllIter, etc.) when the depth bound - excludes leaf nodes. - - Exposed the value buffers inside leaf nodes with LeafNode::buffer(). - This allows for very fast access (const and non-const) to voxel - values using linear array offsets instead of (i,j,k) coordinates. - - In openvdb_houdini/UT_VDBTools.h, added operators for use with - processTypedGrid() that resample grids in several different ways. - - Added a policy mechanism to houdini_utils::OpFactory that allows for - customization of operator names, icons, and Help URLs. - - Renamed many of the Houdini SOPs to make the names more consistent. - - Added an Advect Points SOP. - - Added a Level Set Filter SOP that allows for unrestricted surface - deformations, unlike the older Filter SOP, which restricts surface - motion to the initial narrow band. - - Added staggered vector sampling to the Sample Points SOP. - - Added a minimum radius threshold to the particle voxelization tool - and SOP. - - Merged the Composite and CSG SOPs into a single Combine SOP. - - Added a tool and a SOP to efficiently generate narrow-band level set - representations of spheres. - - In the Visualize SOP, improved the performance of tree topology - generation, which is now enabled by default. - -Version 0.96.0 - September 24 2012 - - Fixed a memory corruption bug in the mesh voxelizer tool. - - Temporarily removed the optional clipping feature from - the level set mesher. - - Added "Staggered Vector Field" to the list of grid classes - in the Create SOP. - -Version 0.95.0 - September 20 2012 - - Added a quad meshing tool for higher-quality level set meshing - and updated the Visualizer SOP to use it. - - Fixed a precision error in the mesh voxelizer and improved - the quality of inside/outside voxel classification. - Output grids are now also tagged as either level sets or fog volumes. - - Modified the GridResampler to use the signed flood fill optimization - only on grids that are tagged as level sets. - - Added a quaternion class to the math library and a method to - return the trace of a Mat3. - - Fixed a bug in the ValueAccessor copy constructor that caused - the copy to reference the original. - - Fixed a bug in RootNode::setActiveState() that caused a crash - when marking a (virtual) background voxel as inactive. - - Added a Tree::pruneLevelSet() method that is similar to but faster than - pruneInactive() for level set grids. - - Added fast leaf node voxel access methods that index by linear offset - (as returned by ValueIter::pos()) instead of by (i, j, k) coordinates. - - Added a Tree::touchLeaf() method that can be used to preallocate a static - tree topology over which to safely perform multithreaded processing. - - Added a grain size argument to the LeafArray class for finer control - of parallelism. - - Modified the Makefile to make it easier to omit the doc, vdb_test - and vdb_view targets. - - Added utility functions (in houdini/UT_VDBUtils.h) to convert - between Houdini and OpenVDB matrix and vector types. - [Contributed by SESI] - - Added accessors to GEO_PrimVDB that make it easier to directly access - voxel data and that are used by the HScript volume expression functions - in Houdini 12.5. - [Contributed by SESI] - - As of Houdini 12.1.77, the native transform SOP operates on OpenVDB - primitives. - [Contributed by SESI] - - Added a Convert SOP that converts OpenVDB grids to Houdini volumes - and vice-versa. - -Version 0.94.1 - September 7 2012 - - Fixed bugs in RootNode and InternalNode setValue*() and fill() methods - that could cause neighboring voxels to become inactive. - - Fixed a bug in Tree::hasSameTopology() that caused false positives - when only active states and not values differed. - - Added a Tree::hasActiveTiles() method. - - For better cross-platform consistency, substituted bitwise AND - operations for right shifts in the ValueAccessor hash key computation. - - vdb_view no longer aborts when asked to surface a vector-valued - grid--but it still doesn't render the surface. - - Made various changes for Visual C++ compatibility. - [Contributed by SESI] - - Added an option to the MeshVoxelizer SOP to convert both open and - closed surfaces to unsigned distance fields. - - The Filter SOP now allows multiple filters to be applied in - user-specified order. - -Version 0.94.0 - August 30 2012 - - Added a method to union just the active states of voxels from - one grid with those of another grid of a possibly different type. - - Fixed an incorrect scale factor in the Laplacian diffusion filter. - - Fixed a bug in Tree::merge that could leave a tree with invalid - value accessors. - - Added TreeValueIteratorBase::setActiveState() and deprecated setValueOn(). - - Removed tools/FastSweeping.h. It will be replaced with a much more - efficient implementation in the near future. - - ZLIB compression of .vdb files is now optional, but enabled by default. - [Contributed by SESI] - - Made various changes for Clang and Visual C++ compatibility. - [Contributed by SESI] - - The MeshVoxelizer SOP can now transfer arbitrary point and - primitive attribute values from the input mesh to output voxels. - -Version 0.93.0 - August 24 2012 - - Renamed symbols in math/Operators.h to avoid ambiguities that - GCC 4.4 reports as errors. - - Simplified the API for the stencil version of the - closest-point transform operator. - - Added logic to io::Archive::readGrid() to set the grid name metadata - from the descriptor if the metadata doesn't already exist. - - Added guards to prevent nesting of openvdb_houdini::Interrupter::start() - and end() calls. - - -Version 0.92.0 - August 23 2012 - - Added a Laplacian diffusion filter. - - Fixed a bug in the initialization of the sparse contour tracer - that caused mesh-to-volume conversion to fail in certain cases. - - Fixed a bug in the curvature stencil that caused mean curvature - filtering to produce wrong results. - - Increased the speed of the GridTransformer by as much as 20% - for fog volumes. - - Added optional pruning to the Resample SOP. - - Modified the PointSample SOP to allow it to work with ungrouped, - anonymous grids. - - Fixed a crash in the LevelSetNoise SOP. - -Version 0.91.0 - August 16 2012 - - tools::GridTransformer and tools::GridResampler now correctly - (but not yet efficiently) process tiles in sparse grids. - - Added an optional CopyPolicy argument to GridBase::copyGrid() - and to Grid::copy() that specifies whether and how the grid's tree - should be copied. - - Added a GridBase::newTree() method that replaces a grid's tree with - a new, empty tree of the correct type. - - Fixed a crash in Tree::setValueOff() when the new value was equal to - the background value. - - Fixed bugs in Tree::prune() that could result in output tiles with - incorrect active states. - - Added librt to the link dependencies to address build failures on - Ubuntu systems. - - Made various small changes to the Makefile and the source code - that should help with Mac OS X compatibility. - - The Composite and Resample SOPs now correctly copy the input grid's - metadata to the output grid. - -Version 0.90.1 - August 7 2012 - - Fixed a bug in the BBox::getCenter() method. - - Added missing header files to various files. - - io::File::NameIterator::gridName() now returns a unique name of the - form "name[1]", "name[2]", etc. if a file contains multiple grids with - the same name. - - Fixed a bug in the Writer SOP that caused grid names to be discarded. - - The Resample SOP now correctly sets the background value of the - output grid. - -Version 0.90.0 - August 3 2012 (initial public release) - - Added a basic GL viewer for OpenVDB files. - - Greatly improved the performance of two commonly-used Tree methods, - evalActiveVoxelBoundingBox() and memUsage(). - - Eliminated the GridMap class. File I/O now uses STL containers - of grid pointers instead. - - Refactored stencil-based tools (Gradient, Laplacian, etc.) and rewrote - some of them for generality and better performance. Most now behave - correctly for grids with nonlinear index-to-world transforms. - - Added a library of index-space finite difference operators. - - Added a "Hermite" grid type that compactly stores each voxel's upwind - normals and can be used to convert volumes to and from polygonal meshes. - - Added a tool (and a Houdini SOP) to scatter points randomly throughout - a volume. - diff --git a/openvdb_3_0_0_library/COPYRIGHT b/openvdb_3_0_0_library/COPYRIGHT deleted file mode 100755 index 4bd6195..0000000 --- a/openvdb_3_0_0_library/COPYRIGHT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2012-2013 DreamWorks Animation LLC - -All rights reserved. This software is distributed under the -Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) - -Redistributions of source code must retain the above copyright -and license notice and the following restrictions and disclaimer. - -* Neither the name of DreamWorks Animation nor the names of -its contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. diff --git a/openvdb_3_0_0_library/Exceptions.h b/openvdb_3_0_0_library/Exceptions.h deleted file mode 100755 index 4d21fc0..0000000 --- a/openvdb_3_0_0_library/Exceptions.h +++ /dev/null @@ -1,112 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_EXCEPTIONS_HAS_BEEN_INCLUDED -#define OPENVDB_EXCEPTIONS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -class OPENVDB_API Exception: public std::exception -{ -public: - virtual const char* what() const throw() - { - try { return mMessage.c_str(); } catch (...) {}; - return NULL; - } - - virtual ~Exception() throw() {} - -protected: - Exception() throw() {} - explicit Exception(const char* eType, const std::string* const msg = NULL) throw() - { - try { - if (eType) mMessage = eType; - if (msg) mMessage += ": " + (*msg); - } catch (...) {} - } - -private: - std::string mMessage; -}; - - -#define OPENVDB_EXCEPTION(_classname) \ -class OPENVDB_API _classname: public Exception \ -{ \ -public: \ - _classname() throw() : Exception( #_classname ) {} \ - explicit _classname(const std::string &msg) throw() : Exception( #_classname , &msg) {} \ -} - - -OPENVDB_EXCEPTION(ArithmeticError); -OPENVDB_EXCEPTION(IllegalValueException); -OPENVDB_EXCEPTION(IndexError); -OPENVDB_EXCEPTION(IoError); -OPENVDB_EXCEPTION(KeyError); -OPENVDB_EXCEPTION(LookupError); -OPENVDB_EXCEPTION(NotImplementedError); -OPENVDB_EXCEPTION(ReferenceError); -OPENVDB_EXCEPTION(RuntimeError); -OPENVDB_EXCEPTION(TypeError); -OPENVDB_EXCEPTION(ValueError); - - -#undef OPENVDB_EXCEPTION - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -#define OPENVDB_THROW(exception, message) \ -{ \ - std::string _openvdb_throw_msg; \ - try { \ - std::ostringstream _openvdb_throw_os; \ - _openvdb_throw_os << message; \ - _openvdb_throw_msg = _openvdb_throw_os.str(); \ - } catch (...) {} \ - throw exception(_openvdb_throw_msg); \ -} // OPENVDB_THROW - -#endif // OPENVDB_EXCEPTIONS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/Grid.cc b/openvdb_3_0_0_library/Grid.cc deleted file mode 100755 index b260671..0000000 --- a/openvdb_3_0_0_library/Grid.cc +++ /dev/null @@ -1,501 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Grid.h" - -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// @note For Houdini compatibility, boolean-valued metadata names -/// should begin with "is_". -const char - * const GridBase::META_GRID_CLASS = "class", - * const GridBase::META_GRID_CREATOR = "creator", - * const GridBase::META_GRID_NAME = "name", - * const GridBase::META_SAVE_HALF_FLOAT = "is_saved_as_half_float", - * const GridBase::META_IS_LOCAL_SPACE = "is_local_space", - * const GridBase::META_VECTOR_TYPE = "vector_type", - * const GridBase::META_FILE_BBOX_MIN = "file_bbox_min", - * const GridBase::META_FILE_BBOX_MAX = "file_bbox_max", - * const GridBase::META_FILE_COMPRESSION = "file_compression", - * const GridBase::META_FILE_MEM_BYTES = "file_mem_bytes", - * const GridBase::META_FILE_VOXEL_COUNT = "file_voxel_count"; - -namespace { -/// @todo Remove (deprecated in favor of META_SAVE_HALF_FLOAT) -const char *SAVE_FLOAT_AS_HALF = "write as 16-bit float"; -} - - -//////////////////////////////////////// - - -namespace { - -typedef std::map GridFactoryMap; -typedef GridFactoryMap::const_iterator GridFactoryMapCIter; - -typedef tbb::mutex Mutex; -typedef Mutex::scoped_lock Lock; - -struct LockedGridRegistry { - LockedGridRegistry() {} - ~LockedGridRegistry() {} - Mutex mMutex; - GridFactoryMap mMap; -}; - -// Declare this at file scope to ensure thread-safe initialization. -Mutex sInitGridRegistryMutex; - - -// Global function for accessing the registry -LockedGridRegistry* -getGridRegistry() -{ - Lock lock(sInitGridRegistryMutex); - - static LockedGridRegistry* registry = NULL; - - if (registry == NULL) { - -#ifdef __ICC -// Disable ICC "assignment to statically allocated variable" warning. -// This assignment is mutex-protected and therefore thread-safe. -__pragma(warning(disable:1711)) -#endif - - registry = new LockedGridRegistry(); - -#ifdef __ICC -__pragma(warning(default:1711)) -#endif - - } - - return registry; -} - -} // unnamed namespace - - -bool -GridBase::isRegistered(const Name& name) -{ - LockedGridRegistry* registry = getGridRegistry(); - Lock lock(registry->mMutex); - - return (registry->mMap.find(name) != registry->mMap.end()); -} - - -void -GridBase::registerGrid(const Name& name, GridFactory factory) -{ - LockedGridRegistry* registry = getGridRegistry(); - Lock lock(registry->mMutex); - - if (registry->mMap.find(name) != registry->mMap.end()) { - OPENVDB_THROW(KeyError, "Grid type " << name << " is already registered"); - } - - registry->mMap[name] = factory; -} - - -void -GridBase::unregisterGrid(const Name& name) -{ - LockedGridRegistry* registry = getGridRegistry(); - Lock lock(registry->mMutex); - - registry->mMap.erase(name); -} - - -GridBase::Ptr -GridBase::createGrid(const Name& name) -{ - LockedGridRegistry* registry = getGridRegistry(); - Lock lock(registry->mMutex); - - GridFactoryMapCIter iter = registry->mMap.find(name); - - if (iter == registry->mMap.end()) { - OPENVDB_THROW(LookupError, "Cannot create grid of unregistered type " << name); - } - - return (iter->second)(); -} - - -void -GridBase::clearRegistry() -{ - LockedGridRegistry* registry = getGridRegistry(); - Lock lock(registry->mMutex); - - registry->mMap.clear(); -} - - -//////////////////////////////////////// - - -GridClass -GridBase::stringToGridClass(const std::string& s) -{ - GridClass ret = GRID_UNKNOWN; - std::string str = s; - boost::trim(str); - boost::to_lower(str); - if (str == gridClassToString(GRID_LEVEL_SET)) { - ret = GRID_LEVEL_SET; - } else if (str == gridClassToString(GRID_FOG_VOLUME)) { - ret = GRID_FOG_VOLUME; - } else if (str == gridClassToString(GRID_STAGGERED)) { - ret = GRID_STAGGERED; - } - return ret; -} - - -std::string -GridBase::gridClassToString(GridClass cls) -{ - std::string ret; - switch (cls) { - case GRID_UNKNOWN: ret = "unknown"; break; - case GRID_LEVEL_SET: ret = "level set"; break; - case GRID_FOG_VOLUME: ret = "fog volume"; break; - case GRID_STAGGERED: ret = "staggered"; break; - } - return ret; -} - -std::string -GridBase::gridClassToMenuName(GridClass cls) -{ - std::string ret; - switch (cls) { - case GRID_UNKNOWN: ret = "Other"; break; - case GRID_LEVEL_SET: ret = "Level Set"; break; - case GRID_FOG_VOLUME: ret = "Fog Volume"; break; - case GRID_STAGGERED: ret = "Staggered Vector Field"; break; - } - return ret; -} - - - -GridClass -GridBase::getGridClass() const -{ - GridClass cls = GRID_UNKNOWN; - if (StringMetadata::ConstPtr s = this->getMetadata(META_GRID_CLASS)) { - cls = stringToGridClass(s->value()); - } - return cls; -} - - -void -GridBase::setGridClass(GridClass cls) -{ - this->insertMeta(META_GRID_CLASS, StringMetadata(gridClassToString(cls))); -} - - -void -GridBase::clearGridClass() -{ - this->removeMeta(META_GRID_CLASS); -} - - -//////////////////////////////////////// - - -VecType -GridBase::stringToVecType(const std::string& s) -{ - VecType ret = VEC_INVARIANT; - std::string str = s; - boost::trim(str); - boost::to_lower(str); - if (str == vecTypeToString(VEC_COVARIANT)) { - ret = VEC_COVARIANT; - } else if (str == vecTypeToString(VEC_COVARIANT_NORMALIZE)) { - ret = VEC_COVARIANT_NORMALIZE; - } else if (str == vecTypeToString(VEC_CONTRAVARIANT_RELATIVE)) { - ret = VEC_CONTRAVARIANT_RELATIVE; - } else if (str == vecTypeToString(VEC_CONTRAVARIANT_ABSOLUTE)) { - ret = VEC_CONTRAVARIANT_ABSOLUTE; - } - return ret; -} - - -std::string -GridBase::vecTypeToString(VecType typ) -{ - std::string ret; - switch (typ) { - case VEC_INVARIANT: ret = "invariant"; break; - case VEC_COVARIANT: ret = "covariant"; break; - case VEC_COVARIANT_NORMALIZE: ret = "covariant normalize"; break; - case VEC_CONTRAVARIANT_RELATIVE: ret = "contravariant relative"; break; - case VEC_CONTRAVARIANT_ABSOLUTE: ret = "contravariant absolute"; break; - } - return ret; -} - - -std::string -GridBase::vecTypeExamples(VecType typ) -{ - std::string ret; - switch (typ) { - case VEC_INVARIANT: ret = "Tuple/Color/UVW"; break; - case VEC_COVARIANT: ret = "Gradient/Normal"; break; - case VEC_COVARIANT_NORMALIZE: ret = "Unit Normal"; break; - case VEC_CONTRAVARIANT_RELATIVE: ret = "Displacement/Velocity/Acceleration"; break; - case VEC_CONTRAVARIANT_ABSOLUTE: ret = "Position"; break; - } - return ret; -} - - -std::string -GridBase::vecTypeDescription(VecType typ) -{ - std::string ret; - switch (typ) { - case VEC_INVARIANT: - ret = "Does not transform"; - break; - case VEC_COVARIANT: - ret = "Apply the inverse-transpose transform matrix but ignore translation"; - break; - case VEC_COVARIANT_NORMALIZE: - ret = "Apply the inverse-transpose transform matrix but ignore translation" - " and renormalize vectors"; - break; - case VEC_CONTRAVARIANT_RELATIVE: - ret = "Apply the forward transform matrix but ignore translation"; - break; - case VEC_CONTRAVARIANT_ABSOLUTE: - ret = "Apply the forward transform matrix, including translation"; - break; - } - return ret; -} - - -VecType -GridBase::getVectorType() const -{ - VecType typ = VEC_INVARIANT; - if (StringMetadata::ConstPtr s = this->getMetadata(META_VECTOR_TYPE)) { - typ = stringToVecType(s->value()); - } - return typ; -} - - -void -GridBase::setVectorType(VecType typ) -{ - this->insertMeta(META_VECTOR_TYPE, StringMetadata(vecTypeToString(typ))); -} - - -void -GridBase::clearVectorType() -{ - this->removeMeta(META_VECTOR_TYPE); -} - - -//////////////////////////////////////// - - -std::string -GridBase::getName() const -{ - if (Metadata::ConstPtr meta = (*this)[META_GRID_NAME]) return meta->str(); - return ""; -} - - -void -GridBase::setName(const std::string& name) -{ - this->removeMeta(META_GRID_NAME); - this->insertMeta(META_GRID_NAME, StringMetadata(name)); -} - - -//////////////////////////////////////// - - -std::string -GridBase::getCreator() const -{ - if (Metadata::ConstPtr meta = (*this)[META_GRID_CREATOR]) return meta->str(); - return ""; -} - - -void -GridBase::setCreator(const std::string& creator) -{ - this->removeMeta(META_GRID_CREATOR); - this->insertMeta(META_GRID_CREATOR, StringMetadata(creator)); -} - - -//////////////////////////////////////// - - -bool -GridBase::saveFloatAsHalf() const -{ - bool saveAsHalf = false; - if (Metadata::ConstPtr meta = (*this)[META_SAVE_HALF_FLOAT]) { - saveAsHalf = meta->asBool(); - } else if ((*this)[SAVE_FLOAT_AS_HALF]) { - // Old behavior: saveAsHalf is true if metadata named - // SAVE_FLOAT_AS_HALF exists, regardless of its value. - saveAsHalf = true; - } - return saveAsHalf; -} - - -void -GridBase::setSaveFloatAsHalf(bool saveAsHalf) -{ - this->removeMeta(META_SAVE_HALF_FLOAT); - this->insertMeta(META_SAVE_HALF_FLOAT, BoolMetadata(saveAsHalf)); - - // Remove the old, deprecated metadata. - this->removeMeta(SAVE_FLOAT_AS_HALF); -} - - -//////////////////////////////////////// - - -bool -GridBase::isInWorldSpace() const -{ - bool local = false; - if (Metadata::ConstPtr meta = (*this)[META_IS_LOCAL_SPACE]) { - local = meta->asBool(); - } - return !local; -} - - -void -GridBase::setIsInWorldSpace(bool world) -{ - this->removeMeta(META_IS_LOCAL_SPACE); - this->insertMeta(META_IS_LOCAL_SPACE, BoolMetadata(!world)); -} - - -//////////////////////////////////////// - - -void -GridBase::addStatsMetadata() -{ - const CoordBBox bbox = this->evalActiveVoxelBoundingBox(); - this->removeMeta(META_FILE_BBOX_MIN); - this->removeMeta(META_FILE_BBOX_MAX); - this->removeMeta(META_FILE_MEM_BYTES); - this->removeMeta(META_FILE_VOXEL_COUNT); - this->insertMeta(META_FILE_BBOX_MIN, Vec3IMetadata(bbox.min().asVec3i())); - this->insertMeta(META_FILE_BBOX_MAX, Vec3IMetadata(bbox.max().asVec3i())); - this->insertMeta(META_FILE_MEM_BYTES, Int64Metadata(this->memUsage())); - this->insertMeta(META_FILE_VOXEL_COUNT, Int64Metadata(this->activeVoxelCount())); -} - - -MetaMap::Ptr -GridBase::getStatsMetadata() const -{ - const char* const fields[] = { - META_FILE_BBOX_MIN, - META_FILE_BBOX_MAX, - META_FILE_MEM_BYTES, - META_FILE_VOXEL_COUNT, - NULL - }; - - /// @todo Check that the fields are of the correct type? - MetaMap::Ptr ret(new MetaMap); - for (int i = 0; fields[i] != NULL; ++i) { - if (Metadata::ConstPtr m = (*this)[fields[i]]) { - ret->insertMeta(fields[i], *m); - } - } - return ret; -} - - -//////////////////////////////////////// - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -void -GridBase::clipGrid(const BBoxd& worldBBox) -{ - const CoordBBox indexBBox = - this->constTransform().worldToIndexNodeCentered(worldBBox); - this->clip(indexBBox); -} -#endif - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/Grid.h b/openvdb_3_0_0_library/Grid.h deleted file mode 100755 index c566448..0000000 --- a/openvdb_3_0_0_library/Grid.h +++ /dev/null @@ -1,1379 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_GRID_HAS_BEEN_INCLUDED -#define OPENVDB_GRID_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -typedef tree::TreeBase TreeBase; - -template class Grid; // forward declaration - - -/// @brief Create a new grid of type @c GridType with a given background value. -/// -/// @note Calling createGrid(background) is equivalent to calling -/// GridType::create(background). -template -inline typename GridType::Ptr createGrid(const typename GridType::ValueType& background); - - -/// @brief Create a new grid of type @c GridType with background value zero. -/// -/// @note Calling createGrid() is equivalent to calling GridType::create(). -template -inline typename GridType::Ptr createGrid(); - - -/// @brief Create a new grid of the appropriate type that wraps the given tree. -/// -/// @note This function can be called without specifying the template argument, -/// i.e., as createGrid(tree). -template -inline typename Grid::Ptr createGrid(TreePtrType); - - -/// @brief Create a new grid of type @c GridType classified as a "Level Set", -/// i.e., a narrow-band level set. -/// -/// @note @c GridType::ValueType must be a floating-point scalar. -/// -/// @param voxelSize the size of a voxel in world units -/// @param halfWidth the half width of the narrow band in voxel units -/// -/// @details The voxel size and the narrow band half width define the grid's -/// background value as halfWidth*voxelWidth. The transform is linear -/// with a uniform scaling only corresponding to the specified voxel size. -/// -/// @note It is generally advisable to specify a half-width of the narrow band -/// that is larger than one voxel unit, otherwise zero crossings are not guaranteed. -template -typename GridType::Ptr createLevelSet( - Real voxelSize = 1.0, Real halfWidth = LEVEL_SET_HALF_WIDTH); - - -//////////////////////////////////////// - - -/// @brief Abstract base class for typed grids -class OPENVDB_API GridBase: public MetaMap -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - typedef Ptr (*GridFactory)(); - - - virtual ~GridBase() {} - - /// @brief Return a new grid of the same type as this grid and whose - /// metadata and transform are deep copies of this grid's. - virtual GridBase::Ptr copyGrid(CopyPolicy treePolicy = CP_SHARE) const = 0; - - /// Return a new grid whose metadata, transform and tree are deep copies of this grid's. - virtual GridBase::Ptr deepCopyGrid() const = 0; - - - // - // Registry methods - // - /// Create a new grid of the given (registered) type. - static Ptr createGrid(const Name& type); - - /// Return @c true if the given grid type name is registered. - static bool isRegistered(const Name &type); - - /// Clear the grid type registry. - static void clearRegistry(); - - - // - // Grid type methods - // - /// Return the name of this grid's type. - virtual Name type() const = 0; - /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d"). - virtual Name valueType() const = 0; - - /// Return @c true if this grid is of the same type as the template parameter. - template - bool isType() const { return (this->type() == GridType::gridType()); } - - //@{ - /// @brief Return the result of downcasting a GridBase pointer to a Grid pointer - /// of the specified type, or return a null pointer if the types are incompatible. - template - static typename GridType::Ptr grid(const GridBase::Ptr&); - template - static typename GridType::ConstPtr grid(const GridBase::ConstPtr&); - template - static typename GridType::ConstPtr constGrid(const GridBase::Ptr&); - template - static typename GridType::ConstPtr constGrid(const GridBase::ConstPtr&); - //@} - - //@{ - /// @brief Return a pointer to this grid's tree, which might be - /// shared with other grids. The pointer is guaranteed to be non-null. - TreeBase::Ptr baseTreePtr(); - TreeBase::ConstPtr baseTreePtr() const { return this->constBaseTreePtr(); } - virtual TreeBase::ConstPtr constBaseTreePtr() const = 0; - //@} - - //@{ - /// @brief Return a reference to this grid's tree, which might be - /// shared with other grids. - /// @note Calling setTree() on this grid invalidates all references - /// previously returned by this method. - TreeBase& baseTree() { return const_cast(this->constBaseTree()); } - const TreeBase& baseTree() const { return this->constBaseTree(); } - const TreeBase& constBaseTree() const { return *(this->constBaseTreePtr()); } - //@} - - /// @brief Associate the given tree with this grid, in place of its existing tree. - /// @throw ValueError if the tree pointer is null - /// @throw TypeError if the tree is not of the appropriate type - /// @note Invalidates all references previously returned by baseTree() - /// or constBaseTree(). - virtual void setTree(TreeBase::Ptr) = 0; - - /// Set a new tree with the same background value as the previous tree. - virtual void newTree() = 0; - - /// Return @c true if this grid contains only background voxels. - virtual bool empty() const = 0; - /// Empty this grid, setting all voxels to the background. - virtual void clear() = 0; - - /// @brief Reduce the memory footprint of this grid by increasing its sparseness - /// either losslessly (@a tolerance = 0) or lossily (@a tolerance > 0). - /// @details With @a tolerance > 0, sparsify regions where voxels have the same - /// active state and have values that differ by no more than the tolerance - /// (converted to this grid's value type). - virtual void pruneGrid(float tolerance = 0.0) = 0; - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Clip this grid to the given world-space bounding box. - /// @details Voxels that lie outside the bounding box are set to the background. - /// @warning Clipping a level set will likely produce a grid that is - /// no longer a valid level set. - void clipGrid(const BBoxd&); - - /// @brief Clip this grid to the given index-space bounding box. - /// @details Voxels that lie outside the bounding box are set to the background. - /// @warning Clipping a level set will likely produce a grid that is - /// no longer a valid level set. - virtual void clip(const CoordBBox&) = 0; -#endif - - - // - // Metadata - // - /// Return this grid's user-specified name. - std::string getName() const; - /// Specify a name for this grid. - void setName(const std::string&); - - /// Return the user-specified description of this grid's creator. - std::string getCreator() const; - /// Provide a description of this grid's creator. - void setCreator(const std::string&); - - /// @brief Return @c true if this grid should be written out with floating-point - /// voxel values (including components of vectors) quantized to 16 bits. - bool saveFloatAsHalf() const; - void setSaveFloatAsHalf(bool); - - /// Return the class of volumetric data (level set, fog volume, etc.) stored in this grid. - GridClass getGridClass() const; - /// Specify the class of volumetric data (level set, fog volume, etc.) stored in this grid. - void setGridClass(GridClass); - /// Remove the setting specifying the class of this grid's volumetric data. - void clearGridClass(); - - /// Return the metadata string value for the given class of volumetric data. - static std::string gridClassToString(GridClass); - /// Return a formatted string version of the grid class. - static std::string gridClassToMenuName(GridClass); - /// @brief Return the class of volumetric data specified by the given string. - /// @details If the string is not one of the ones returned by gridClassToString(), - /// return @c GRID_UNKNOWN. - static GridClass stringToGridClass(const std::string&); - - /// @brief Return the type of vector data (invariant, covariant, etc.) stored - /// in this grid, assuming that this grid contains a vector-valued tree. - VecType getVectorType() const; - /// @brief Specify the type of vector data (invariant, covariant, etc.) stored - /// in this grid, assuming that this grid contains a vector-valued tree. - void setVectorType(VecType); - /// Remove the setting specifying the type of vector data stored in this grid. - void clearVectorType(); - - /// Return the metadata string value for the given type of vector data. - static std::string vecTypeToString(VecType); - /// Return a string listing examples of the given type of vector data - /// (e.g., "Gradient/Normal", given VEC_COVARIANT). - static std::string vecTypeExamples(VecType); - /// @brief Return a string describing how the given type of vector data is affected - /// by transformations (e.g., "Does not transform", given VEC_INVARIANT). - static std::string vecTypeDescription(VecType); - static VecType stringToVecType(const std::string&); - - /// Return @c true if this grid's voxel values are in world space and should be - /// affected by transformations, @c false if they are in local space and should - /// not be affected by transformations. - bool isInWorldSpace() const; - /// Specify whether this grid's voxel values are in world space or in local space. - void setIsInWorldSpace(bool); - - // Standard metadata field names - // (These fields should normally not be accessed directly, but rather - // via the accessor methods above, when available.) - // Note: Visual C++ requires these declarations to be separate statements. - static const char* const META_GRID_CLASS; - static const char* const META_GRID_CREATOR; - static const char* const META_GRID_NAME; - static const char* const META_SAVE_HALF_FLOAT; - static const char* const META_IS_LOCAL_SPACE; - static const char* const META_VECTOR_TYPE; - static const char* const META_FILE_BBOX_MIN; - static const char* const META_FILE_BBOX_MAX; - static const char* const META_FILE_COMPRESSION; - static const char* const META_FILE_MEM_BYTES; - static const char* const META_FILE_VOXEL_COUNT; - - - // - // Statistics - // - /// Return the number of active voxels. - virtual Index64 activeVoxelCount() const = 0; - - /// Return the axis-aligned bounding box of all active voxels. If - /// the grid is empty a default bbox is returned. - virtual CoordBBox evalActiveVoxelBoundingBox() const = 0; - - /// Return the dimensions of the axis-aligned bounding box of all active voxels. - virtual Coord evalActiveVoxelDim() const = 0; - - /// Return the number of bytes of memory used by this grid. - virtual Index64 memUsage() const = 0; - - /// @brief Add metadata to this grid comprising the current values - /// of statistics like the active voxel count and bounding box. - /// @note This metadata is not automatically kept up-to-date with - /// changes to this grid. - void addStatsMetadata(); - /// @brief Return a new MetaMap containing just the metadata that - /// was added to this grid with addStatsMetadata(). - /// @details If addStatsMetadata() was never called on this grid, - /// return an empty MetaMap. - MetaMap::Ptr getStatsMetadata() const; - - - // - // Transform methods - // - //@{ - /// @brief Return a pointer to this grid's transform, which might be - /// shared with other grids. - math::Transform::Ptr transformPtr() { return mTransform; } - math::Transform::ConstPtr transformPtr() const { return mTransform; } - math::Transform::ConstPtr constTransformPtr() const { return mTransform; } - //@} - //@{ - /// @brief Return a reference to this grid's transform, which might be - /// shared with other grids. - /// @note Calling setTransform() on this grid invalidates all references - /// previously returned by this method. - math::Transform& transform() { return *mTransform; } - const math::Transform& transform() const { return *mTransform; } - const math::Transform& constTransform() const { return *mTransform; } - //@} - /// @brief Associate the given transform with this grid, in place of - /// its existing transform. - /// @throw ValueError if the transform pointer is null - /// @note Invalidates all references previously returned by transform() - /// or constTransform(). - void setTransform(math::Transform::Ptr); - - /// Return the size of this grid's voxels. - Vec3d voxelSize() const { return transform().voxelSize(); } - /// @brief Return the size of this grid's voxel at position (x, y, z). - /// @note Frustum and perspective transforms have position-dependent voxel size. - Vec3d voxelSize(const Vec3d& xyz) const { return transform().voxelSize(xyz); } - /// Return true if the voxels in world space are uniformly sized cubes - bool hasUniformVoxels() const { return mTransform->hasUniformScale(); } - //@{ - /// Apply this grid's transform to the given coordinates. - Vec3d indexToWorld(const Vec3d& xyz) const { return transform().indexToWorld(xyz); } - Vec3d indexToWorld(const Coord& ijk) const { return transform().indexToWorld(ijk); } - //@} - /// Apply the inverse of this grid's transform to the given coordinates. - Vec3d worldToIndex(const Vec3d& xyz) const { return transform().worldToIndex(xyz); } - - - // - // I/O methods - // - /// @brief Read the grid topology from a stream. - /// This will read only the grid structure, not the actual data buffers. - virtual void readTopology(std::istream&) = 0; - /// @brief Write the grid topology to a stream. - /// This will write only the grid structure, not the actual data buffers. - virtual void writeTopology(std::ostream&) const = 0; - - /// Read all data buffers for this grid. - virtual void readBuffers(std::istream&) = 0; -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Read all of this grid's data buffers that intersect the given index-space bounding box. - virtual void readBuffers(std::istream&, const CoordBBox&) = 0; - /// @brief Read all of this grid's data buffers that are not yet resident in memory - /// (because delayed loading is in effect). - /// @details If this grid was read from a memory-mapped file, this operation - /// disconnects the grid from the file. - /// @sa io::File::open, io::MappedFile - virtual void readNonresidentBuffers() const = 0; -#endif - /// Write out all data buffers for this grid. - virtual void writeBuffers(std::ostream&) const = 0; - - /// Read in the transform for this grid. - void readTransform(std::istream& is) { transform().read(is); } - /// Write out the transform for this grid. - void writeTransform(std::ostream& os) const { transform().write(os); } - - /// Output a human-readable description of this grid. - virtual void print(std::ostream& = std::cout, int verboseLevel = 1) const = 0; - - -protected: - /// @brief Initialize with an identity linear transform. - GridBase(): mTransform(math::Transform::createLinearTransform()) {} - - /// @brief Deep copy another grid's metadata and transform. - GridBase(const GridBase& other): MetaMap(other), mTransform(other.mTransform->copy()) {} - - /// @brief Copy another grid's metadata but share its transform. - GridBase(const GridBase& other, ShallowCopy): MetaMap(other), mTransform(other.mTransform) {} - - /// Register a grid type along with a factory function. - static void registerGrid(const Name& type, GridFactory); - /// Remove a grid type from the registry. - static void unregisterGrid(const Name& type); - - -private: - math::Transform::Ptr mTransform; -}; // class GridBase - - -//////////////////////////////////////// - - -typedef std::vector GridPtrVec; -typedef GridPtrVec::iterator GridPtrVecIter; -typedef GridPtrVec::const_iterator GridPtrVecCIter; -typedef boost::shared_ptr GridPtrVecPtr; - -typedef std::vector GridCPtrVec; -typedef GridCPtrVec::iterator GridCPtrVecIter; -typedef GridCPtrVec::const_iterator GridCPtrVecCIter; -typedef boost::shared_ptr GridCPtrVecPtr; - -typedef std::set GridPtrSet; -typedef GridPtrSet::iterator GridPtrSetIter; -typedef GridPtrSet::const_iterator GridPtrSetCIter; -typedef boost::shared_ptr GridPtrSetPtr; - -typedef std::set GridCPtrSet; -typedef GridCPtrSet::iterator GridCPtrSetIter; -typedef GridCPtrSet::const_iterator GridCPtrSetCIter; -typedef boost::shared_ptr GridCPtrSetPtr; - - -/// @brief Predicate functor that returns @c true for grids that have a specified name -struct OPENVDB_API GridNamePred -{ - GridNamePred(const Name& _name): name(_name) {} - bool operator()(const GridBase::ConstPtr& g) const { return g && g->getName() == name; } - Name name; -}; - -/// Return the first grid in the given container whose name is @a name. -template -inline typename GridPtrContainerT::value_type -findGridByName(const GridPtrContainerT& container, const Name& name) -{ - typedef typename GridPtrContainerT::value_type GridPtrT; - typename GridPtrContainerT::const_iterator it = - std::find_if(container.begin(), container.end(), GridNamePred(name)); - return (it == container.end() ? GridPtrT() : *it); -} - -/// Return the first grid in the given map whose name is @a name. -template -inline GridPtrT -findGridByName(const std::map& container, const Name& name) -{ - typedef std::map GridPtrMapT; - for (typename GridPtrMapT::const_iterator it = container.begin(), end = container.end(); - it != end; ++it) - { - const GridPtrT& grid = it->second; - if (grid && grid->getName() == name) return grid; - } - return GridPtrT(); -} -//@} - - -//////////////////////////////////////// - - -/// @brief Container class that associates a tree with a transform and metadata -template -class Grid: public GridBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - typedef _TreeType TreeType; - typedef typename _TreeType::Ptr TreePtrType; - typedef typename _TreeType::ConstPtr ConstTreePtrType; - typedef typename _TreeType::ValueType ValueType; - - typedef typename tree::ValueAccessor<_TreeType> Accessor; - typedef typename tree::ValueAccessor ConstAccessor; - - typedef typename _TreeType::ValueOnIter ValueOnIter; - typedef typename _TreeType::ValueOnCIter ValueOnCIter; - typedef typename _TreeType::ValueOffIter ValueOffIter; - typedef typename _TreeType::ValueOffCIter ValueOffCIter; - typedef typename _TreeType::ValueAllIter ValueAllIter; - typedef typename _TreeType::ValueAllCIter ValueAllCIter; - - /// @brief ValueConverter::Type is the type of a grid having the same - /// hierarchy as this grid but a different value type, T. - /// - /// For example, FloatGrid::ValueConverter::Type is equivalent to DoubleGrid. - /// @note If the source grid type is a template argument, it might be necessary - /// to write "typename SourceGrid::template ValueConverter::Type". - template - struct ValueConverter { - typedef Grid::Type> Type; - }; - - /// Return a new grid with the given background value. - static Ptr create(const ValueType& background); - /// Return a new grid with background value zero. - static Ptr create(); - /// @brief Return a new grid that contains the given tree. - /// @throw ValueError if the tree pointer is null - static Ptr create(TreePtrType); - /// @brief Return a new, empty grid with the same transform and metadata as the - /// given grid and with background value zero. - static Ptr create(const GridBase& other); - - - /// Construct a new grid with background value zero. - Grid(); - /// Construct a new grid with the given background value. - explicit Grid(const ValueType& background); - /// @brief Construct a new grid that shares the given tree and associates with it - /// an identity linear transform. - /// @throw ValueError if the tree pointer is null - explicit Grid(TreePtrType); - /// Deep copy another grid's metadata, transform and tree. - Grid(const Grid&); - /// @brief Deep copy the metadata, transform and tree of another grid whose tree - /// configuration is the same as this grid's but whose value type is different. - /// Cast the other grid's values to this grid's value type. - /// @throw TypeError if the other grid's tree configuration doesn't match this grid's - /// or if this grid's ValueType is not constructible from the other grid's ValueType. - template - explicit Grid(const Grid&); - /// Deep copy another grid's metadata, but share its tree and transform. - Grid(const Grid&, ShallowCopy); - /// @brief Deep copy another grid's metadata and transform, but construct a new tree - /// with background value zero. - Grid(const GridBase&); - - virtual ~Grid() {} - - //@{ - /// @brief Return a new grid of the same type as this grid and whose - /// metadata and transform are deep copies of this grid's. - /// @details If @a treePolicy is @c CP_NEW, give the new grid a new, empty tree; - /// if @c CP_SHARE, the new grid shares this grid's tree and transform; - /// if @c CP_COPY, the new grid's tree is a deep copy of this grid's tree and transform - Ptr copy(CopyPolicy treePolicy = CP_SHARE) const; - virtual GridBase::Ptr copyGrid(CopyPolicy treePolicy = CP_SHARE) const; - //@} - //@{ - /// Return a new grid whose metadata, transform and tree are deep copies of this grid's. - Ptr deepCopy() const { return Ptr(new Grid(*this)); } - virtual GridBase::Ptr deepCopyGrid() const { return this->deepCopy(); } - //@} - - /// Return the name of this grid's type. - virtual Name type() const { return this->gridType(); } - /// Return the name of this type of grid. - static Name gridType() { return TreeType::treeType(); } - - - // - // Voxel access methods - // - /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d"). - virtual Name valueType() const { return tree().valueType(); } - - /// @brief Return this grid's background value. - /// - /// @note Use tools::changeBackground to efficiently modify the background values. - const ValueType& background() const { return mTree->background(); } - - /// Return @c true if this grid contains only inactive background voxels. - virtual bool empty() const { return tree().empty(); } - /// Empty this grid, so that all voxels become inactive background voxels. - virtual void clear() { tree().clear(); } - - /// Return an accessor that provides random read and write access to this grid's voxels. - Accessor getAccessor() { return Accessor(tree()); } - //@{ - /// Return an accessor that provides random read-only access to this grid's voxels. - ConstAccessor getAccessor() const { return ConstAccessor(tree()); } - ConstAccessor getConstAccessor() const { return ConstAccessor(tree()); } - //@} - - //@{ - /// Return an iterator over all of this grid's active values (tile and voxel). - ValueOnIter beginValueOn() { return tree().beginValueOn(); } - ValueOnCIter beginValueOn() const { return tree().cbeginValueOn(); } - ValueOnCIter cbeginValueOn() const { return tree().cbeginValueOn(); } - //@} - //@{ - /// Return an iterator over all of this grid's inactive values (tile and voxel). - ValueOffIter beginValueOff() { return tree().beginValueOff(); } - ValueOffCIter beginValueOff() const { return tree().cbeginValueOff(); } - ValueOffCIter cbeginValueOff() const { return tree().cbeginValueOff(); } - //@} - //@{ - /// Return an iterator over all of this grid's values (tile and voxel). - ValueAllIter beginValueAll() { return tree().beginValueAll(); } - ValueAllCIter beginValueAll() const { return tree().cbeginValueAll(); } - ValueAllCIter cbeginValueAll() const { return tree().cbeginValueAll(); } - //@} - - /// Return the minimum and maximum active values in this grid. - void evalMinMax(ValueType& minVal, ValueType& maxVal) const; - - /// @brief Set all voxels within a given axis-aligned box to a constant value. - /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box - /// @param value the value to which to set voxels within the box - /// @param active if true, mark voxels within the box as active, - /// otherwise mark them as inactive - /// @note This operation generates a sparse, but not always optimally sparse, - /// representation of the filled box. Follow fill operations with a prune() - /// operation for optimal sparseness. - void fill(const CoordBBox& bbox, const ValueType& value, bool active = true); - - /// Reduce the memory footprint of this grid by increasing its sparseness. - virtual void pruneGrid(float tolerance = 0.0); - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Clip this grid to the given index-space bounding box. - /// @details Voxels that lie outside the bounding box are set to the background. - /// @warning Clipping a level set will likely produce a grid that is - /// no longer a valid level set. - virtual void clip(const CoordBBox&); -#endif - - /// @brief Efficiently merge another grid into this grid using one of several schemes. - /// @details This operation is primarily intended to combine grids that are mostly - /// non-overlapping (for example, intermediate grids from computations that are - /// parallelized across disjoint regions of space). - /// @warning This operation always empties the other grid. - void merge(Grid& other, MergePolicy policy = MERGE_ACTIVE_STATES); - - /// @brief Union this grid's set of active values with the active values - /// of the other grid, whose value type may be different. - /// @details The resulting state of a value is active if the corresponding value - /// was already active OR if it is active in the other grid. Also, a resulting - /// value maps to a voxel if the corresponding value already mapped to a voxel - /// OR if it is a voxel in the other grid. Thus, a resulting value can only - /// map to a tile if the corresponding value already mapped to a tile - /// AND if it is a tile value in the other grid. - /// - /// @note This operation modifies only active states, not values. - /// Specifically, active tiles and voxels in this grid are not changed, and - /// tiles or voxels that were inactive in this grid but active in the other grid - /// are marked as active in this grid but left with their original values. - template - void topologyUnion(const Grid& other); - - /// @brief Intersect this grid's set of active values with the active values - /// of the other grid, whose value type may be different. - /// @details The resulting state of a value is active only if the corresponding - /// value was already active AND if it is active in the other tree. Also, a - /// resulting value maps to a voxel if the corresponding value - /// already mapped to an active voxel in either of the two grids - /// and it maps to an active tile or voxel in the other grid. - /// - /// @note This operation can delete branches of this grid that overlap with - /// inactive tiles in the other grid. Also, because it can deactivate voxels, - /// it can create leaf nodes with no active values. Thus, it is recommended - /// to prune this grid after calling this method. - template - void topologyIntersection(const Grid& other); - - /// @brief Difference this grid's set of active values with the active values - /// of the other grid, whose value type may be different. - /// @details After this method is called, voxels in this grid will be active - /// only if they were active to begin with and if the corresponding voxels - /// in the other grid were inactive. - /// - /// @note This operation can delete branches of this grid that overlap with - /// active tiles in the other grid. Also, because it can deactivate voxels, - /// it can create leaf nodes with no active values. Thus, it is recommended - /// to prune this grid after calling this method. - template - void topologyDifference(const Grid& other); - - // - // Statistics - // - /// Return the number of active voxels. - virtual Index64 activeVoxelCount() const { return tree().activeVoxelCount(); } - /// Return the axis-aligned bounding box of all active voxels. - virtual CoordBBox evalActiveVoxelBoundingBox() const; - /// Return the dimensions of the axis-aligned bounding box of all active voxels. - virtual Coord evalActiveVoxelDim() const; - - /// Return the number of bytes of memory used by this grid. - /// @todo Add transform().memUsage() - virtual Index64 memUsage() const { return tree().memUsage(); } - - - // - // Tree methods - // - //@{ - /// @brief Return a pointer to this grid's tree, which might be - /// shared with other grids. The pointer is guaranteed to be non-null. - TreePtrType treePtr() { return mTree; } - ConstTreePtrType treePtr() const { return mTree; } - ConstTreePtrType constTreePtr() const { return mTree; } - virtual TreeBase::ConstPtr constBaseTreePtr() const { return mTree; } - //@} - //@{ - /// @brief Return a reference to this grid's tree, which might be - /// shared with other grids. - /// @note Calling setTree() on this grid invalidates all references - /// previously returned by this method. - TreeType& tree() { return *mTree; } - const TreeType& tree() const { return *mTree; } - const TreeType& constTree() const { return *mTree; } - //@} - - /// @brief Associate the given tree with this grid, in place of its existing tree. - /// @throw ValueError if the tree pointer is null - /// @throw TypeError if the tree is not of type TreeType - /// @note Invalidates all references previously returned by baseTree(), - /// constBaseTree(), tree() or constTree(). - virtual void setTree(TreeBase::Ptr); - - /// @brief Associate a new, empty tree with this grid, in place of its existing tree. - /// @note The new tree has the same background value as the existing tree. - virtual void newTree(); - - - // - // I/O methods - // - /// @brief Read the grid topology from a stream. - /// This will read only the grid structure, not the actual data buffers. - virtual void readTopology(std::istream&); - /// @brief Write the grid topology to a stream. - /// This will write only the grid structure, not the actual data buffers. - virtual void writeTopology(std::ostream&) const; - - /// Read all data buffers for this grid. - virtual void readBuffers(std::istream&); -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Read all of this grid's data buffers that intersect the given index-space bounding box. - virtual void readBuffers(std::istream&, const CoordBBox&); - /// @brief Read all of this grid's data buffers that are not yet resident in memory - /// (because delayed loading is in effect). - /// @details If this grid was read from a memory-mapped file, this operation - /// disconnects the grid from the file. - /// @sa io::File::open, io::MappedFile - virtual void readNonresidentBuffers() const; -#endif - /// Write out all data buffers for this grid. - virtual void writeBuffers(std::ostream&) const; - - /// Output a human-readable description of this grid. - virtual void print(std::ostream& = std::cout, int verboseLevel = 1) const; - - - // - // Registry methods - // - /// Return @c true if this grid type is registered. - static bool isRegistered() { return GridBase::isRegistered(Grid::gridType()); } - /// Register this grid type along with a factory function. - static void registerGrid() { GridBase::registerGrid(Grid::gridType(), Grid::factory); } - /// Remove this grid type from the registry. - static void unregisterGrid() { GridBase::unregisterGrid(Grid::gridType()); } - - -private: - /// Disallow assignment, since it wouldn't be obvious whether the copy is deep or shallow. - Grid& operator=(const Grid& other); - - /// Helper function for use with registerGrid() - static GridBase::Ptr factory() { return Grid::create(); } - - TreePtrType mTree; -}; // class Grid - - -//////////////////////////////////////// - - -/// @brief Cast a generic grid pointer to a pointer to a grid of a concrete class. -/// -/// Return a null pointer if the input pointer is null or if it -/// points to a grid that is not of type @c GridType. -/// -/// @note Calling gridPtrCast(grid) is equivalent to calling -/// GridBase::grid(grid). -template -inline typename GridType::Ptr -gridPtrCast(const GridBase::Ptr& grid) -{ - return GridBase::grid(grid); -} - - -/// @brief Cast a generic const grid pointer to a const pointer to a grid -/// of a concrete class. -/// -/// Return a null pointer if the input pointer is null or if it -/// points to a grid that is not of type @c GridType. -/// -/// @note Calling gridConstPtrCast(grid) is equivalent to calling -/// GridBase::constGrid(grid). -template -inline typename GridType::ConstPtr -gridConstPtrCast(const GridBase::ConstPtr& grid) -{ - return GridBase::constGrid(grid); -} - - -//////////////////////////////////////// - - -/// @{ -/// @brief Return a pointer to a deep copy of the given grid, provided that -/// the grid's concrete type is @c GridType. -/// -/// Return a null pointer if the input pointer is null or if it -/// points to a grid that is not of type @c GridType. -template -inline typename GridType::Ptr -deepCopyTypedGrid(const GridBase::ConstPtr& grid) -{ - if (!grid || !grid->isType()) return typename GridType::Ptr(); - return gridPtrCast(grid->deepCopyGrid()); -} - - -template -inline typename GridType::Ptr -deepCopyTypedGrid(const GridBase& grid) -{ - if (!grid.isType()) return typename GridType::Ptr(); - return gridPtrCast(grid.deepCopyGrid()); -} -/// @} - - -//////////////////////////////////////// - - -//@{ -/// @brief This adapter allows code that is templated on a Tree type to -/// accept either a Tree type or a Grid type. -template -struct TreeAdapter -{ - typedef _TreeType TreeType; - typedef typename boost::remove_const::type NonConstTreeType; - typedef typename TreeType::Ptr TreePtrType; - typedef typename TreeType::ConstPtr ConstTreePtrType; - typedef typename NonConstTreeType::Ptr NonConstTreePtrType; - typedef Grid GridType; - typedef Grid NonConstGridType; - typedef typename GridType::Ptr GridPtrType; - typedef typename NonConstGridType::Ptr NonConstGridPtrType; - typedef typename GridType::ConstPtr ConstGridPtrType; - typedef typename TreeType::ValueType ValueType; - typedef typename tree::ValueAccessor AccessorType; - typedef typename tree::ValueAccessor ConstAccessorType; - typedef typename tree::ValueAccessor NonConstAccessorType; - - static TreeType& tree(TreeType& t) { return t; } - static TreeType& tree(GridType& g) { return g.tree(); } - static const TreeType& tree(const TreeType& t) { return t; } - static const TreeType& tree(const GridType& g) { return g.tree(); } - static const TreeType& constTree(TreeType& t) { return t; } - static const TreeType& constTree(GridType& g) { return g.constTree(); } - static const TreeType& constTree(const TreeType& t) { return t; } - static const TreeType& constTree(const GridType& g) { return g.constTree(); } -}; - - -/// Partial specialization for Grid types -template -struct TreeAdapter > -{ - typedef _TreeType TreeType; - typedef typename boost::remove_const::type NonConstTreeType; - typedef typename TreeType::Ptr TreePtrType; - typedef typename TreeType::ConstPtr ConstTreePtrType; - typedef typename NonConstTreeType::Ptr NonConstTreePtrType; - typedef Grid GridType; - typedef Grid NonConstGridType; - typedef typename GridType::Ptr GridPtrType; - typedef typename NonConstGridType::Ptr NonConstGridPtrType; - typedef typename GridType::ConstPtr ConstGridPtrType; - typedef typename TreeType::ValueType ValueType; - typedef typename tree::ValueAccessor AccessorType; - typedef typename tree::ValueAccessor ConstAccessorType; - typedef typename tree::ValueAccessor NonConstAccessorType; - - static TreeType& tree(TreeType& t) { return t; } - static TreeType& tree(GridType& g) { return g.tree(); } - static const TreeType& tree(const TreeType& t) { return t; } - static const TreeType& tree(const GridType& g) { return g.tree(); } - static const TreeType& constTree(TreeType& t) { return t; } - static const TreeType& constTree(GridType& g) { return g.constTree(); } - static const TreeType& constTree(const TreeType& t) { return t; } - static const TreeType& constTree(const GridType& g) { return g.constTree(); } -}; - -/// Partial specialization for ValueAccessor types -template -struct TreeAdapter > -{ - typedef _TreeType TreeType; - typedef typename boost::remove_const::type NonConstTreeType; - typedef typename TreeType::Ptr TreePtrType; - typedef typename TreeType::ConstPtr ConstTreePtrType; - typedef typename NonConstTreeType::Ptr NonConstTreePtrType; - typedef Grid GridType; - typedef Grid NonConstGridType; - typedef typename GridType::Ptr GridPtrType; - typedef typename NonConstGridType::Ptr NonConstGridPtrType; - typedef typename GridType::ConstPtr ConstGridPtrType; - typedef typename TreeType::ValueType ValueType; - typedef typename tree::ValueAccessor AccessorType; - typedef typename tree::ValueAccessor ConstAccessorType; - typedef typename tree::ValueAccessor NonConstAccessorType; - - static TreeType& tree(TreeType& t) { return t; } - static TreeType& tree(GridType& g) { return g.tree(); } - static TreeType& tree(AccessorType& a) { return a.tree(); } - static const TreeType& tree(const TreeType& t) { return t; } - static const TreeType& tree(const GridType& g) { return g.tree(); } - static const TreeType& tree(const AccessorType& a) { return a.tree(); } - static const TreeType& constTree(TreeType& t) { return t; } - static const TreeType& constTree(GridType& g) { return g.constTree(); } - static const TreeType& constTree(const TreeType& t) { return t; } - static const TreeType& constTree(const GridType& g) { return g.constTree(); } -}; - -//@} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -GridBase::grid(const GridBase::Ptr& grid) -{ - // The string comparison on type names is slower than a dynamic_pointer_cast, but - // it is safer when pointers cross dso boundaries, as they do in many Houdini nodes. - if (grid && grid->type() == GridType::gridType()) { - return boost::static_pointer_cast(grid); - } - return typename GridType::Ptr(); -} - - -template -inline typename GridType::ConstPtr -GridBase::grid(const GridBase::ConstPtr& grid) -{ - return boost::const_pointer_cast( - GridBase::grid(boost::const_pointer_cast(grid))); -} - - -template -inline typename GridType::ConstPtr -GridBase::constGrid(const GridBase::Ptr& grid) -{ - return boost::const_pointer_cast(GridBase::grid(grid)); -} - - -template -inline typename GridType::ConstPtr -GridBase::constGrid(const GridBase::ConstPtr& grid) -{ - return boost::const_pointer_cast( - GridBase::grid(boost::const_pointer_cast(grid))); -} - - -inline TreeBase::Ptr -GridBase::baseTreePtr() -{ - return boost::const_pointer_cast(this->constBaseTreePtr()); -} - - -inline void -GridBase::setTransform(math::Transform::Ptr xform) -{ - if (!xform) OPENVDB_THROW(ValueError, "Transform pointer is null"); - mTransform = xform; -} - - -//////////////////////////////////////// - - -template -inline Grid::Grid(): mTree(new TreeType) -{ -} - - -template -inline Grid::Grid(const ValueType &background): mTree(new TreeType(background)) -{ -} - - -template -inline Grid::Grid(TreePtrType tree): mTree(tree) -{ - if (!tree) OPENVDB_THROW(ValueError, "Tree pointer is null"); -} - - -template -inline Grid::Grid(const Grid& other): - GridBase(other), - mTree(boost::static_pointer_cast(other.mTree->copy())) -{ -} - - -template -template -inline Grid::Grid(const Grid& other): - GridBase(other), - mTree(new TreeType(other.constTree())) -{ -} - - -template -inline Grid::Grid(const Grid& other, ShallowCopy): - GridBase(other, ShallowCopy()), - mTree(other.mTree) -{ -} - - -template -inline Grid::Grid(const GridBase& other): - GridBase(other), - mTree(new TreeType) -{ -} - - -//static -template -inline typename Grid::Ptr -Grid::create() -{ - return Grid::create(zeroVal()); -} - - -//static -template -inline typename Grid::Ptr -Grid::create(const ValueType& background) -{ - return Ptr(new Grid(background)); -} - - -//static -template -inline typename Grid::Ptr -Grid::create(TreePtrType tree) -{ - return Ptr(new Grid(tree)); -} - - -//static -template -inline typename Grid::Ptr -Grid::create(const GridBase& other) -{ - return Ptr(new Grid(other)); -} - - -//////////////////////////////////////// - - -template -inline typename Grid::Ptr -Grid::copy(CopyPolicy treePolicy) const -{ - Ptr ret; - switch (treePolicy) { - case CP_NEW: - ret.reset(new Grid(*this, ShallowCopy())); - ret->newTree(); - break; - case CP_COPY: - ret.reset(new Grid(*this)); - break; - case CP_SHARE: - ret.reset(new Grid(*this, ShallowCopy())); - break; - } - return ret; -} - - -template -inline GridBase::Ptr -Grid::copyGrid(CopyPolicy treePolicy) const -{ - return this->copy(treePolicy); -} - - -//////////////////////////////////////// - - -template -inline void -Grid::setTree(TreeBase::Ptr tree) -{ - if (!tree) OPENVDB_THROW(ValueError, "Tree pointer is null"); - if (tree->type() != TreeType::treeType()) { - OPENVDB_THROW(TypeError, "Cannot assign a tree of type " - + tree->type() + " to a grid of type " + this->type()); - } - mTree = boost::static_pointer_cast(tree); -} - - -template -inline void -Grid::newTree() -{ - mTree.reset(new TreeType(this->background())); -} - - -//////////////////////////////////////// - - -template -inline void -Grid::fill(const CoordBBox& bbox, const ValueType& value, bool active) -{ - tree().fill(bbox, value, active); -} - -template -inline void -Grid::pruneGrid(float tolerance) -{ - this->tree().prune(ValueType(zeroVal() + tolerance)); -} - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -inline void -Grid::clip(const CoordBBox& bbox) -{ - tree().clip(bbox); -} -#endif - - -template -inline void -Grid::merge(Grid& other, MergePolicy policy) -{ - tree().merge(other.tree(), policy); -} - - -template -template -inline void -Grid::topologyUnion(const Grid& other) -{ - tree().topologyUnion(other.tree()); -} - - -template -template -inline void -Grid::topologyIntersection(const Grid& other) -{ - tree().topologyIntersection(other.tree()); -} - - -template -template -inline void -Grid::topologyDifference(const Grid& other) -{ - tree().topologyDifference(other.tree()); -} - - -//////////////////////////////////////// - - -template -inline void -Grid::evalMinMax(ValueType& minVal, ValueType& maxVal) const -{ - tree().evalMinMax(minVal, maxVal); -} - - -template -inline CoordBBox -Grid::evalActiveVoxelBoundingBox() const -{ - CoordBBox bbox; - tree().evalActiveVoxelBoundingBox(bbox); - return bbox; -} - - -template -inline Coord -Grid::evalActiveVoxelDim() const -{ - Coord dim; - const bool nonempty = tree().evalActiveVoxelDim(dim); - return (nonempty ? dim : Coord()); -} - - -//////////////////////////////////////// - - -/// @internal Consider using the stream tagging mechanism (see io::Archive) -/// to specify the float precision, but note that the setting is per-grid. - -template -inline void -Grid::readTopology(std::istream& is) -{ - tree().readTopology(is, saveFloatAsHalf()); -} - - -template -inline void -Grid::writeTopology(std::ostream& os) const -{ - tree().writeTopology(os, saveFloatAsHalf()); -} - - -template -inline void -Grid::readBuffers(std::istream& is) -{ - tree().readBuffers(is, saveFloatAsHalf()); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE - -template -inline void -Grid::readBuffers(std::istream& is, const CoordBBox& bbox) -{ - tree().readBuffers(is, bbox, saveFloatAsHalf()); -} - - -template -inline void -Grid::readNonresidentBuffers() const -{ - tree().readNonresidentBuffers(); -} - -#endif // !OPENVDB_2_ABI_COMPATIBLE - - -template -inline void -Grid::writeBuffers(std::ostream& os) const -{ - tree().writeBuffers(os, saveFloatAsHalf()); -} - - -template -inline void -Grid::print(std::ostream& os, int verboseLevel) const -{ - tree().print(os, verboseLevel); - - if (metaCount() > 0) { - os << "Additional metadata:" << std::endl; - for (ConstMetaIterator it = beginMeta(), end = endMeta(); it != end; ++it) { - os << " " << it->first; - if (it->second) { - const std::string value = it->second->str(); - if (!value.empty()) os << ": " << value; - } - os << "\n"; - } - } - - os << "Transform:" << std::endl; - transform().print(os, /*indent=*/" "); - os << std::endl; -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -createGrid(const typename GridType::ValueType& background) -{ - return GridType::create(background); -} - - -template -inline typename GridType::Ptr -createGrid() -{ - return GridType::create(); -} - - -template -inline typename Grid::Ptr -createGrid(TreePtrType tree) -{ - typedef typename TreePtrType::element_type TreeType; - return Grid::create(tree); -} - - -template -typename GridType::Ptr -createLevelSet(Real voxelSize, Real halfWidth) -{ - typedef typename GridType::ValueType ValueType; - - // GridType::ValueType is required to be a floating-point scalar. - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - typename GridType::Ptr grid = GridType::create( - /*background=*/static_cast(voxelSize * halfWidth)); - grid->setTransform(math::Transform::createLinearTransform(voxelSize)); - grid->setGridClass(GRID_LEVEL_SET); - return grid; -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_GRID_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/INSTALL b/openvdb_3_0_0_library/INSTALL deleted file mode 100755 index 976eeeb..0000000 --- a/openvdb_3_0_0_library/INSTALL +++ /dev/null @@ -1,263 +0,0 @@ -Installing OpenVDB -================== - -Requirements ------------- -- GNU GCC (gcc.gnu.org), version 4.1 or later - or Intel ICC (software.intel.com), version 11.1 or later - -- GNU gmake (www.gnu.org/software/make/), version 3.81 or later - -- Boost (www.boost.org), version 1.42.0 or later - (Linux: yum install boost-devel; OS X: port install boost +python26) - -- libz (zlib.net) - (Linux: yum install zlib-devel) - -- OpenEXR (www.openexr.com), for the 16-bit float Half class in half.h - and for .exr file output in vdb_render - -- Intel Threading Building Blocks (threadingbuildingblocks.org), - version 3.0 or later - -Other compilers or versions might work but have not been tested. - - -Optional: - -- Doxygen 1.8 (www.stack.nl/~dimitri/doxygen/), for documentation - -- CppUnit (www.freedesktop.org/wiki/Software/cppunit), version 1.10 or later - (Linux: yum install cppunit-devel) - -- Houdini HDK (ftp://ftp.sidefx.com/public/Houdini12.0), version 12.0.628 - or later - -- Blosc compression library (www.blosc.org), version 1.5.0 or later - (included in the Houdini HDK as of version 14.0) - -- Ghostscript (www.ghostscript.com), version 8.70 or later, for documentation - in PDF format - -- pdfLaTeX (www.pdftex.org), version 1.21 or later, for documentation - in PDF format - -- log4cplus (log4cplus.sourceforge.net), version 1.0 or later, - for error logging - -- GLFW 2.7 (www.glfw.org), for the OpenVDB viewer - -- OpenGL 3.2 or later, for the OpenVDB viewer - -- Python 2.5, 2.6 or 2.7, for the Python module - -- NumPy (www.numpy.org), for the Python module - -- Epydoc (http://epydoc.sourceforge.net/), version 3.0 or later, - for Python module documentation - -Other versions might work but have not been tested. - - -Installation ------------- -1. Set values appropriate to your environment for the following variables - at the top of the Makefile: - - INSTALL_DIR the directory into which to install libraries, - executables and header files (e.g., /usr/local) - - BOOST_INCL_DIR the parent directory of the boost/ header directory - (e.g., /usr/include) - BOOST_LIB_DIR the directory containing libboost_iostreams, etc. - BOOST_LIB linker flags for libboost_iostreams and libboost_system - BOOST_THREAD_LIB linker flags for libboost_thread - - ILMBASE_INCL_DIR the parent directory of the OpenEXR/ header directory - (which contains half.h) - ILMBASE_LIB_DIR the directory containing libHalf.so and/or libHalf.a - ILMBASE_LIB linker flags for libIlmThread, libIex and libImath - HALF_LIB linker flag(s) for the Half library (e.g., -lHalf) - - EXR_INCL_DIR the parent directory of the OpenEXR/ header directory - (Note: some OpenEXR headers incorrectly include other - OpenEXR headers with, e.g., '#include ' - instead of '#include "ImfName.h"'. When compiling - with Clang, set EXR_INCL_DIR to the parent directory - of the OpenEXR/ directory and ILMBASE_INCL_DIR to the - OpenEXR/ directory itself to avoid errors.) - EXR_LIB_DIR the directory containing libIlmImf - EXR_LIB linker flags for libIlmImf - - TBB_INCL_DIR the parent directory of the tbb/ header directory - TBB_LIB_DIR the directory containing libtbb - TBB_LIB linker flag(s) for the TBB library (e.g., -ltbb) - - BLOSC_INCL_DIR the parent directory of the blosc.h header - BLOSC_LIB_DIR the directory containing libblosc - BLOSC_LIB linker flags for libblosc - - CONCURRENT_MALLOC_LIB_DIR - a directory containing a scalable, concurrent malloc - replacement library such as jemalloc or TBB malloc - (leave blank if no such library is available, but - be aware that using standard malloc in concurrent - code incurs a significant performance penalty) - CONCURRENT_MALLOC_LIB - linker flag(s) for the malloc replacement library - (e.g., -ltbbmalloc_proxy -ltbbmalloc) - - CPPUNIT_INCL_DIR the parent directory of the cppunit/ header directory - (leave blank if CppUnit is not available) - CPPUNIT_LIB_DIR the directory containing libcppunit.so or libcppunit.a - CPPUNIT_LIB linker flag(s) for the cppunit library - (e.g., -lcppunit) - - GLFW_INCL_DIR the directory containing glfw.h - (leave blank if GLFW is not available; - GLFW is needed only for the command-line viewer tool) - GLFW_LIB_DIR the directory containing libglfw - GLFW_LIB linker flags for the GLFW library (e.g., -lglfw) - GLFW_MAJOR_VERSION the major version number of the GLFW library - (header filenames changed between GLFW 2 and 3, - so this must be specified explicitly) - - LOG4CPLUS_INCL_DIR the parent directory of the log4cplus/ header directory - (leave blank if log4cplus is not available) - LOG4CPLUS_LIB_DIR directory containing liblog4cplus.so or liblog4cplus.a - LOG4CPLUS_LIB linker flags for the log4cplus library - (e.g., -llog4cplus) - - PYTHON_VERSION the version of Python for which to build the OpenVDB - module (e.g., 2.6) - (leave blank if Python is unavailable) - PYTHON_INCL_DIR the directory containing the Python.h header file - (on OS X, this is usually /System/Library/Frameworks/ - Python.framework/Versions/$(PYTHON_VERSION)/Headers) - PYCONFIG_INCL_DIR the directory containing the pyconfig.h header file - (usually but not always the same as PYTHON_INCL_DIR) - PYTHON_LIB_DIR the directory containing the Python library - (on OS X, this is usually /System/Library/Frameworks/ - Python.framework/Versions/$(PYTHON_VERSION)/lib) - PYTHON_LIB linker flags for the Python library - (e.g., -lpython2.6) - BOOST_PYTHON_LIB_DIR - the directory containing the Boost.Python library - BOOST_PYTHON_LIB linker flags for the Boost.Python library - (e.g., -lboost_python-mt) - NUMPY_INCL_DIR the directory containing the NumPy arrayobject.h - header file (leave blank if NumPy is unavailable) - (on OS X, this is usually /System/Library/Frameworks/ - Python.framework/Versions/$(PYTHON_VERSION)/Extras/ - lib/python/numpy/core/include/numpy) - EPYDOC the path to the Epydoc executable - (leave blank if Epydoc is unavailable) - PYTHON_WRAP_ALL_GRID_TYPES - if set to "no", expose only FloatGrid, BoolGrid - and Vec3SGrid in Python, otherwise expose (most of) - the standard grid types defined in openvdb.h - - DOXYGEN the path to the Doxygen executable - (leave blank if Doxygen is unavailable) - - Note that if you plan to build the Houdini OpenVDB tools (distributed - separately), you must build the OpenVDB library and the Houdini tools - against compatible versions of the Boost, OpenEXR and TBB libraries. - Fortunately, all three are included in the Houdini HDK, so by default - several of the variables above reference the Houdini environment variables - $HDSO, $HFS and $HT. Source the houdini_setup script provided with - your Houdini installation to set those environment variables. - - Also note that certain new features in OpenVDB 3 (see the CHANGES file - for details) necessitated changes to the ABI of the Grid class, - rendering it incompatible with earlier versions of the library, - such as the ones in Houdini 12.5 and 13. Passing grids between native - VDB nodes in a scene graph and nodes built against the new ABI - will lead to crashes, so if you must use OpenVDB 3 with those versions - of Houdini, set abi=2 to compile with the incompatible features disabled. - - To build the OpenVDB Python module, you will need local installations of - Python, Boost.Python, and optionally NumPy. As of Houdini 12.5, the HDK - includes versions 2.5 and 2.6 of Python as well as Boost.Python headers. - Unfortunately, it includes neither the libboost_python library nor NumPy, - so both Boost.Python and NumPy have to be built separately. - Point the variables $(BOOST_PYTHON_LIB_DIR), $(BOOST_PYTHON_LIB) and - $(NUMPY_INCL_DIR) to your local installations of those libraries. - -2. From the top-level openvdb/ directory, type "make" (or "make -s" for - less verbose output) to locally build the library and commands. - The Makefile supports parallel builds (e.g. "make -j 8"). - - A default local build generates the following libraries and executables - (but see the Makefile for additional targets and build options): - - openvdb/libopenvdb.so.3.0.0 the OpenVDB library - openvdb/libopenvdb.so symlink to libopenvdb.so.3.0.0 - openvdb/pyopenvdb.so the OpenVDB Python module (if Python - and Boost.Python are available) - openvdb/vdb_print command-line tool that prints info - about OpenVDB .vdb files - openvdb/vdb_render command-line tool that ray-traces - OpenVDB volumes - openvdb/vdb_test unit test runner for libopenvdb - (if CppUnit is available) - - From the openvdb/ directory, type "make test" to run the unit tests - and verify that the library is working correctly. (Alternatively, once - the library has been installed (Step 5), run the unit test executable - directly with "./vdb_test", or "./vdb_test -v" for more verbose output.) - Type "make pytest" to run the Python module unit tests. - -3. From the openvdb/ directory, type "make doc" (or "make -s doc") - to generate HTML library documentation, then open the file - openvdb/doc/html/index.html in a browser. Type "make pydoc" - (or "make -s pydoc") to generate HTML Python module documentation, - then open openvdb/doc/html/python/index.html in a browser. - -4. Optionally (if OpenGL and GLFW are available), from the top-level openvdb/ - directory, type "make vdb_view" (or "make -s vdb_view") to locally build - the OpenVDB viewer tool. Then type "./vdb_view" for usage information. - -5. From the openvdb/ directory, type "make install" (or "make -s install") - to copy generated files into the directory tree rooted at $(INSTALL_DIR). - This creates the following distribution: - - $(INSTALL_DIR)/ - bin/ - vdb_print - vdb_render - vdb_view - include/ - openvdb/ - Exceptions.h - ... - openvdb.h - tools/ - tree/ - ... - version.h - lib/ - libopenvdb.so - libopenvdb.so.3.0 - libopenvdb.so.3.0.0 - - python/ - include/ - python$(PYTHON_VERSION)/ - pyopenvdb.h - lib/ - python$(PYTHON_VERSION)/ - pyopenvdb.so - pyopenvdb.so.3.0 - - share/ - doc/ - openvdb/ - html/ - index.html - ... - python/ - index.html - ... - -EOF diff --git a/openvdb_3_0_0_library/LICENSE b/openvdb_3_0_0_library/LICENSE deleted file mode 100755 index 14e2f77..0000000 --- a/openvdb_3_0_0_library/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/openvdb_3_0_0_library/Makefile b/openvdb_3_0_0_library/Makefile deleted file mode 100755 index 46f2bdb..0000000 --- a/openvdb_3_0_0_library/Makefile +++ /dev/null @@ -1,928 +0,0 @@ -# Copyright (c) 2012-2014 DreamWorks Animation LLC -# -# All rights reserved. This software is distributed under the -# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -# -# Redistributions of source code must retain the above copyright -# and license notice and the following restrictions and disclaimer. -# -# * Neither the name of DreamWorks Animation nor the names of -# its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -# -# Makefile for the OpenVDB library - -# See INSTALL for a list of requirements. -# -# Targets: -# lib the OpenVDB library -# -# doc HTML documentation (doc/html/index.html) -# pdfdoc PDF documentation (doc/latex/refman.pdf; -# requires LaTeX and ghostscript) -# python OpenVDB Python module -# pytest unit tests for the Python module -# pydoc HTML documentation for the Python module -# (doc/html/python/index.html) -# vdb_print command-line tool to inspect OpenVDB files -# vdb_render command-line tool to ray-trace OpenVDB files -# vdb_view command-line tool to view OpenVDB files -# vdb_test unit tests for the OpenVDB library -# -# all [default target] all of the above -# install install all of the above except vdb_test -# into subdirectories of DESTDIR -# depend recompute source file header dependencies -# clean delete generated files from the local directory -# test run tests -# -# Options: -# abi=2 build for compatibility with the OpenVDB 2.x Grid ABI -# (some OpenVDB 3.x features will be disabled) -# shared=no link executables against static OpenVDB libraries -# (default: link against shared libraries) -# debug=yes build with debugging symbols and without optimization -# verbose=yes run commands (e.g., doxygen) in verbose mode - - -# -# The following variables must be defined, either here or on the command line -# (e.g., "make install DESTDIR=/usr/local"): -# -# Note that if you plan to build the Houdini OpenVDB tools (distributed -# separately), you must build the OpenVDB library and the Houdini tools -# against compatible versions of the Boost, OpenEXR and TBB libraries. -# Fortunately, all three are included in the Houdini HDK, so the relevant -# variables below point by default to the HDK library and header directories: -# $(HDSO) and $(HT)/include, respectively. (Source the houdini_setup script -# to set those two environment variables.) -# -# To build the OpenVDB Python module, you will need local distributions of -# Python, Boost.Python, and optionally NumPy. As of Houdini 12.5, the HDK -# includes versions 2.5 and 2.6 of Python as well as the Boost.Python headers. -# Unfortunately, it does not include the libboost_python library, nor does it -# include NumPy, so both Boost.Python and NumPy have to be built separately. -# Point the variables $(BOOST_PYTHON_LIB_DIR), $(BOOST_PYTHON_LIB) and -# $(NUMPY_INCL_DIR) below to your local distributions of those libraries. -# - -# The directory into which to install libraries, executables and header files -DESTDIR := /tmp/OpenVDB - -# The parent directory of the boost/ header directory -BOOST_INCL_DIR := $(HT)/include -# The directory containing libboost_iostreams, libboost_system, etc. -BOOST_LIB_DIR := $(HDSO) -BOOST_LIB := -lboost_iostreams -lboost_system -BOOST_THREAD_LIB := -lboost_thread - -# The parent directory of the OpenEXR/ header directory -EXR_INCL_DIR := $(HT)/include -# The directory containing IlmImf -EXR_LIB_DIR := $(HDSO) -EXR_LIB := -lIlmImf - -# The parent directory of the OpenEXR/ header directory (which contains half.h) -ILMBASE_INCL_DIR := $(EXR_INCL_DIR) -# The directory containing libIlmThread, libIlmThread, libHalf etc. -ILMBASE_LIB_DIR := $(EXR_LIB_DIR) -ILMBASE_LIB := -lIlmThread -lIex -lImath -HALF_LIB := -lHalf - -# The parent directory of the tbb/ header directory -TBB_INCL_DIR := $(HT)/include -# The directory containing libtbb -TBB_LIB_DIR := $(HDSO) -TBB_LIB := -ltbb - -# The parent directory of the blosc.h header -# (leave blank if Blosc is unavailable) -BLOSC_INCL_DIR := $(HT)/include -# The directory containing libblosc -BLOSC_LIB_DIR := $(HDSO) -BLOSC_LIB := -lblosc - -# A scalable, concurrent malloc replacement library -# such as jemalloc (included in the Houdini HDK) or TBB malloc -# (leave blank if unavailable) -CONCURRENT_MALLOC_LIB := -ljemalloc -#CONCURRENT_MALLOC_LIB := -ltbbmalloc_proxy -ltbbmalloc -# The directory containing the malloc replacement library -CONCURRENT_MALLOC_LIB_DIR := $(HDSO) - -# The parent directory of the cppunit/ header directory -# (leave blank if CppUnit is unavailable) -CPPUNIT_INCL_DIR := /rel/map/generic-2013.22/sys_include -# The directory containing libcppunit -CPPUNIT_LIB_DIR := /rel/depot/third_party_build/cppunit/1.10.2-7/opt-ws5-x86_64-gccWS5_64/lib -CPPUNIT_LIB := -lcppunit - -# The parent directory of the log4cplus/ header directory -# (leave blank if log4cplus is unavailable) -LOG4CPLUS_INCL_DIR := /rel/folio/log4cplus/log4cplus-1.0.3-latest/sys_include -# The directory containing liblog4cplus -LOG4CPLUS_LIB_DIR := /rel/folio/log4cplus/log4cplus-1.0.3-latest/library -LOG4CPLUS_LIB := -llog4cplus - -# The directory containing glfw.h -# (leave blank if GLFW is unavailable) -GLFW_INCL_DIR := /rel/third_party/glfw/glfw-3.0.1/include -# The directory containing libglfw -GLFW_LIB_DIR := /rel/third_party/glfw/glfw-3.0.1/lib -GLFW_LIB := -lglfw -# The major version number of the GLFW library -# (header filenames changed between GLFW 2 and 3, so this must be specified explicitly) -GLFW_MAJOR_VERSION := 3 - -# The version of Python for which to build the OpenVDB module -# (leave blank if Python is unavailable) -PYTHON_VERSION := 2.6 -# The directory containing Python.h -PYTHON_INCL_DIR := $(HFS)/python/include/python$(PYTHON_VERSION) -# The directory containing pyconfig.h -PYCONFIG_INCL_DIR := $(PYTHON_INCL_DIR) -# The directory containing libpython -PYTHON_LIB_DIR := $(HFS)/python/lib -PYTHON_LIB := -lpython$(PYTHON_VERSION) -# The directory containing libboost_python -BOOST_PYTHON_LIB_DIR := /rel/depot/third_party_build/boost/rhel6-1.46.1-0/lib -BOOST_PYTHON_LIB := -lboost_python-gcc41-mt-python26-1_46_1 -# The directory containing arrayobject.h -# (leave blank if NumPy is unavailable) -NUMPY_INCL_DIR := /rel/map/generic-2013.22/include -# The Epydoc executable -# (leave blank if Epydoc is unavailable) -EPYDOC := epydoc -# Set PYTHON_WRAP_ALL_GRID_TYPES to "yes" to specify that the Python module -# should expose (almost) all of the grid types defined in openvdb.h -# Otherwise, only FloatGrid, BoolGrid and Vec3SGrid will be exposed -# (see, e.g., exportIntGrid() in python/pyIntGrid.cc). -# Compiling the Python module with PYTHON_WRAP_ALL_GRID_TYPES set to "yes" -# can be very memory-intensive. -PYTHON_WRAP_ALL_GRID_TYPES := no - -# The Doxygen executable -# (leave blank if Doxygen is unavailable) -DOXYGEN := doxygen - - -# -# Ideally, users shouldn't need to change anything below this line. -# - -SHELL = /bin/bash - -# Turn off implicit rules for speed. -.SUFFIXES: - -ifneq (,$(INSTALL_DIR)) - $(warning Warning: $$(INSTALL_DIR) is no longer used; set $$(DESTDIR) instead.) -endif - -# Determine the platform. -ifeq ("$(OS)","Windows_NT") - WINDOWS_NT := 1 -else - UNAME_S := $(shell uname -s) - ifeq ("$(UNAME_S)","Linux") - LINUX := 1 - else - ifeq ("$(UNAME_S)","Darwin") - MBSD := 1 - endif - endif -endif - -ifeq (yes,$(strip $(debug))) - OPTIMIZE := -g -else - OPTIMIZE := -O3 -DNDEBUG -endif - -ifeq (yes,$(strip $(verbose))) - QUIET := - QUIET_TEST := -v -else - QUIET := > /dev/null - QUIET_TEST := $(QUIET) -endif - -has_blosc := no -ifneq (,$(and $(BLOSC_LIB_DIR),$(BLOSC_INCL_DIR),$(BLOSC_LIB))) - has_blosc := yes -endif - -has_glfw := no -ifneq (,$(and $(GLFW_LIB_DIR),$(GLFW_INCL_DIR),$(GLFW_LIB))) - has_glfw := yes -endif - -has_log4cplus := no -ifneq (,$(and $(LOG4CPLUS_LIB_DIR),$(LOG4CPLUS_INCL_DIR),$(LOG4CPLUS_LIB))) - has_log4cplus := yes -endif - -has_python := no -ifneq (,$(and $(PYTHON_VERSION),$(PYTHON_LIB_DIR),$(PYTHON_INCL_DIR), \ - $(PYCONFIG_INCL_DIR),$(PYTHON_LIB),$(BOOST_PYTHON_LIB_DIR),$(BOOST_PYTHON_LIB))) - has_python := yes -endif - -INCLDIRS := -I . -I .. -isystem $(BOOST_INCL_DIR) -isystem $(ILMBASE_INCL_DIR) -isystem $(TBB_INCL_DIR) -ifeq (yes,$(has_blosc)) - INCLDIRS += -isystem $(BLOSC_INCL_DIR) -endif -ifeq (yes,$(has_log4cplus)) - INCLDIRS += -isystem $(LOG4CPLUS_INCL_DIR) -endif - -CXXFLAGS += -pthread $(OPTIMIZE) $(INCLDIRS) -ifeq (yes,$(has_blosc)) - CXXFLAGS += -DOPENVDB_USE_BLOSC -endif -ifeq (yes,$(has_log4cplus)) - CXXFLAGS += -DOPENVDB_USE_LOG4CPLUS -endif -ifeq (2,$(strip $(abi))) - CXXFLAGS += -DOPENVDB_2_ABI_COMPATIBLE -endif -ifneq (2,$(strip $(GLFW_MAJOR_VERSION))) - CXXFLAGS += -DOPENVDB_USE_GLFW_3 -endif - -LIBS := \ - -ldl -lm -lz \ - -L$(ILMBASE_LIB_DIR) $(HALF_LIB) \ - -L$(TBB_LIB_DIR) $(TBB_LIB) \ - -L$(BOOST_LIB_DIR) $(BOOST_LIB) \ -# -LIBS_RPATH := \ - -ldl -lm -lz \ - -Wl,-rpath,$(ILMBASE_LIB_DIR) -L$(ILMBASE_LIB_DIR) $(HALF_LIB) \ - -Wl,-rpath,$(TBB_LIB_DIR) -L$(TBB_LIB_DIR) $(TBB_LIB) \ - -Wl,-rpath,$(BOOST_LIB_DIR) -L$(BOOST_LIB_DIR) $(BOOST_LIB) \ -# -ifeq (yes,$(has_blosc)) - LIBS += -L$(BLOSC_LIB_DIR) $(BLOSC_LIB) - LIBS_RPATH += -Wl,-rpath,$(BLOSC_LIB_DIR) -L$(BLOSC_LIB_DIR) $(BLOSC_LIB) -endif -ifeq (yes,$(has_log4cplus)) - LIBS += -L$(LOG4CPLUS_LIB_DIR) $(LOG4CPLUS_LIB) - LIBS_RPATH += -Wl,-rpath,$(LOG4CPLUS_LIB_DIR) -L$(LOG4CPLUS_LIB_DIR) $(LOG4CPLUS_LIB) -endif -ifneq (,$(strip $(CONCURRENT_MALLOC_LIB))) -ifneq (,$(strip $(CONCURRENT_MALLOC_LIB_DIR))) - LIBS_RPATH += -Wl,-rpath,$(CONCURRENT_MALLOC_LIB_DIR) -L$(CONCURRENT_MALLOC_LIB_DIR) -endif -endif -ifdef LINUX - LIBS += -lrt - LIBS_RPATH += -lrt -endif - -INCLUDE_NAMES := \ - Exceptions.h \ - Grid.h \ - io/Archive.h \ - io/Compression.h \ - io/File.h \ - io/GridDescriptor.h \ - io/io.h \ - io/Queue.h \ - io/Stream.h \ - io/TempFile.h \ - math/BBox.h \ - math/Coord.h \ - math/DDA.h \ - math/FiniteDifference.h \ - math/Hermite.h \ - math/LegacyFrustum.h \ - math/Maps.h \ - math/Mat.h \ - math/Mat3.h \ - math/Mat4.h \ - math/Math.h \ - math/Operators.h \ - math/Proximity.h \ - math/QuantizedUnitVec.h \ - math/Quat.h \ - math/Ray.h \ - math/Stats.h \ - math/Stencils.h \ - math/Transform.h\ - math/Tuple.h\ - math/Vec2.h \ - math/Vec3.h \ - math/Vec4.h \ - Metadata.h \ - metadata/Metadata.h \ - metadata/MetaMap.h \ - metadata/StringMetadata.h \ - openvdb.h \ - Platform.h \ - PlatformConfig.h \ - tools/ChangeBackground.h \ - tools/Clip.h \ - tools/Composite.h \ - tools/Dense.h \ - tools/DenseSparseTools.h \ - tools/Diagnostics.h \ - tools/Filter.h \ - tools/GridOperators.h \ - tools/GridTransformer.h \ - tools/Interpolation.h \ - tools/LevelSetAdvect.h \ - tools/LevelSetFilter.h \ - tools/LevelSetFracture.h \ - tools/LevelSetMeasure.h \ - tools/LevelSetMorph.h \ - tools/LevelSetRebuild.h \ - tools/LevelSetSphere.h \ - tools/LevelSetTracker.h \ - tools/LevelSetUtil.h \ - tools/MeshToVolume.h \ - tools/Morphology.h \ - tools/ParticlesToLevelSet.h \ - tools/PointAdvect.h \ - tools/PointIndexGrid.h \ - tools/PointPartitioner.h \ - tools/PointScatter.h \ - tools/Prune.h \ - tools/RayIntersector.h \ - tools/RayTracer.h \ - tools/SignedFloodFill.h \ - tools/Statistics.h \ - tools/ValueTransformer.h \ - tools/VectorTransformer.h \ - tools/VolumeToMesh.h \ - tools/VolumeToSpheres.h \ - tree/InternalNode.h \ - tree/Iterator.h \ - tree/LeafManager.h \ - tree/LeafNode.h \ - tree/LeafNodeBool.h \ - tree/NodeManager.h \ - tree/NodeUnion.h \ - tree/RootNode.h \ - tree/Tree.h \ - tree/TreeIterator.h \ - tree/ValueAccessor.h \ - Types.h \ - util/CpuTimer.h \ - util/Formats.h \ - util/logging.h \ - util/MapsUtil.h \ - util/Name.h \ - util/NodeMasks.h \ - util/NullInterrupter.h \ - util/Util.h \ - version.h \ -# - -SRC_NAMES := \ - Grid.cc \ - io/Archive.cc \ - io/Compression.cc \ - io/File.cc \ - io/GridDescriptor.cc \ - io/Queue.cc \ - io/Stream.cc \ - io/TempFile.cc \ - math/Hermite.cc \ - math/Maps.cc \ - math/Proximity.cc \ - math/QuantizedUnitVec.cc \ - math/Transform.cc \ - metadata/Metadata.cc \ - metadata/MetaMap.cc \ - openvdb.cc \ - Platform.cc \ - util/Formats.cc \ - util/Util.cc \ -# - -UNITTEST_INCLUDE_NAMES := \ - unittest/util.h \ -# - -UNITTEST_SRC_NAMES := \ - unittest/main.cc \ - unittest/TestBBox.cc \ - unittest/TestCoord.cc \ - unittest/TestCpt.cc \ - unittest/TestCurl.cc \ - unittest/TestDense.cc \ - unittest/TestDenseSparseTools.cc \ - unittest/TestDiagnostics.cc \ - unittest/TestDivergence.cc \ - unittest/TestDoubleMetadata.cc \ - unittest/TestExceptions.cc \ - unittest/TestFile.cc \ - unittest/TestFloatMetadata.cc \ - unittest/TestGradient.cc \ - unittest/TestGrid.cc \ - unittest/TestGridBbox.cc \ - unittest/TestGridDescriptor.cc \ - unittest/TestGridIO.cc \ - unittest/TestGridTransformer.cc \ - unittest/TestHermite.cc \ - unittest/TestInit.cc \ - unittest/TestInt32Metadata.cc \ - unittest/TestInt64Metadata.cc \ - unittest/TestInternalOrigin.cc \ - unittest/TestLaplacian.cc \ - unittest/TestLeaf.cc \ - unittest/TestLeafBool.cc \ - unittest/TestLeafIO.cc \ - unittest/TestLeafOrigin.cc \ - unittest/TestLevelSetRayIntersector.cc \ - unittest/TestLevelSetUtil.cc \ - unittest/TestLinearInterp.cc \ - unittest/TestMaps.cc \ - unittest/TestMat4Metadata.cc \ - unittest/TestMath.cc \ - unittest/TestMeanCurvature.cc \ - unittest/TestMeshToVolume.cc \ - unittest/TestMetadata.cc \ - unittest/TestMetadataIO.cc \ - unittest/TestMetaMap.cc \ - unittest/TestName.cc \ - unittest/TestNodeIterator.cc \ - unittest/TestNodeMask.cc \ - unittest/TestParticlesToLevelSet.cc \ - unittest/TestPointIndexGrid.cc \ - unittest/TestPointPartitioner.cc \ - unittest/TestPrePostAPI.cc \ - unittest/TestQuadraticInterp.cc \ - unittest/TestQuantizedUnitVec.cc \ - unittest/TestQuat.cc \ - unittest/TestRay.cc \ - unittest/TestStats.cc \ - unittest/TestStream.cc \ - unittest/TestStringMetadata.cc \ - unittest/TestTools.cc \ - unittest/TestTransform.cc \ - unittest/TestTree.cc \ - unittest/TestTreeCombine.cc \ - unittest/TestTreeGetSetValues.cc \ - unittest/TestTreeIterators.cc \ - unittest/TestTreeVisitor.cc \ - unittest/TestValueAccessor.cc \ - unittest/TestVec2Metadata.cc \ - unittest/TestVec3Metadata.cc \ - unittest/TestVolumeRayIntersector.cc \ - unittest/TestVolumeToMesh.cc \ -# - -DOC_FILES := doc/doc.txt doc/faq.txt doc/changes.txt doc/codingstyle.txt doc/examplecode.txt doc/api_0_98_0.txt doc/math.txt doc/python.txt -DOC_INDEX := doc/html/index.html -DOC_PDF := doc/latex/refman.pdf - -LIBVIEWER_INCLUDE_NAMES := \ - viewer/Camera.h \ - viewer/ClipBox.h \ - viewer/Font.h \ - viewer/RenderModules.h \ - viewer/Viewer.h \ -# -# Used for "install" target only -LIBVIEWER_PUBLIC_INCLUDE_NAMES := \ - viewer/Viewer.h \ -# -LIBVIEWER_SRC_NAMES := \ - viewer/Camera.cc \ - viewer/ClipBox.cc \ - viewer/Font.cc \ - viewer/RenderModules.cc \ - viewer/Viewer.cc \ -# -ifdef MBSD - LIBVIEWER_FLAGS := -framework Cocoa -framework OpenGL -framework IOKit -else - LIBVIEWER_FLAGS := -lGL -lGLU -endif - - -CMD_INCLUDE_NAMES := \ -# - -CMD_SRC_NAMES := \ - cmd/openvdb_print/main.cc \ - cmd/openvdb_render/main.cc \ - cmd/openvdb_view/main.cc \ -# - - -PYTHON_INCLUDE_NAMES := \ - python/pyopenvdb.h \ - python/pyutil.h \ - python/pyAccessor.h \ - python/pyGrid.h \ -# -# Used for "install" target only -PYTHON_PUBLIC_INCLUDE_NAMES := \ - python/pyopenvdb.h \ -# -PYTHON_SRC_NAMES := \ - python/pyFloatGrid.cc \ - python/pyIntGrid.cc \ - python/pyMetadata.cc \ - python/pyOpenVDBModule.cc \ - python/pyTransform.cc \ - python/pyVec3Grid.cc \ -# -PYCXXFLAGS := -fPIC -isystem python -isystem $(PYTHON_INCL_DIR) -isystem $(PYCONFIG_INCL_DIR) -ifneq (,$(strip $(NUMPY_INCL_DIR))) -PYCXXFLAGS += -isystem $(NUMPY_INCL_DIR) -DPY_OPENVDB_USE_NUMPY -endif -ifneq (no,$(strip $(PYTHON_WRAP_ALL_GRID_TYPES))) -PYCXXFLAGS += -DPY_OPENVDB_WRAP_ALL_GRID_TYPES -endif - - -HEADER_SUBDIRS := $(dir $(INCLUDE_NAMES)) - -ALL_INCLUDE_FILES := \ - $(INCLUDE_NAMES) \ - $(UNITTEST_INCLUDE_NAMES) \ - $(CMD_INCLUDE_NAMES) \ - $(LIBVIEWER_INCLUDE_NAMES) \ - $(PYTHON_INCLUDE_NAMES) \ -# -SRC_FILES := \ - $(SRC_NAMES) \ - $(UNITTEST_SRC_NAMES) \ - $(CMD_SRC_NAMES) \ - $(LIBVIEWER_SRC_NAMES) \ - $(PYTHON_SRC_NAMES) \ -# -ALL_SRC_FILES := $(SRC_FILES) - -OBJ_NAMES := $(SRC_NAMES:.cc=.o) -UNITTEST_OBJ_NAMES := $(UNITTEST_SRC_NAMES:.cc=.o) -LIBVIEWER_OBJ_NAMES := $(LIBVIEWER_SRC_NAMES:.cc=.o) -PYTHON_OBJ_NAMES := $(PYTHON_SRC_NAMES:.cc=.o) - -LIB_MAJOR_VERSION=$(shell grep 'define OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER ' \ - version.h | sed 's/[^0-9]*//g') -LIB_MINOR_VERSION=$(shell grep 'define OPENVDB_LIBRARY_MINOR_VERSION_NUMBER ' \ - version.h | sed 's/[^0-9]*//g') -LIB_PATCH_VERSION=$(shell grep 'define OPENVDB_LIBRARY_PATCH_VERSION_NUMBER ' \ - version.h | sed 's/[^0-9]*//g') - -LIB_VERSION=$(LIB_MAJOR_VERSION).$(LIB_MINOR_VERSION).$(LIB_PATCH_VERSION) -SO_VERSION=$(LIB_MAJOR_VERSION).$(LIB_MINOR_VERSION) - -LIBOPENVDB_NAME=libopenvdb -LIBOPENVDB_STATIC := $(LIBOPENVDB_NAME).a -ifndef MBSD -LIBOPENVDB_SHARED_NAME := $(LIBOPENVDB_NAME).so -LIBOPENVDB_SHARED := $(LIBOPENVDB_NAME).so.$(LIB_VERSION) -LIBOPENVDB_SONAME := $(LIBOPENVDB_NAME).so.$(SO_VERSION) -LIBOPENVDB_SONAME_FLAGS := -Wl,-soname,$(LIBOPENVDB_SONAME) -else -LIBOPENVDB_SHARED_NAME := $(LIBOPENVDB_NAME).dylib -LIBOPENVDB_SHARED := $(LIBOPENVDB_NAME).$(LIB_VERSION).dylib -LIBOPENVDB_SONAME := $(LIBOPENVDB_NAME).$(SO_VERSION).dylib -LIBOPENVDB_SONAME_FLAGS := -Wl,-install_name,$(DESTDIR)/lib/$(LIBOPENVDB_SONAME) -endif - -# TODO: libopenvdb_viewer is currently built into vdb_view and is not installed separately. -LIBVIEWER_NAME=libopenvdb_viewer -LIBVIEWER_STATIC := $(LIBVIEWER_NAME).a -ifndef MBSD -LIBVIEWER_SHARED_NAME := $(LIBVIEWER_NAME).so -LIBVIEWER_SHARED := $(LIBVIEWER_NAME).so.$(LIB_VERSION) -LIBVIEWER_SONAME := $(LIBVIEWER_NAME).so.$(SO_VERSION) -LIBVIEWER_SONAME_FLAGS := -Wl,-soname,$(LIBVIEWER_SONAME) -else -LIBVIEWER_SHARED_NAME := $(LIBVIEWER_NAME).dylib -LIBVIEWER_SHARED := $(LIBVIEWER_NAME).$(LIB_VERSION).dylib -LIBVIEWER_SONAME := $(LIBVIEWER_NAME).$(SO_VERSION).dylib -LIBVIEWER_SONAME_FLAGS := -Wl,-install_name,$(DESTDIR)/lib/$(LIBVIEWER_SONAME) -endif - -PYTHON_MODULE_NAME=pyopenvdb -PYTHON_MODULE := $(PYTHON_MODULE_NAME).so -PYTHON_SONAME := $(PYTHON_MODULE_NAME).so.$(SO_VERSION) -ifndef MBSD -PYTHON_SONAME_FLAGS := -Wl,-soname,$(PYTHON_SONAME) -endif - -ifeq (no,$(strip $(shared))) - LIBOPENVDB := $(LIBOPENVDB_STATIC) - LIBVIEWER := $(LIBVIEWER_STATIC) -else - LIBOPENVDB := $(LIBOPENVDB_SHARED) - LIBVIEWER := $(LIBVIEWER_SHARED) - LIBOPENVDB_RPATH := -Wl,-rpath,$(DESTDIR)/lib -endif # shared - -DEPEND := dependencies - -# Get the list of dependencies that are newer than the current target, -# but limit the list to at most three entries. -list_deps = $(if $(wordlist 4,5,$(?F)),$(firstword $(?F)) and others,$(wordlist 1,3,$(?F))) - -ALL_PRODUCTS := \ - $(LIBOPENVDB) \ - vdb_test \ - vdb_print \ - vdb_render \ - vdb_view \ - $(DEPEND) \ - $(LIBOPENVDB_SHARED_NAME) \ - $(LIBOPENVDB_SONAME) \ - $(PYTHON_MODULE) \ -# - -.SUFFIXES: .o .cc - -.PHONY: all clean depend doc install lib pdfdoc pydoc pytest python test viewerlib - -.cc.o: - @echo "Building $@ because of $(call list_deps)" - $(CXX) -c $(CXXFLAGS) -fPIC -o $@ $< - -all: lib python vdb_print vdb_render vdb_test depend - -$(OBJ_NAMES): %.o: %.cc - @echo "Building $@ because of $(call list_deps)" - $(CXX) -c -DOPENVDB_PRIVATE $(CXXFLAGS) -fPIC -o $@ $< - -ifneq (no,$(strip $(shared))) - -# Build shared library -lib: $(LIBOPENVDB_SHARED_NAME) $(LIBOPENVDB_SONAME) - -$(LIBOPENVDB_SHARED_NAME): $(LIBOPENVDB_SHARED) - ln -f -s $< $@ - -$(LIBOPENVDB_SONAME): $(LIBOPENVDB_SHARED) - ln -f -s $< $@ - -$(LIBOPENVDB_SHARED): $(OBJ_NAMES) - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) -shared -o $@ $^ $(LIBS_RPATH) $(LIBOPENVDB_SONAME_FLAGS) - -else - -# Build static library -lib: $(LIBOPENVDB) - -$(LIBOPENVDB_STATIC): $(OBJ_NAMES) - @echo "Building $@ because of $(list_deps)" - $(AR) cr $@ $^ - -endif # shared - - -$(DOC_INDEX): doxygen-config $(INCLUDE_NAMES) $(SRC_NAMES) $(DOC_FILES) - @echo "Generating documentation because of $(list_deps)" - echo 'OUTPUT_DIRECTORY=./doc' | cat doxygen-config - | $(DOXYGEN) - $(QUIET) - -$(DOC_PDF): doxygen-config $(INCLUDE_NAMES) $(SRC_NAMES) $(DOC_FILES) - @echo "Generating documentation because of $(list_deps)" - echo -e 'OUTPUT_DIRECTORY=./doc\nGENERATE_LATEX=YES\nGENERATE_HTML=NO' \ - | cat doxygen-config - | $(DOXYGEN) - $(QUIET) \ - && cd ./doc/latex && make refman.pdf $(QUIET) \ - && echo 'Created doc/latex/refman.pdf' - -ifneq (,$(strip $(DOXYGEN))) -doc: $(DOC_INDEX) -pdfdoc: $(DOC_PDF) -else -doc: - @echo "$@"': $$DOXYGEN is undefined' -pdfdoc: - @echo "$@"': $$DOXYGEN is undefined' -endif - -vdb_print: $(LIBOPENVDB) cmd/openvdb_print/main.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) -o $@ cmd/openvdb_print/main.cc -I . \ - $(LIBOPENVDB_RPATH) -L$(CURDIR) $(LIBOPENVDB) \ - $(LIBS_RPATH) $(CONCURRENT_MALLOC_LIB) - -vdb_render: $(LIBOPENVDB) cmd/openvdb_render/main.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) -o $@ cmd/openvdb_render/main.cc -I . \ - -isystem $(EXR_INCL_DIR) -isystem $(ILMBASE_INCL_DIR) \ - -Wl,-rpath,$(EXR_LIB_DIR) -L$(EXR_LIB_DIR) $(EXR_LIB) \ - -Wl,-rpath,$(ILMBASE_LIB_DIR) -L$(ILMBASE_LIB_DIR) $(ILMBASE_LIB) \ - $(LIBOPENVDB_RPATH) -L$(CURDIR) $(LIBOPENVDB) \ - $(LIBS_RPATH) $(CONCURRENT_MALLOC_LIB) - -# Create an openvdb_viewer/ symlink to the viewer/ subdirectory, -# to mirror the DWA directory structure. -openvdb_viewer: - ln -f -s viewer openvdb_viewer - -ifneq (yes,$(has_glfw)) -vdb_view: - @echo "$@"': GLFW is unavailable' -else -$(LIBVIEWER_INCLUDE_NAMES): openvdb_viewer - -$(LIBVIEWER_OBJ_NAMES): $(LIBVIEWER_INCLUDE_NAMES) -$(LIBVIEWER_OBJ_NAMES): %.o: %.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) -c $(CXXFLAGS) -I . -isystem $(GLFW_INCL_DIR) -DGL_GLEXT_PROTOTYPES=1 -fPIC -o $@ $< - -vdb_view: $(LIBOPENVDB) $(LIBVIEWER_OBJ_NAMES) cmd/openvdb_view/main.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) -o $@ cmd/openvdb_view/main.cc $(LIBVIEWER_OBJ_NAMES) \ - -I . -Wl,-rpath,$(GLFW_LIB_DIR) -L$(GLFW_LIB_DIR) $(GLFW_LIB) \ - $(LIBOPENVDB_RPATH) -L$(CURDIR) $(LIBOPENVDB) \ - $(LIBVIEWER_FLAGS) $(LIBS_RPATH) $(BOOST_THREAD_LIB) $(CONCURRENT_MALLOC_LIB) -endif - - -# Build the Python module -$(PYTHON_OBJ_NAMES): $(PYTHON_INCLUDE_NAMES) -$(PYTHON_OBJ_NAMES): %.o: %.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) -c $(CXXFLAGS) -I . $(PYCXXFLAGS) -o $@ $< -$(PYTHON_MODULE): $(LIBOPENVDB) $(PYTHON_OBJ_NAMES) - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) $(PYCXXFLAGS) -shared $(PYTHON_SONAME_FLAGS) -o $@ $(PYTHON_OBJ_NAMES) \ - -Wl,-rpath,$(PYTHON_LIB_DIR) -L$(PYTHON_LIB_DIR) $(PYTHON_LIB) \ - -Wl,-rpath,$(BOOST_PYTHON_LIB_DIR) -L$(BOOST_PYTHON_LIB_DIR) $(BOOST_PYTHON_LIB) \ - $(LIBOPENVDB_RPATH) -L$(CURDIR) $(LIBOPENVDB) \ - $(LIBS_RPATH) $(CONCURRENT_MALLOC_LIB) - -ifeq (yes,$(has_python)) -ifneq (,$(strip $(EPYDOC))) -pydoc: $(PYTHON_MODULE) $(LIBOPENVDB_SONAME) - @echo "Generating Python module documentation because of $(list_deps)" - pydocdir=doc/html/python; \ - mkdir -p $${pydocdir}; \ - echo "Created $${pydocdir}"; \ - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(CURDIR); \ - export PYTHONPATH=${PYTHONPATH}:$(CURDIR); \ - $(EPYDOC) --html -o $${pydocdir} $(PYTHON_MODULE_NAME) $(QUIET) -else -pydoc: - @echo "$@"': $$EPYDOC is undefined' -endif - -pytest: $(PYTHON_MODULE) $(LIBOPENVDB_SONAME) - @echo "Testing Python module $(PYTHON_MODULE)" - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(CURDIR); \ - export PYTHONPATH=${PYTHONPATH}:$(CURDIR); \ - python$(PYTHON_VERSION) ./python/test/TestOpenVDB.py $(QUIET_TEST) - -python: $(PYTHON_MODULE) -else -python pytest pydoc: - @echo "$@"': Python is unavailable' -endif - - -$(UNITTEST_OBJ_NAMES): %.o: %.cc - @echo "Building $@ because of $(list_deps)" - $(CXX) -c $(CXXFLAGS) -isystem $(CPPUNIT_INCL_DIR) -fPIC -o $@ $< - -ifneq (,$(strip $(CPPUNIT_INCL_DIR))) -vdb_test: $(LIBOPENVDB) $(UNITTEST_OBJ_NAMES) - @echo "Building $@ because of $(list_deps)" - $(CXX) $(CXXFLAGS) -o $@ $(UNITTEST_OBJ_NAMES) \ - -Wl,-rpath,$(CPPUNIT_LIB_DIR) -L$(CPPUNIT_LIB_DIR) $(CPPUNIT_LIB) \ - $(LIBOPENVDB_RPATH) -L$(CURDIR) $(LIBOPENVDB) \ - $(LIBS_RPATH) $(CONCURRENT_MALLOC_LIB) - -test: lib vdb_test - @echo "Testing $(LIBOPENVDB_NAME)" - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(CURDIR); ./vdb_test $(QUIET_TEST) -else -vdb_test: - @echo "$@"': $$(CPPUNIT_INCL_DIR) is undefined' -test: - @echo "$@"': $$(CPPUNIT_INCL_DIR) is undefined' -endif - -install: lib python vdb_print vdb_render vdb_view doc pydoc - mkdir -p $(DESTDIR)/include/openvdb - @echo "Created $(DESTDIR)/include/openvdb" - pushd $(DESTDIR)/include/openvdb > /dev/null; \ - mkdir -p $(HEADER_SUBDIRS); popd > /dev/null - for f in $(INCLUDE_NAMES); \ - do cp -f $$f $(DESTDIR)/include/openvdb/$$f; done - @# - if [ -f $(LIBVIEWER) ]; \ - then \ - mkdir -p $(DESTDIR)/include/openvdb_viewer; \ - echo "Created $(DESTDIR)/include/openvdb_viewer"; \ - cp -f $(LIBVIEWER_PUBLIC_INCLUDE_NAMES) $(DESTDIR)/include/openvdb_viewer/; \ - fi - @echo "Copied header files to $(DESTDIR)/include" - @# - mkdir -p $(DESTDIR)/lib - @echo "Created $(DESTDIR)/lib/" - cp -f $(LIBOPENVDB) $(DESTDIR)/lib - pushd $(DESTDIR)/lib > /dev/null; \ - if [ -f $(LIBOPENVDB_SHARED) ]; then \ - ln -f -s $(LIBOPENVDB_SHARED) $(LIBOPENVDB_SHARED_NAME); \ - ln -f -s $(LIBOPENVDB_SHARED) $(LIBOPENVDB_SONAME); \ - fi; \ - popd > /dev/null - @echo "Copied libopenvdb to $(DESTDIR)/lib/" - @# - if [ -f $(LIBVIEWER) ]; \ - then \ - cp -f $(LIBVIEWER) $(DESTDIR)/lib; \ - pushd $(DESTDIR)/lib > /dev/null; \ - if [ -f $(LIBVIEWER_SHARED) ]; then \ - ln -f -s $(LIBVIEWER_SHARED) $(LIBVIEWER_SHARED_NAME); fi; \ - popd > /dev/null; \ - echo "Copied libopenvdb_viewer to $(DESTDIR)/lib/"; \ - fi - @# - if [ -f $(PYTHON_MODULE) ]; \ - then \ - installdir=$(DESTDIR)/python/include/python$(PYTHON_VERSION); \ - mkdir -p $${installdir}; \ - echo "Created $${installdir}"; \ - cp -f $(PYTHON_PUBLIC_INCLUDE_NAMES) $${installdir}/; \ - echo "Copied Python header files to $${installdir}"; \ - installdir=$(DESTDIR)/python/lib/python$(PYTHON_VERSION); \ - mkdir -p $${installdir}; \ - echo "Created $${installdir}"; \ - cp -f $(PYTHON_MODULE) $${installdir}/; \ - pushd $${installdir} > /dev/null; \ - ln -f -s $(PYTHON_MODULE) $(PYTHON_SONAME); \ - popd > /dev/null; \ - echo "Copied Python module to $${installdir}"; \ - fi - @# - mkdir -p $(DESTDIR)/bin - @echo "Created $(DESTDIR)/bin/" - cp -f vdb_print $(DESTDIR)/bin - @echo "Copied vdb_print to $(DESTDIR)/bin/" - cp -f vdb_render $(DESTDIR)/bin - @echo "Copied vdb_render to $(DESTDIR)/bin/" - if [ -f vdb_view ]; \ - then \ - cp -f vdb_view $(DESTDIR)/bin; \ - echo "Copied vdb_view to $(DESTDIR)/bin/"; \ - fi - @# - if [ -d doc/html ]; \ - then \ - mkdir -p $(DESTDIR)/share/doc/openvdb; \ - echo "Created $(DESTDIR)/share/doc/openvdb/"; \ - cp -r -f doc/html $(DESTDIR)/share/doc/openvdb; \ - echo "Copied documentation to $(DESTDIR)/share/doc/openvdb/"; \ - fi - -# TODO: This accumulates all source file dependencies into a single file -# containing a rule for each *.o file. Consider generating a separate -# dependency file for each *.o file instead. -$(DEPEND): $(ALL_INCLUDE_FILES) $(ALL_SRC_FILES) openvdb_viewer - @echo "Generating dependencies because of $(list_deps)" - $(RM) $(DEPEND) - for f in $(SRC_NAMES) $(CMD_SRC_NAMES); \ - do $(CXX) $(CXXFLAGS) -O0 \ - -MM $$f -MT `echo $$f | sed 's%\.[^.]*%.o%'` >> $(DEPEND); \ - done - if [ -d "$(CPPUNIT_INCL_DIR)" ]; \ - then \ - for f in $(UNITTEST_SRC_NAMES); \ - do $(CXX) $(CXXFLAGS) -O0 \ - -MM $$f -MT `echo $$f | sed 's%\.[^.]*%.o%'` \ - -isystem $(CPPUNIT_INCL_DIR) >> $(DEPEND); \ - done; \ - fi - -depend: $(DEPEND) - -clean: - $(RM) $(OBJ_NAMES) $(ALL_PRODUCTS) $(DEPEND) - $(RM) $(LIBOPENVDB_STATIC) - $(RM) $(LIBOPENVDB_SHARED) - $(RM) $(LIBVIEWER_OBJ_NAMES) - $(RM) $(PYTHON_OBJ_NAMES) - $(RM) $(UNITTEST_OBJ_NAMES) - $(RM) -r ./doc/html ./doc/latex - -ifneq (,$(strip $(wildcard $(DEPEND)))) - include $(DEPEND) -endif - -# Copyright (c) 2012-2014 DreamWorks Animation LLC -# All rights reserved. This software is distributed under the -# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/Metadata.h b/openvdb_3_0_0_library/Metadata.h deleted file mode 100755 index 7f7889c..0000000 --- a/openvdb_3_0_0_library/Metadata.h +++ /dev/null @@ -1,41 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_METADATA_HAS_BEEN_INCLUDED -#define OPENVDB_METADATA_HAS_BEEN_INCLUDED - -#include -#include - -#endif // OPENVDB_METADATA_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/Platform.cc b/openvdb_3_0_0_library/Platform.cc deleted file mode 100755 index e79ac20..0000000 --- a/openvdb_3_0_0_library/Platform.cc +++ /dev/null @@ -1,38 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -// For Windows, we need these includes to ensure all OPENVDB_API -// functions/classes are compiled into the shared library. -#include "openvdb.h" -#include "Exceptions.h" - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/Platform.h b/openvdb_3_0_0_library/Platform.h deleted file mode 100755 index 3e89ebe..0000000 --- a/openvdb_3_0_0_library/Platform.h +++ /dev/null @@ -1,202 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file Platform.h - -#ifndef OPENVDB_PLATFORM_HAS_BEEN_INCLUDED -#define OPENVDB_PLATFORM_HAS_BEEN_INCLUDED - -#include "PlatformConfig.h" - -/// Use OPENVDB_DEPRECATED to mark functions as deprecated. -/// It should be placed right before the signature of the function, -/// e.g., "OPENVDB_DEPRECATED void functionName();". -#ifdef OPENVDB_DEPRECATED -#undef OPENVDB_DEPRECATED -#endif -#ifdef _MSC_VER - #define OPENVDB_DEPRECATED __declspec(deprecated) -#else - #define OPENVDB_DEPRECATED __attribute__ ((deprecated)) -#endif - -/// Macro for determining if GCC version is >= than X.Y -#if defined(__GNUC__) - #define OPENVDB_CHECK_GCC(MAJOR, MINOR) \ - (__GNUC__ > MAJOR || (__GNUC__ == MAJOR && __GNUC_MINOR__ >= MINOR)) -#else - #define OPENVDB_CHECK_GCC(MAJOR, MINOR) 0 -#endif - -/// Macro for determining if there are sufficient C++0x/C++11 features -#ifdef __INTEL_COMPILER - #ifdef __INTEL_CXX11_MODE__ - #define OPENVDB_HAS_CXX11 1 - #endif -#elif defined(__clang__) - #ifndef _LIBCPP_VERSION - #include - #endif - #ifdef _LIBCPP_VERSION - #define OPENVDB_HAS_CXX11 1 - #endif -#elif defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus > 199711L) - #define OPENVDB_HAS_CXX11 1 -#elif defined(_MSC_VER) - #if (_MSC_VER >= 1700) - #define OPENVDB_HAS_CXX11 1 - #endif -#endif -#if defined(__GNUC__) && !OPENVDB_CHECK_GCC(4, 4) - // ICC uses GCC's standard library headers, so even if the ICC version - // is recent enough for C++11, the GCC version might not be. - #undef OPENVDB_HAS_CXX11 -#endif - -/// For compilers that need templated function specializations to have -/// storage qualifiers, we need to declare the specializations as static inline. -/// Otherwise, we'll get linker errors about multiply defined symbols. -#if defined(__GNUC__) && OPENVDB_CHECK_GCC(4, 4) - #define OPENVDB_STATIC_SPECIALIZATION -#else - #define OPENVDB_STATIC_SPECIALIZATION static -#endif - - -/// Bracket code with OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN/_END, -/// as in the following example, to inhibit ICC remarks about unreachable code: -/// @code -/// template -/// void processNode(NodeType& node) -/// { -/// OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN -/// if (NodeType::LEVEL == 0) return; // ignore leaf nodes -/// int i = 0; -/// ... -/// OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -/// } -/// @endcode -/// In the above, NodeType::LEVEL == 0 is a compile-time constant expression, -/// so for some template instantiations, the line below it is unreachable. -#if defined(__INTEL_COMPILER) - // Disable ICC remarks 111 ("statement is unreachable"), 128 ("loop is not reachable"), - // 185 ("dynamic initialization in unreachable code"), and 280 ("selector expression - // is constant"). - #define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN \ - _Pragma("warning (push)") \ - _Pragma("warning (disable:111)") \ - _Pragma("warning (disable:128)") \ - _Pragma("warning (disable:185)") \ - _Pragma("warning (disable:280)") - #define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END \ - _Pragma("warning (pop)") -#else - #define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - #define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -#endif - - -/// Visual C++ does not have constants like M_PI unless this is defined. -/// @note This is needed even though the core library is built with this but -/// hcustom 12.1 doesn't define it. So this is needed for HDK operators. -#ifndef _USE_MATH_DEFINES - #define _USE_MATH_DEFINES -#endif - -/// Visual C++ does not have round -#ifdef _MSC_VER - #include - using boost::math::round; -#endif - -/// Visual C++ uses _copysign() instead of copysign() -#ifdef _MSC_VER - #include - static inline double copysign(double x, double y) { return _copysign(x, y); } -#endif - -/// Visual C++ does not have stdint.h which defines types like uint64_t. -/// So for portability we instead include boost/cstdint.hpp. -#include -using boost::int8_t; -using boost::int16_t; -using boost::int32_t; -using boost::int64_t; -using boost::uint8_t; -using boost::uint16_t; -using boost::uint32_t; -using boost::uint64_t; - -/// Helper macros for defining library symbol visibility -#ifdef OPENVDB_EXPORT -#undef OPENVDB_EXPORT -#endif -#ifdef OPENVDB_IMPORT -#undef OPENVDB_IMPORT -#endif -#ifdef __GNUC__ - #define OPENVDB_EXPORT __attribute__((visibility("default"))) - #define OPENVDB_IMPORT __attribute__((visibility("default"))) -#endif -#ifdef _WIN32 - #ifdef OPENVDB_DLL - #define OPENVDB_EXPORT __declspec(dllexport) - #define OPENVDB_IMPORT __declspec(dllimport) - #else - #define OPENVDB_EXPORT - #define OPENVDB_IMPORT - #endif -#endif - -/// All classes and public free standing functions must be explicitly marked -/// as \_API to be exported. The \_PRIVATE macros are defined when -/// building that particular library. -#ifdef OPENVDB_API -#undef OPENVDB_API -#endif -#ifdef OPENVDB_PRIVATE - #define OPENVDB_API OPENVDB_EXPORT -#else - #define OPENVDB_API OPENVDB_IMPORT -#endif -#ifdef OPENVDB_HOUDINI_API -#undef OPENVDB_HOUDINI_API -#endif -#ifdef OPENVDB_HOUDINI_PRIVATE - #define OPENVDB_HOUDINI_API OPENVDB_EXPORT -#else - #define OPENVDB_HOUDINI_API OPENVDB_IMPORT -#endif - -#endif // OPENVDB_PLATFORM_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/PlatformConfig.h b/openvdb_3_0_0_library/PlatformConfig.h deleted file mode 100755 index bb7b7e7..0000000 --- a/openvdb_3_0_0_library/PlatformConfig.h +++ /dev/null @@ -1,57 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file PlatformConfig.h - -#ifndef OPENVDB_PLATFORMCONFIG_HAS_BEEN_INCLUDED -#define OPENVDB_PLATFORMCONFIG_HAS_BEEN_INCLUDED - -// Windows specific configuration -#ifdef _WIN32 - - // By default, assume we're building OpenVDB as a DLL if we're dynamically - // linking in the CRT, unless OPENVDB_STATICLIB is defined. - #if defined(_DLL) && !defined(OPENVDB_STATICLIB) && !defined(OPENVDB_DLL) - #define OPENVDB_DLL - #endif - - // By default, assume that we're dynamically linking OpenEXR, unless - // OPENVDB_OPENEXR_STATICLIB is defined. - #if !defined(OPENVDB_OPENEXR_STATICLIB) && !defined(OPENEXR_DLL) - #define OPENEXR_DLL - #endif - -#endif // _WIN32 - -#endif // OPENVDB_PLATFORMCONFIG_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/README b/openvdb_3_0_0_library/README deleted file mode 100755 index 4450746..0000000 --- a/openvdb_3_0_0_library/README +++ /dev/null @@ -1,16 +0,0 @@ -======================================================================== - OpenVDB -======================================================================== - -The OpenVDB library comprises a hierarchical data structure and a suite -of tools for the efficient manipulation of sparse, possibly time-varying, -volumetric data discretized on a three-dimensional grid. - -For instructions on library installation and dependencies see INSTALL - -For documentation of the library and code examples see: -www.openvdb.org/documentation/doxygen - -For more details visit the project's home page: -www.openvdb.org - diff --git a/openvdb_3_0_0_library/Types.h b/openvdb_3_0_0_library/Types.h deleted file mode 100755 index f759334..0000000 --- a/openvdb_3_0_0_library/Types.h +++ /dev/null @@ -1,486 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TYPES_HAS_BEEN_INCLUDED -#define OPENVDB_TYPES_HAS_BEEN_INCLUDED - -#include "version.h" -#include "Platform.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -// One-dimensional scalar types -typedef uint32_t Index32; -typedef uint64_t Index64; -typedef Index32 Index; -typedef int16_t Int16; -typedef int32_t Int32; -typedef int64_t Int64; -typedef Int32 Int; -typedef unsigned char Byte; -typedef double Real; - -// Two-dimensional vector types -typedef math::Vec2 Vec2R; -typedef math::Vec2 Vec2I; -typedef math::Vec2 Vec2f; -typedef math::Vec2 Vec2H; -using math::Vec2i; -using math::Vec2s; -using math::Vec2d; - -// Three-dimensional vector types -typedef math::Vec3 Vec3R; -typedef math::Vec3 Vec3I; -typedef math::Vec3 Vec3f; -typedef math::Vec3 Vec3H; -using math::Vec3i; -using math::Vec3s; -using math::Vec3d; - -using math::Coord; -using math::CoordBBox; -typedef math::BBox BBoxd; - -// Four-dimensional vector types -typedef math::Vec4 Vec4R; -typedef math::Vec4 Vec4I; -typedef math::Vec4 Vec4f; -typedef math::Vec4 Vec4H; -using math::Vec4i; -using math::Vec4s; -using math::Vec4d; - -// Three-dimensional matrix types -typedef math::Mat3 Mat3R; - -// Four-dimensional matrix types -typedef math::Mat4 Mat4R; -typedef math::Mat4 Mat4d; -typedef math::Mat4 Mat4s; - -// Compressed Hermite data -typedef math::Hermite Hermite; - -// Quaternions -typedef math::Quat QuatR; - - -//////////////////////////////////////// - - -/// @brief Integer wrapper, required to distinguish PointIndexGrid and -/// PointDataGrid from Int32Grid and Int64Grid -/// @note @c Kind is a dummy parameter used to create distinct types. -template -struct PointIndex -{ - BOOST_STATIC_ASSERT(boost::is_integral::value); - - typedef IntType_ IntType; - - PointIndex(IntType i = IntType(0)): mIndex(i) {} - - operator IntType() const { return mIndex; } - - /// Needed to support the (zeroVal() + val) idiom. - template - PointIndex operator+(T x) { return PointIndex(mIndex + IntType(x)); } - -private: - IntType mIndex; -}; - - -typedef PointIndex PointIndex32; -typedef PointIndex PointIndex64; - -typedef PointIndex PointDataIndex32; -typedef PointIndex PointDataIndex64; - - -//////////////////////////////////////// - - -template struct VecTraits { - static const bool IsVec = false; - static const int Size = 1; - typedef T ElementType; -}; -template struct VecTraits > { - static const bool IsVec = true; - static const int Size = 2; - typedef T ElementType; -}; -template struct VecTraits > { - static const bool IsVec = true; - static const int Size = 3; - typedef T ElementType; -}; -template struct VecTraits > { - static const bool IsVec = true; - static const int Size = 4; - typedef T ElementType; -}; - - -//////////////////////////////////////// - - -/// @brief CanConvertType::value is @c true if a value -/// of type @a ToType can be constructed from a value of type @a FromType. -/// -/// @note @c boost::is_convertible tests for implicit convertibility only. -/// What we want is the equivalent of C++11's @c std::is_constructible, -/// which allows for explicit conversions as well. Unfortunately, not all -/// compilers support @c std::is_constructible yet, so for now, types that -/// can only be converted explicitly have to be indicated with specializations -/// of this template. -template -struct CanConvertType { enum { value = boost::is_convertible::value }; }; - -// Specializations for vector types, which can be constructed from values -// of their own ValueTypes (or values that can be converted to their ValueTypes), -// but only explicitly -template struct CanConvertType > { enum { value = true }; }; -template struct CanConvertType > { enum { value = true }; }; -template struct CanConvertType > { enum { value = true }; }; -template struct CanConvertType, math::Vec2 > { enum {value = true}; }; -template struct CanConvertType, math::Vec3 > { enum {value = true}; }; -template struct CanConvertType, math::Vec4 > { enum {value = true}; }; -template -struct CanConvertType > { enum { value = CanConvertType::value }; }; -template -struct CanConvertType > { enum { value = CanConvertType::value }; }; -template -struct CanConvertType > { enum { value = CanConvertType::value }; }; -template<> struct CanConvertType { enum {value = true}; }; -template<> struct CanConvertType { enum {value = true}; }; - -//////////////////////////////////////// - - -// Add new items to the *end* of this list, and update NUM_GRID_CLASSES. -enum GridClass { - GRID_UNKNOWN = 0, - GRID_LEVEL_SET, - GRID_FOG_VOLUME, - GRID_STAGGERED -}; -enum { NUM_GRID_CLASSES = GRID_STAGGERED + 1 }; - -static const Real LEVEL_SET_HALF_WIDTH = 3; - -/// The type of a vector determines how transforms are applied to it: -///
-///
Invariant -///
Does not transform (e.g., tuple, uvw, color) -/// -///
Covariant -///
Apply inverse-transpose transformation: @e w = 0, ignores translation -/// (e.g., gradient/normal) -/// -///
Covariant Normalize -///
Apply inverse-transpose transformation: @e w = 0, ignores translation, -/// vectors are renormalized (e.g., unit normal) -/// -///
Contravariant Relative -///
Apply "regular" transformation: @e w = 0, ignores translation -/// (e.g., displacement, velocity, acceleration) -/// -///
Contravariant Absolute -///
Apply "regular" transformation: @e w = 1, vector translates (e.g., position) -///
-enum VecType { - VEC_INVARIANT = 0, - VEC_COVARIANT, - VEC_COVARIANT_NORMALIZE, - VEC_CONTRAVARIANT_RELATIVE, - VEC_CONTRAVARIANT_ABSOLUTE -}; -enum { NUM_VEC_TYPES = VEC_CONTRAVARIANT_ABSOLUTE + 1 }; - - -/// Specify how grids should be merged during certain (typically multithreaded) operations. -///
-///
MERGE_ACTIVE_STATES -///
The output grid is active wherever any of the input grids is active. -/// -///
MERGE_NODES -///
The output grid's tree has a node wherever any of the input grids' trees -/// has a node, regardless of any active states. -/// -///
MERGE_ACTIVE_STATES_AND_NODES -///
The output grid is active wherever any of the input grids is active, -/// and its tree has a node wherever any of the input grids' trees has a node. -///
-enum MergePolicy { - MERGE_ACTIVE_STATES = 0, - MERGE_NODES, - MERGE_ACTIVE_STATES_AND_NODES -}; - - -//////////////////////////////////////// - - -template const char* typeNameAsString() { return typeid(T).name(); } -template<> inline const char* typeNameAsString() { return "bool"; } -template<> inline const char* typeNameAsString() { return "float"; } -template<> inline const char* typeNameAsString() { return "double"; } -template<> inline const char* typeNameAsString() { return "int32"; } -template<> inline const char* typeNameAsString() { return "uint32"; } -template<> inline const char* typeNameAsString() { return "int64"; } -template<> inline const char* typeNameAsString() { return "Hermite"; } -template<> inline const char* typeNameAsString() { return "vec2i"; } -template<> inline const char* typeNameAsString() { return "vec2s"; } -template<> inline const char* typeNameAsString() { return "vec2d"; } -template<> inline const char* typeNameAsString() { return "vec3i"; } -template<> inline const char* typeNameAsString() { return "vec3s"; } -template<> inline const char* typeNameAsString() { return "vec3d"; } -template<> inline const char* typeNameAsString() { return "string"; } -template<> inline const char* typeNameAsString() { return "mat4s"; } -template<> inline const char* typeNameAsString() { return "mat4d"; } -template<> inline const char* typeNameAsString() { return "ptidx32"; } -template<> inline const char* typeNameAsString() { return "ptidx64"; } -template<> inline const char* typeNameAsString() { return "ptdataidx32"; } -template<> inline const char* typeNameAsString() { return "ptdataidx64"; } - - -//////////////////////////////////////// - - -/// @brief This struct collects both input and output arguments to "grid combiner" functors -/// used with the tree::TypedGrid::combineExtended() and combine2Extended() methods. -/// AValueType and BValueType are the value types of the two grids being combined. -/// -/// @see openvdb/tree/Tree.h for usage information. -/// -/// Setter methods return references to this object, to facilitate the following usage: -/// @code -/// CombineArgs args; -/// myCombineOp(args.setARef(aVal).setBRef(bVal).setAIsActive(true).setBIsActive(false)); -/// @endcode -template -class CombineArgs -{ -public: - typedef AValueType AValueT; - typedef BValueType BValueT; - - CombineArgs(): - mAValPtr(NULL), mBValPtr(NULL), mResultValPtr(&mResultVal), - mAIsActive(false), mBIsActive(false), mResultIsActive(false) - {} - - /// Use this constructor when the result value is stored externally. - CombineArgs(const AValueType& a, const BValueType& b, AValueType& result, - bool aOn = false, bool bOn = false): - mAValPtr(&a), mBValPtr(&b), mResultValPtr(&result), - mAIsActive(aOn), mBIsActive(bOn) - { updateResultActive(); } - - /// Use this constructor when the result value should be stored in this struct. - CombineArgs(const AValueType& a, const BValueType& b, bool aOn = false, bool bOn = false): - mAValPtr(&a), mBValPtr(&b), mResultValPtr(&mResultVal), - mAIsActive(aOn), mBIsActive(bOn) - { updateResultActive(); } - - /// Get the A input value. - const AValueType& a() const { return *mAValPtr; } - /// Get the B input value. - const BValueType& b() const { return *mBValPtr; } - //@{ - /// Get the output value. - const AValueType& result() const { return *mResultValPtr; } - AValueType& result() { return *mResultValPtr; } - //@} - - /// Set the output value. - CombineArgs& setResult(const AValueType& val) { *mResultValPtr = val; return *this; } - - /// Redirect the A value to a new external source. - CombineArgs& setARef(const AValueType& a) { mAValPtr = &a; return *this; } - /// Redirect the B value to a new external source. - CombineArgs& setBRef(const BValueType& b) { mBValPtr = &b; return *this; } - /// Redirect the result value to a new external destination. - CombineArgs& setResultRef(AValueType& val) { mResultValPtr = &val; return *this; } - - /// @return true if the A value is active - bool aIsActive() const { return mAIsActive; } - /// @return true if the B value is active - bool bIsActive() const { return mBIsActive; } - /// @return true if the output value is active - bool resultIsActive() const { return mResultIsActive; } - - /// Set the active state of the A value. - CombineArgs& setAIsActive(bool b) { mAIsActive = b; updateResultActive(); return *this; } - /// Set the active state of the B value. - CombineArgs& setBIsActive(bool b) { mBIsActive = b; updateResultActive(); return *this; } - /// Set the active state of the output value. - CombineArgs& setResultIsActive(bool b) { mResultIsActive = b; return *this; } - -protected: - /// By default, the result value is active if either of the input values is active, - /// but this behavior can be overridden by calling setResultIsActive(). - void updateResultActive() { mResultIsActive = mAIsActive || mBIsActive; } - - const AValueType* mAValPtr; // pointer to input value from A grid - const BValueType* mBValPtr; // pointer to input value from B grid - AValueType mResultVal; // computed output value (unused if stored externally) - AValueType* mResultValPtr; // pointer to either mResultVal or an external value - bool mAIsActive, mBIsActive; // active states of A and B values - bool mResultIsActive; // computed active state (default: A active || B active) -}; - - -/// This struct adapts a "grid combiner" functor to swap the A and B grid values -/// (e.g., so that if the original functor computes a + 2 * b, the adapted functor -/// will compute b + 2 * a). -template -struct SwappedCombineOp -{ - SwappedCombineOp(CombineOp& _op): op(_op) {} - - void operator()(CombineArgs& args) - { - CombineArgs swappedArgs(args.b(), args.a(), args.result(), - args.bIsActive(), args.aIsActive()); - op(swappedArgs); - } - - CombineOp& op; -}; - - -//////////////////////////////////////// - - -/// In copy constructors, members stored as shared pointers can be handled -/// in several ways: -///
-///
CP_NEW -///
Don't copy the member; default construct a new member object instead. -/// -///
CP_SHARE -///
Copy the shared pointer, so that the original and new objects share -/// the same member. -/// -///
CP_COPY -///
Create a deep copy of the member. -///
-enum CopyPolicy { CP_NEW, CP_SHARE, CP_COPY }; - - -// Dummy class that distinguishes shallow copy constructors from -// deep copy constructors -class ShallowCopy {}; -// Dummy class that distinguishes topology copy constructors from -// deep copy constructors -class TopologyCopy {}; -// Dummy class that distinguishes constructors during file input -class PartialCreate {}; - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -#if defined(__ICC) - -// Use these defines to bracket a region of code that has safe static accesses. -// Keep the region as small as possible. -#define OPENVDB_START_THREADSAFE_STATIC_REFERENCE __pragma(warning(disable:1710)) -#define OPENVDB_FINISH_THREADSAFE_STATIC_REFERENCE __pragma(warning(default:1710)) -#define OPENVDB_START_THREADSAFE_STATIC_WRITE __pragma(warning(disable:1711)) -#define OPENVDB_FINISH_THREADSAFE_STATIC_WRITE __pragma(warning(default:1711)) -#define OPENVDB_START_THREADSAFE_STATIC_ADDRESS __pragma(warning(disable:1712)) -#define OPENVDB_FINISH_THREADSAFE_STATIC_ADDRESS __pragma(warning(default:1712)) - -// Use these defines to bracket a region of code that has unsafe static accesses. -// Keep the region as small as possible. -#define OPENVDB_START_NON_THREADSAFE_STATIC_REFERENCE __pragma(warning(disable:1710)) -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_REFERENCE __pragma(warning(default:1710)) -#define OPENVDB_START_NON_THREADSAFE_STATIC_WRITE __pragma(warning(disable:1711)) -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_WRITE __pragma(warning(default:1711)) -#define OPENVDB_START_NON_THREADSAFE_STATIC_ADDRESS __pragma(warning(disable:1712)) -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_ADDRESS __pragma(warning(default:1712)) - -// Simpler version for one-line cases -#define OPENVDB_THREADSAFE_STATIC_REFERENCE(CODE) \ - __pragma(warning(disable:1710)); CODE; __pragma(warning(default:1710)) -#define OPENVDB_THREADSAFE_STATIC_WRITE(CODE) \ - __pragma(warning(disable:1711)); CODE; __pragma(warning(default:1711)) -#define OPENVDB_THREADSAFE_STATIC_ADDRESS(CODE) \ - __pragma(warning(disable:1712)); CODE; __pragma(warning(default:1712)) - -#else // GCC does not support these compiler warnings - -#define OPENVDB_START_THREADSAFE_STATIC_REFERENCE -#define OPENVDB_FINISH_THREADSAFE_STATIC_REFERENCE -#define OPENVDB_START_THREADSAFE_STATIC_WRITE -#define OPENVDB_FINISH_THREADSAFE_STATIC_WRITE -#define OPENVDB_START_THREADSAFE_STATIC_ADDRESS -#define OPENVDB_FINISH_THREADSAFE_STATIC_ADDRESS - -#define OPENVDB_START_NON_THREADSAFE_STATIC_REFERENCE -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_REFERENCE -#define OPENVDB_START_NON_THREADSAFE_STATIC_WRITE -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_WRITE -#define OPENVDB_START_NON_THREADSAFE_STATIC_ADDRESS -#define OPENVDB_FINISH_NON_THREADSAFE_STATIC_ADDRESS - -#define OPENVDB_THREADSAFE_STATIC_REFERENCE(CODE) CODE -#define OPENVDB_THREADSAFE_STATIC_WRITE(CODE) CODE -#define OPENVDB_THREADSAFE_STATIC_ADDRESS(CODE) CODE - -#endif // defined(__ICC) - -#endif // OPENVDB_TYPES_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/cmd/openvdb_print/main.cc b/openvdb_3_0_0_library/cmd/openvdb_print/main.cc deleted file mode 100755 index 054ad49..0000000 --- a/openvdb_3_0_0_library/cmd/openvdb_print/main.cc +++ /dev/null @@ -1,337 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#ifdef DWA_OPENVDB -#include -#include -#endif - - -namespace { - -typedef std::vector StringVec; - -const char* INDENT = " "; -const char* gProgName = ""; - - -void -usage(int exitStatus = EXIT_FAILURE) -{ - std::cerr << -"Usage: " << gProgName << " in.vdb [in.vdb ...] [options]\n" << -"Which: prints information about OpenVDB grids\n" << -"Options:\n" << -" -l, -stats long printout, including grid statistics\n" << -" -m, -metadata print per-file and per-grid metadata\n"; - exit(exitStatus); -} - - -std::string -sizeAsString(openvdb::Index64 n, const std::string& units) -{ - std::ostringstream ostr; - ostr << std::setprecision(3); - if (n < 1000) { - ostr << n; - } else if (n < 1000000) { - ostr << (double(n) / 1.0e3) << "K"; - } else if (n < 1000000000) { - ostr << (double(n) / 1.0e6) << "M"; - } else { - ostr << (double(n) / 1.0e9) << "G"; - } - ostr << units; - return ostr.str(); -} - - -std::string -bytesAsString(openvdb::Index64 n) -{ - std::ostringstream ostr; - ostr << std::setprecision(3); - if (n >> 30) { - ostr << (double(n) / double(uint64_t(1) << 30)) << "GB"; - } else if (n >> 20) { - ostr << (double(n) / double(uint64_t(1) << 20)) << "MB"; - } else if (n >> 10) { - ostr << (double(n) / double(uint64_t(1) << 10)) << "KB"; - } else { - ostr << n << "B"; - } - return ostr.str(); -} - - -std::string -coordAsString(const openvdb::Coord ijk, const std::string& sep) -{ - std::ostringstream ostr; - ostr << ijk[0] << sep << ijk[1] << sep << ijk[2]; - return ostr.str(); -} - - -std::string -bkgdValueAsString(const openvdb::GridBase::ConstPtr& grid) -{ - std::ostringstream ostr; - if (grid) { - const openvdb::TreeBase& tree = grid->baseTree(); - ostr << "background: "; - openvdb::Metadata::Ptr background = tree.getBackgroundValue(); - if (background) ostr << background->str(); - } - return ostr.str(); -} - - -/// Print detailed information about the given VDB files. -/// If @a metadata is true, include file-level metadata key, value pairs. -void -printLongListing(const StringVec& filenames) -{ - bool oneFile = (filenames.size() == 1), firstFile = true; - - for (size_t i = 0, N = filenames.size(); i < N; ++i, firstFile = false) { - openvdb::io::File file(filenames[i]); - std::string version; - openvdb::GridPtrVecPtr grids; - openvdb::MetaMap::Ptr meta; - try { - file.open(); - grids = file.getGrids(); - meta = file.getMetadata(); - version = file.version(); - file.close(); - } catch (openvdb::Exception& e) { - OPENVDB_LOG_ERROR(e.what() << " (" << filenames[i] << ")"); - } - if (!grids) continue; - - if (!oneFile) { - if (!firstFile) { - std::cout << "\n" << std::string(40, '-') << "\n\n"; - } - std::cout << filenames[i] << "\n\n"; - } - - // Print file-level metadata. - std::cout << "VDB version: " << version << "\n"; - if (meta) { - std::string str = meta->str(); - if (!str.empty()) std::cout << str << "\n"; - } - std::cout << "\n"; - - // For each grid in the file... - bool firstGrid = true; - for (openvdb::GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { - if (openvdb::GridBase::ConstPtr grid = *it) { - if (!firstGrid) std::cout << "\n\n"; - std::cout << "Name: " << grid->getName() << std::endl; - grid->print(std::cout, /*verboseLevel=*/11); - firstGrid = false; - } - } - } -} - - -/// Print condensed information about the given VDB files. -/// If @a metadata is true, include file- and grid-level metadata. -void -printShortListing(const StringVec& filenames, bool metadata) -{ - bool oneFile = (filenames.size() == 1), firstFile = true; - - for (size_t i = 0, N = filenames.size(); i < N; ++i, firstFile = false) { - const std::string - indent(oneFile ? "": INDENT), - indent2(indent + INDENT); - - if (!oneFile) { - if (metadata && !firstFile) std::cout << "\n"; - std::cout << filenames[i] << ":\n"; - } - - openvdb::GridPtrVecPtr grids; - openvdb::MetaMap::Ptr meta; - - openvdb::io::File file(filenames[i]); - try { - file.open(); - grids = file.getGrids(); - meta = file.getMetadata(); - file.close(); - } catch (openvdb::Exception& e) { - OPENVDB_LOG_ERROR(e.what() << " (" << filenames[i] << ")"); - } - if (!grids) continue; - - if (metadata) { - // Print file-level metadata. - std::string str = meta->str(indent); - if (!str.empty()) std::cout << str << "\n"; - } - - // For each grid in the file... - for (openvdb::GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { - const openvdb::GridBase::ConstPtr grid = *it; - if (!grid) continue; - - // Print the grid name and its voxel value datatype. - std::cout << indent << std::left << std::setw(11) << grid->getName() - << " " << std::right << std::setw(6) << grid->valueType(); - - // Print the grid's bounding box and dimensions. - openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox(); - std::string - boxStr = coordAsString(bbox.min()," ") + " " + coordAsString(bbox.max()," "), - dimStr = coordAsString(bbox.extents(), "x"); - boxStr += std::string( - std::max(1, int(40 - boxStr.size() - dimStr.size())), ' ') + dimStr; - std::cout << " " << std::left << std::setw(40) << boxStr; - - // Print the number of active voxels. - std::cout << " " << std::right << std::setw(8) - << sizeAsString(grid->activeVoxelCount(), "Vox"); - - // Print the grid's in-core size, in bytes. - std::cout << " " << std::right << std::setw(6) << bytesAsString(grid->memUsage()); - - std::cout << std::endl; - - // Print grid-specific metadata. - if (metadata) { - // Print background value. - std::string str = bkgdValueAsString(grid); - if (!str.empty()) { - std::cout << indent2 << str << "\n"; - } - // Print local and world transforms. - grid->transform().print(std::cout, indent2); - // Print custom metadata. - str = grid->str(indent2); - if (!str.empty()) std::cout << str << "\n"; - std::cout << std::flush; - } - } - } -} - -} // unnamed namespace - - -int -main(int argc, char *argv[]) -{ -#ifdef DWA_OPENVDB - USAGETRACK_report_basic_tool_usage(argc, argv, /*duration=*/0); - logging_base::configure(argc, argv); -#endif - - OPENVDB_START_THREADSAFE_STATIC_WRITE - gProgName = argv[0]; - if (const char* ptr = ::strrchr(gProgName, '/')) gProgName = ptr + 1; - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - - int exitStatus = EXIT_SUCCESS; - - if (argc == 1) usage(); - - bool stats = false, metadata = false; - StringVec filenames; - for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - if (arg[0] == '-') { - if (arg == "-m" || arg == "-metadata") { - metadata = true; - } else if (arg == "-l" || arg == "-stats") { - stats = true; - } else if (arg == "-h" || arg == "-help" || arg == "--help") { - usage(EXIT_SUCCESS); - } else { - std::cerr << gProgName << ": \"" << arg << "\" is not a valid option\n"; - usage(); - } - } else if (!arg.empty()) { - filenames.push_back(arg); - } - } - if (filenames.empty()) { - std::cerr << gProgName << ": expected one or more OpenVDB files\n"; - usage(); - } - - try { - openvdb::initialize(); - - /// @todo Remove the following at some point: - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - openvdb::Grid::Type>::registerGrid(); - - if (stats) { - printLongListing(filenames); - } else { - printShortListing(filenames, metadata); - } - } - catch (const std::exception& e) { - OPENVDB_LOG_FATAL(e.what()); - exitStatus = EXIT_FAILURE; - } - catch (...) { - OPENVDB_LOG_FATAL("Exception caught (unexpected type)"); - std::unexpected(); - } - - return exitStatus; -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/cmd/openvdb_render/main.cc b/openvdb_3_0_0_library/cmd/openvdb_render/main.cc deleted file mode 100755 index f2d837c..0000000 --- a/openvdb_3_0_0_library/cmd/openvdb_render/main.cc +++ /dev/null @@ -1,719 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file main.cc -/// -/// @brief Simple ray tracer for OpenVDB volumes -/// -/// @note This is intended mainly as an example of how to ray-trace -/// OpenVDB volumes. It is not a production-quality renderer. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef DWA_OPENVDB -#include -#include -#endif - - -namespace { - -const char* gProgName = ""; - -const double LIGHT_DEFAULTS[] = { 0.3, 0.3, 0.0, 0.7, 0.7, 0.7 }; - - -struct RenderOpts -{ - std::string shader; - std::string color; - openvdb::Vec3SGrid::Ptr colorgrid; - std::string camera; - float aperture, focal, frame, znear, zfar; - double isovalue; - openvdb::Vec3d rotate; - openvdb::Vec3d translate; - openvdb::Vec3d target; - openvdb::Vec3d up; - bool lookat; - size_t samples; - openvdb::Vec3d absorb; - std::vector light; - openvdb::Vec3d scatter; - double cutoff, gain; - openvdb::Vec2d step; - size_t width, height; - std::string compression; - int threads; - bool verbose; - - RenderOpts(): - shader("diffuse"), - camera("perspective"), - aperture(41.2136f), - focal(50.0f), - frame(1.0f), - znear(1.0e-3f), - zfar(std::numeric_limits::max()), - isovalue(0.0), - rotate(0.0), - translate(0.0), - target(0.0), - up(0.0, 1.0, 0.0), - lookat(false), - samples(1), - absorb(0.1), - light(LIGHT_DEFAULTS, LIGHT_DEFAULTS + 6), - scatter(1.5), - cutoff(0.005), - gain(0.2), - step(1.0, 3.0), - width(1920), - height(1080), - compression("zip"), - threads(0), - verbose(false) - {} - - std::string validate() const - { - if (shader != "diffuse" && shader != "matte" && shader != "normal" && shader != "position"){ - return "expected diffuse, matte, normal or position shader, got \"" + shader + "\""; - } - if (!boost::starts_with(camera, "ortho") && !boost::starts_with(camera, "persp")) { - return "expected perspective or orthographic camera, got \"" + camera + "\""; - } - if (compression != "none" && compression != "rle" && compression != "zip") { - return "expected none, rle or zip compression, got \"" + compression + "\""; - } - if (width < 1 || height < 1) { - std::ostringstream ostr; - ostr << "expected width > 0 and height > 0, got " << width << "x" << height; - return ostr.str(); - } - return ""; - } - - std::ostream& put(std::ostream& os) const - { - os << " -absorb " << absorb[0] << "," << absorb[1] << "," << absorb[2] - << " -aperture " << aperture - << " -camera " << camera; - if (!color.empty()) os << " -color '" << color << "'"; - os << " -compression " << compression - << " -cpus " << threads - << " -cutoff " << cutoff - << " -far " << zfar - << " -focal " << focal - << " -frame " << frame - << " -gain " << gain - << " -isovalue " << isovalue - << " -light " << light[0] << "," << light[1] << "," << light[2] - << "," << light[3] << "," << light[4] << "," << light[5]; - if (lookat) os << " -lookat " << target[0] << "," << target[1] << "," << target[2]; - os << " -near " << znear - << " -res " << width << "x" << height; - if (!lookat) os << " -rotate " << rotate[0] << "," << rotate[1] << "," << rotate[2]; - os << " -shader " << shader - << " -samples " << samples - << " -scatter " << scatter[0] << "," << scatter[1] << "," << scatter[2] - << " -shadowstep " << step[1] - << " -step " << step[0] - << " -translate " << translate[0] << "," << translate[1] << "," << translate[2]; - if (lookat) os << " -up " << up[0] << "," << up[1] << "," << up[2]; - if (verbose) os << " -v"; - return os; - } -}; - -std::ostream& operator<<(std::ostream& os, const RenderOpts& opts) { return opts.put(os); } - - -void -usage(int exitStatus = EXIT_FAILURE) -{ - RenderOpts opts; // default options - const double fov = openvdb::tools::PerspectiveCamera::focalLengthToFieldOfView( - opts.focal, opts.aperture); - - std::ostringstream ostr; - ostr << std::setprecision(3) << -"Usage: " << gProgName << " in.vdb out.{exr,ppm} [options]\n" << -"Which: ray-traces OpenVDB volumes\n" << -"Options:\n" << -" -aperture F perspective camera aperture in mm (default: " << opts.aperture << ")\n" << -" -camera S camera type; either \"persp[ective]\" or \"ortho[graphic]\"\n" << -" (default: " << opts.camera << ")\n" << -" -compression S EXR compression scheme; either \"none\" (uncompressed),\n" << -" \"rle\" or \"zip\" (default: " << opts.compression << ")\n" << -" -cpus N number of rendering threads, or 1 to disable threading,\n" << -" or 0 to use all available CPUs (default: " << opts.threads << ")\n" << -" -far F camera far plane depth (default: " << opts.zfar << ")\n" << -" -focal F perspective camera focal length in mm (default: " << opts.focal << ")\n" << -" -fov F perspective camera field of view in degrees\n" << -" (default: " << fov << ")\n" << -" -frame F ortho camera frame width in world units (default: " << - opts.frame << ")\n" << -" -lookat X,Y,Z rotate the camera to point to (X, Y, Z)\n" << -" -name S name of the volume to be rendered (default: render\n" << -" the first floating-point volume found in in.vdb)\n" << -" -near F camera near plane depth (default: " << opts.znear << ")\n" << -" -res WxH image dimensions in pixels (default: " << - opts.width << "x" << opts.height << ")\n" << -" -r X,Y,Z \n" << -" -rotate X,Y,Z camera rotation in degrees\n" << -" (default: look at the center of the volume)\n" << -" -t X,Y,Z \n" << -" -translate X,Y,Z camera translation\n" << -" -up X,Y,Z vector that should point up after rotation with -lookat\n" << -" (default: " << opts.up << ")\n" << -"\n" << -" -v verbose (print timing and diagnostics)\n" << -" -h, -help print this usage message and exit\n" << -"\n" << -"Level set options:\n" << -" -color S name of a vec3s volume to be used to set material colors\n" << -" -isovalue F isovalue in world units for level set ray intersection\n" << -" (default: " << opts.isovalue << ")\n" << -" -samples N number of samples (rays) per pixel (default: " << opts.samples << ")\n" << -" -shader S shader name; either \"diffuse\", \"matte\", \"normal\"\n" << -" or \"position\" (default: " << opts.shader << ")\n" << -"\n" << -"Dense volume options:\n" << -" -absorb R,G,B absorption coefficients (default: " << opts.absorb << ")\n" << -" -cutoff F density and transmittance cutoff value (default: " << opts.cutoff << ")\n" << -" -gain F amount of scatter along the shadow ray (default: " << opts.gain << ")\n" << -" -light X,Y,Z[,R,G,B] light source direction and optional color\n" << -" (default: [" << opts.light[0] << ", " << opts.light[1] - << ", " << opts.light[2] << ", " << opts.light[3] << ", " << opts.light[4] - << ", " << opts.light[5] << "])\n" << -" -scatter R,G,B scattering coefficients (default: " << opts.scatter << ")\n" << -" -shadowstep F step size in voxels for integration along the shadow ray\n" << -" (default: " << opts.step[1] << ")\n" << -" -step F step size in voxels for integration along the primary ray\n" << -" (default: " << opts.step[0] << ")\n" << -"\n" << -"Examples:\n" << -" " << gProgName << " crawler.vdb crawler.exr -shader diffuse -res 1920x1080 \\\n" << -" -focal 35 -samples 4 -translate 0,210.5,400 -compression rle -v\n" << -"\n" << -" " << gProgName << " bunny_cloud.vdb bunny_cloud.exr -res 1920x1080 \\\n" << -" -translate 0,0,110 -absorb 0.4,0.2,0.1 -gain 0.2 -v\n" << -"\n" << -"Warning:\n" << -" This is not (and is not intended to be) a production-quality renderer.\n" << -" Use it for fast previewing or simply as a reference implementation\n" << -" for integration into existing ray tracers.\n"; - - std::cerr << ostr.str(); - exit(exitStatus); -} - - -void -saveEXR(const std::string& fname, const openvdb::tools::Film& film, const RenderOpts& opts) -{ - typedef openvdb::tools::Film::RGBA RGBA; - - std::string filename = fname; - if (!boost::iends_with(filename, ".exr")) filename += ".exr"; - - if (opts.verbose) { - std::cout << gProgName << ": writing " << filename << "..." << std::endl; - } - - const tbb::tick_count start = tbb::tick_count::now(); - - int threads = (opts.threads == 0 ? 8 : opts.threads); - Imf::setGlobalThreadCount(threads); - - Imf::Header header(int(film.width()), int(film.height())); - if (opts.compression == "none") { - header.compression() = Imf::NO_COMPRESSION; - } else if (opts.compression == "rle") { - header.compression() = Imf::RLE_COMPRESSION; - } else if (opts.compression == "zip") { - header.compression() = Imf::ZIP_COMPRESSION; - } else { - OPENVDB_THROW(openvdb::ValueError, - "expected none, rle or zip compression, got \"" << opts.compression << "\""); - } - header.channels().insert("R", Imf::Channel(Imf::FLOAT)); - header.channels().insert("G", Imf::Channel(Imf::FLOAT)); - header.channels().insert("B", Imf::Channel(Imf::FLOAT)); - header.channels().insert("A", Imf::Channel(Imf::FLOAT)); - - const size_t pixelBytes = sizeof(RGBA), rowBytes = pixelBytes * film.width(); - RGBA& pixel0 = const_cast(film.pixels())[0]; - Imf::FrameBuffer framebuffer; - framebuffer.insert("R", - Imf::Slice(Imf::FLOAT, reinterpret_cast(&pixel0.r), pixelBytes, rowBytes)); - framebuffer.insert("G", - Imf::Slice(Imf::FLOAT, reinterpret_cast(&pixel0.g), pixelBytes, rowBytes)); - framebuffer.insert("B", - Imf::Slice(Imf::FLOAT, reinterpret_cast(&pixel0.b), pixelBytes, rowBytes)); - framebuffer.insert("A", - Imf::Slice(Imf::FLOAT, reinterpret_cast(&pixel0.a), pixelBytes, rowBytes)); - - Imf::OutputFile imgFile(filename.c_str(), header); - imgFile.setFrameBuffer(framebuffer); - imgFile.writePixels(int(film.height())); - - if (opts.verbose) { - std::ostringstream ostr; - ostr << gProgName << ": ...completed in " << std::setprecision(3) - << (tbb::tick_count::now() - start).seconds() << " sec"; - std::cout << ostr.str() << std::endl; - } -} - - -template -void -render(const GridType& grid, const std::string& imgFilename, const RenderOpts& opts) -{ - using namespace openvdb; - - const bool isLevelSet = (grid.getGridClass() == GRID_LEVEL_SET); - - tools::Film film(opts.width, opts.height); - - boost::scoped_ptr camera; - if (boost::starts_with(opts.camera, "persp")) { - camera.reset(new tools::PerspectiveCamera(film, opts.rotate, opts.translate, - opts.focal, opts.aperture, opts.znear, opts.zfar)); - } else if (boost::starts_with(opts.camera, "ortho")) { - camera.reset(new tools::OrthographicCamera(film, opts.rotate, opts.translate, - opts.frame, opts.znear, opts.zfar)); - } else { - OPENVDB_THROW(ValueError, - "expected perspective or orthographic camera, got \"" << opts.camera << "\""); - } - if (opts.lookat) camera->lookAt(opts.target, opts.up); - - // Define the shader for level set rendering. The default shader is a diffuse shader. - boost::scoped_ptr shader; - if (opts.shader == "matte") { - if (opts.colorgrid) { - shader.reset(new tools::MatteShader(*opts.colorgrid)); - } else { - shader.reset(new tools::MatteShader<>()); - } - } else if (opts.shader == "normal") { - if (opts.colorgrid) { - shader.reset(new tools::NormalShader(*opts.colorgrid)); - } else { - shader.reset(new tools::NormalShader<>()); - } - } else if (opts.shader == "position") { - const CoordBBox bbox = grid.evalActiveVoxelBoundingBox(); - const math::BBox bboxIndex(bbox.min().asVec3d(), bbox.max().asVec3d()); - const math::BBox bboxWorld = bboxIndex.applyMap(*(grid.transform().baseMap())); - if (opts.colorgrid) { - shader.reset(new tools::PositionShader(bboxWorld, *opts.colorgrid)); - } else { - shader.reset(new tools::PositionShader<>(bboxWorld)); - } - } else /* if (opts.shader == "diffuse") */ { // default - if (opts.colorgrid) { - shader.reset(new tools::DiffuseShader(*opts.colorgrid)); - } else { - shader.reset(new tools::DiffuseShader<>()); - } - } - - if (opts.verbose) { - std::cout << gProgName << ": ray-tracing"; - const std::string gridName = grid.getName(); - if (!gridName.empty()) std::cout << " " << gridName; - std::cout << "..." << std::endl; - } - const tbb::tick_count start = tbb::tick_count::now(); - - if (isLevelSet) { - tools::LevelSetRayIntersector intersector( - grid, static_cast(opts.isovalue)); - tools::rayTrace(grid, intersector, *shader, *camera, opts.samples, - /*seed=*/0, (opts.threads != 1)); - } else { - typedef tools::VolumeRayIntersector IntersectorType; - IntersectorType intersector(grid); - - tools::VolumeRender renderer(intersector, *camera); - renderer.setLightDir(opts.light[0], opts.light[1], opts.light[2]); - renderer.setLightColor(opts.light[3], opts.light[4], opts.light[5]); - renderer.setPrimaryStep(opts.step[0]); - renderer.setShadowStep(opts.step[1]); - renderer.setScattering(opts.scatter[0], opts.scatter[1], opts.scatter[2]); - renderer.setAbsorption(opts.absorb[0], opts.absorb[1], opts.absorb[2]); - renderer.setLightGain(opts.gain); - renderer.setCutOff(opts.cutoff); - - renderer.render(opts.threads != 1); - } - - if (opts.verbose) { - std::ostringstream ostr; - ostr << gProgName << ": ...completed in " << std::setprecision(3) - << (tbb::tick_count::now() - start).seconds() << " sec"; - std::cout << ostr.str() << std::endl; - } - - if (boost::iends_with(imgFilename, ".ppm")) { - // Save as PPM (fast, but large file size). - std::string filename = imgFilename; - filename.erase(filename.size() - 4); // strip .ppm extension - film.savePPM(filename); - } else if (boost::iends_with(imgFilename, ".exr")) { - // Save as EXR (slow, but small file size). - saveEXR(imgFilename, film, opts); - } else { - OPENVDB_THROW(ValueError, "unsupported image file format (" + imgFilename + ")"); - } -} - - -void -strToSize(const std::string& s, size_t& x, size_t& y) -{ - std::vector elems; - boost::split(elems, s, boost::algorithm::is_any_of(",x")); - const size_t numElems = elems.size(); - if (numElems > 0) x = size_t(std::max(0, atoi(elems[0].c_str()))); - if (numElems > 1) y = size_t(std::max(0, atoi(elems[1].c_str()))); -} - - -std::vector -strToVec(const std::string& s) -{ - std::vector result; - std::vector elems; - boost::split(elems, s, boost::algorithm::is_any_of(",")); - for (size_t i = 0, N = elems.size(); i < N; ++i) { - result.push_back(atof(elems[i].c_str())); - } - return result; -} - - -openvdb::Vec3d -strToVec3d(const std::string& s) -{ - openvdb::Vec3d result(0.0, 0.0, 0.0); - std::vector elems = strToVec(s); - if (!elems.empty()) { - result = openvdb::Vec3d(elems[0]); - for (int i = 1, N = std::min(3, int(elems.size())); i < N; ++i) { - result[i] = elems[i]; - } - } - return result; -} - - -struct OptParse -{ - int argc; - char** argv; - - OptParse(int argc_, char* argv_[]): argc(argc_), argv(argv_) {} - - bool check(int idx, const std::string& name, int numArgs = 1) const - { - if (argv[idx] == name) { - if (idx + numArgs >= argc) { - std::cerr << gProgName << ": option " << name << " requires " - << numArgs << " argument" << (numArgs == 1 ? "" : "s") << "\n"; - usage(); - } - return true; - } - return false; - } -}; - -} // unnamed namespace - - -int -main(int argc, char *argv[]) -{ -#ifdef DWA_OPENVDB - USAGETRACK_report_basic_tool_usage(argc, argv, /*duration=*/0); - logging_base::configure(argc, argv); -#endif - - OPENVDB_START_THREADSAFE_STATIC_WRITE - gProgName = argv[0]; - if (const char* ptr = ::strrchr(gProgName, '/')) gProgName = ptr + 1; - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - - int retcode = EXIT_SUCCESS; - - if (argc == 1) usage(); - - std::string vdbFilename, imgFilename, gridName; - RenderOpts opts; - - bool hasFocal = false, hasFov = false, hasRotate = false, hasLookAt = false; - float fov = 0.0; - - OptParse parser(argc, argv); - for (int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - if (arg[0] == '-') { - if (parser.check(i, "-absorb")) { - ++i; - opts.absorb = strToVec3d(argv[i]); - } else if (parser.check(i, "-aperture")) { - ++i; - opts.aperture = float(atof(argv[i])); - } else if (parser.check(i, "-camera")) { - ++i; - opts.camera = argv[i]; - } else if (parser.check(i, "-color")) { - ++i; - opts.color = argv[i]; - } else if (parser.check(i, "-compression")) { - ++i; - opts.compression = argv[i]; - } else if (parser.check(i, "-cpus")) { - ++i; - opts.threads = std::max(0, atoi(argv[i])); - } else if (parser.check(i, "-cutoff")) { - ++i; - opts.cutoff = atof(argv[i]); - } else if (parser.check(i, "-isovalue")) { - ++i; - opts.isovalue = atof(argv[i]); - } else if (parser.check(i, "-far")) { - ++i; - opts.zfar = float(atof(argv[i])); - } else if (parser.check(i, "-focal")) { - ++i; - opts.focal = float(atof(argv[i])); - hasFocal = true; - } else if (parser.check(i, "-fov")) { - ++i; - fov = float(atof(argv[i])); - hasFov = true; - } else if (parser.check(i, "-frame")) { - ++i; - opts.frame = float(atof(argv[i])); - } else if (parser.check(i, "-gain")) { - ++i; - opts.gain = atof(argv[i]); - } else if (parser.check(i, "-light")) { - ++i; - opts.light = strToVec(argv[i]); - } else if (parser.check(i, "-lookat")) { - ++i; - opts.lookat = true; - opts.target = strToVec3d(argv[i]); - hasLookAt = true; - } else if (parser.check(i, "-name")) { - ++i; - gridName = argv[i]; - } else if (parser.check(i, "-near")) { - ++i; - opts.znear = float(atof(argv[i])); - } else if (parser.check(i, "-r") || parser.check(i, "-rotate")) { - ++i; - opts.rotate = strToVec3d(argv[i]); - hasRotate = true; - } else if (parser.check(i, "-res")) { - ++i; - strToSize(argv[i], opts.width, opts.height); - } else if (parser.check(i, "-scatter")) { - ++i; - opts.scatter = strToVec3d(argv[i]); - } else if (parser.check(i, "-shader")) { - ++i; - opts.shader = argv[i]; - } else if (parser.check(i, "-shadowstep")) { - ++i; - opts.step[1] = atof(argv[i]); - } else if (parser.check(i, "-samples")) { - ++i; - opts.samples = size_t(std::max(0, atoi(argv[i]))); - } else if (parser.check(i, "-step")) { - ++i; - opts.step[0] = atof(argv[i]); - } else if (parser.check(i, "-t") || parser.check(i, "-translate")) { - ++i; - opts.translate = strToVec3d(argv[i]); - } else if (parser.check(i, "-up")) { - ++i; - opts.up = strToVec3d(argv[i]); - } else if (arg == "-v") { - opts.verbose = true; - } else if (arg == "-h" || arg == "-help" || arg == "--help") { - usage(EXIT_SUCCESS); - } else { - std::cerr << gProgName << ": \"" << arg << "\" is not a valid option\n"; - usage(); - } - } else if (vdbFilename.empty()) { - vdbFilename = arg; - } else if (imgFilename.empty()) { - imgFilename = arg; - } else { - usage(); - } - } - if (vdbFilename.empty() || imgFilename.empty()) { - usage(); - } - if (hasFov) { - if (hasFocal) { - OPENVDB_LOG_FATAL("specify -focal or -fov, but not both"); - usage(); - } - opts.focal = float( - openvdb::tools::PerspectiveCamera::fieldOfViewToFocalLength(fov, opts.aperture)); - } - if (hasLookAt && hasRotate) { - OPENVDB_LOG_FATAL("specify -lookat or -r[otate], but not both"); - usage(); - } - { - const std::string err = opts.validate(); - if (!err.empty()) { - OPENVDB_LOG_FATAL(err); - usage(); - } - } - - try { - tbb::task_scheduler_init schedulerInit( - (opts.threads == 0) ? tbb::task_scheduler_init::automatic : opts.threads); - - openvdb::initialize(); - - const tbb::tick_count start = tbb::tick_count::now(); - if (opts.verbose) { - std::cout << gProgName << ": reading "; - if (!gridName.empty()) std::cout << gridName << " from "; - std::cout << vdbFilename << "..." << std::endl; - } - - openvdb::FloatGrid::Ptr grid; - { - openvdb::io::File file(vdbFilename); - - if (!gridName.empty()) { - file.open(); - grid = openvdb::gridPtrCast(file.readGrid(gridName)); - if (!grid) { - OPENVDB_THROW(openvdb::ValueError, - gridName + " is not a scalar, floating-point volume"); - } - } else { - // If no grid was specified by name, retrieve the first float grid from the file. - file.open(/*delayLoad=*/false); - openvdb::io::File::NameIterator it = file.beginName(); - openvdb::GridPtrVecPtr grids = file.readAllGridMetadata(); - for (size_t i = 0; i < grids->size(); ++i, ++it) { - grid = openvdb::gridPtrCast(grids->at(i)); - if (grid) { - gridName = *it; - file.close(); - file.open(); - grid = openvdb::gridPtrCast(file.readGrid(gridName)); - break; - } - } - if (!grid) { - OPENVDB_THROW(openvdb::ValueError, - "no scalar, floating-point volumes in file " + vdbFilename); - } - } - - if (!opts.color.empty()) { - opts.colorgrid = - openvdb::gridPtrCast(file.readGrid(opts.color)); - if (!opts.colorgrid) { - OPENVDB_THROW(openvdb::ValueError, - opts.color + " is not a vec3s color volume"); - } - } - } - - if (opts.verbose) { - std::ostringstream ostr; - ostr << gProgName << ": ...completed in " << std::setprecision(3) - << (tbb::tick_count::now() - start).seconds() << " sec"; - std::cout << ostr.str() << std::endl; - } - - if (grid) { - if (!hasLookAt && !hasRotate) { - // If the user specified neither the camera rotation nor a target - // to look at, orient the camera to point to the center of the grid. - opts.target = grid->evalActiveVoxelBoundingBox().getCenter(); - opts.target = grid->constTransform().indexToWorld(opts.target); - opts.lookat = true; - } - - if (opts.verbose) std::cout << opts << std::endl; - - render(*grid, imgFilename, opts); - } - } catch (std::exception& e) { - OPENVDB_LOG_FATAL(e.what()); - retcode = EXIT_FAILURE; - } catch (...) { - OPENVDB_LOG_FATAL("Exception caught (unexpected type)"); - std::unexpected(); - } - - return retcode; -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/cmd/openvdb_view/main.cc b/openvdb_3_0_0_library/cmd/openvdb_view/main.cc deleted file mode 100755 index 8523f58..0000000 --- a/openvdb_3_0_0_library/cmd/openvdb_view/main.cc +++ /dev/null @@ -1,169 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#ifdef DWA_OPENVDB -#include -#include -#endif - - -void -usage(const char* progName, int status) -{ - (status == EXIT_SUCCESS ? std::cout : std::cerr) << -"Usage: " << progName << " file.vdb [file.vdb ...] [options]\n" << -"Which: displays OpenVDB grids\n" << -"Options:\n" << -" -i print grid info\n" << -" -d print debugging info\n" << -"Controls:\n" << -" Esc exit\n" << -" -> (Right) show next grid\n" << -" <- (Left) show previous grid\n" << -" 1 toggle tree topology view on/off\n" << -" 2 toggle surface view on/off\n" << -" 3 toggle data view on/off\n" << -" G (\"geometry\") look at center of geometry\n" << -" H (\"home\") look at origin\n" << -" I toggle on-screen grid info on/off\n" << -" left mouse tumble\n" << -" right mouse pan\n" << -" mouse wheel zoom\n" << -"\n" << -" X + wheel move right cut plane\n" << -" Shift + X + wheel move left cut plane\n" << -" Y + wheel move top cut plane\n" << -" Shift + Y + wheel move bottom cut plane\n" << -" Z + wheel move front cut plane\n" << -" Shift + Z + wheel move back cut plane\n" << -" Ctrl + X + wheel move both X cut planes\n" << -" Ctrl + Y + wheel move both Y cut planes\n" << -" Ctrl + Z + wheel move both Z cut planes\n"; - exit(status); -} - - -//////////////////////////////////////// - - -int -main(int argc, char *argv[]) -{ -#ifdef DWA_OPENVDB - USAGETRACK_report_basic_tool_usage(argc, argv, /*duration=*/0); - logging_base::configure(argc, argv); -#endif - - const char* progName = argv[0]; - if (const char* ptr = ::strrchr(progName, '/')) progName = ptr + 1; - - int status = EXIT_SUCCESS; - - try { - openvdb::initialize(); - - bool printInfo = false, printDebugInfo = false; - - // Parse the command line. - std::vector filenames; - for (int n = 1; n < argc; ++n) { - std::string str(argv[n]); - if (str[0] != '-') { - filenames.push_back(str); - } else if (str == "-i") { - printInfo = true; - } else if (str == "-d") { - printDebugInfo = true; - } else if (str == "-h" || str == "--help") { - usage(progName, EXIT_SUCCESS); - } else { - usage(progName, EXIT_FAILURE); - } - } - - openvdb_viewer::Viewer viewer = openvdb_viewer::init(progName, /*bg=*/false); - - if (printDebugInfo) { - std::cout << viewer.getVersionString() << std::endl; - } - - const size_t numFiles = filenames.size(); - if (numFiles == 0) usage(progName, EXIT_FAILURE); - - openvdb::GridCPtrVec allGrids; - - // Load VDB files. - std::string indent(numFiles == 1 ? "" : " "); - for (size_t n = 0; n < numFiles; ++n) { - openvdb::io::File file(filenames[n]); - file.open(); - - openvdb::GridPtrVecPtr grids = file.getGrids(); - if (grids->empty()) { - OPENVDB_LOG_WARN(filenames[n] << " is empty"); - continue; - } - allGrids.insert(allGrids.end(), grids->begin(), grids->end()); - - if (printInfo) { - if (numFiles > 1) std::cout << filenames[n] << ":\n"; - for (size_t i = 0; i < grids->size(); ++i) { - const std::string name = (*grids)[i]->getName(); - openvdb::Coord dim = (*grids)[i]->evalActiveVoxelDim(); - std::cout << indent << (name.empty() ? "" : name) - << " (" << dim[0] << " x " << dim[1] << " x " << dim[2] - << " voxels)" << std::endl; - } - } - } - - viewer.open(); - viewer.view(allGrids); - - openvdb_viewer::exit(); - - } catch (const char* s) { - OPENVDB_LOG_ERROR(progName << ": " << s); - status = EXIT_FAILURE; - } catch (std::exception& e) { - OPENVDB_LOG_ERROR(progName << ": " << e.what()); - status = EXIT_FAILURE; - } - return status; -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/doc/api_0_98_0.txt b/openvdb_3_0_0_library/doc/api_0_98_0.txt deleted file mode 100755 index de5b29f..0000000 --- a/openvdb_3_0_0_library/doc/api_0_98_0.txt +++ /dev/null @@ -1,196 +0,0 @@ -/** - -@page api_0_98_0 Porting to OpenVDB 0.98.0 - -Starting in OpenVDB 0.98.0, @vdblink::tree::Tree Tree@endlink and -@vdblink::math::Transform Transform@endlink objects (and -@vdblink::Grid Grid@endlink objects in the context of Houdini SOPs) -are passed and accessed primarily by reference -rather than by shared pointer. -(This is partly for performance reasons; the overhead of copying shared -pointers, especially in a threaded environment, can be significant.) -Furthermore, those objects now exhibit copy-on-write semantics, so that -in most cases it is no longer necessary to make explicit deep copies. -These changes were, for the most part, requested and implemented by -Side Effects. - -Accessor methods like @vdblink::Grid::tree() Grid::tree@endlink, -@vdblink::Grid::transform() Grid::transform@endlink and -@c GEO_PrimVDB::getGrid that used to return shared pointers now return const -references. -Variants like @c Grid::constTree, which returned const shared -pointers, have been removed, and new read/write accessors have been added. -The latter, including @c Grid::treeRW(), @c Grid::transformRW() and -@c GEO_PrimVDB::getGridRW, return non-const references, but they also ensure -that ownership of the returned object is exclusive to the container -(that is, they ensure that the grid has exclusive ownership of the tree or -transform and that the primitive has exclusive ownership of the grid). -The logic is as follows: if a grid, for example, has sole ownership of a -tree, then @c Grid::treeRW() returns a non-const reference to that tree; -but if the tree is shared (with other grids, perhaps), then -@c Grid::treeRW() assigns the grid a new, deep copy of the tree -and returns a non-const reference to the new tree. - -Shared pointers to @c Tree, @c Transform and @c Grid objects can still be -requested from their respective containers via @c Grid::sharedTree(), -@c Grid::sharedTransform() and @c GEO_PrimVDB::getSharedGrid, -but their use is now discouraged. - -For Houdini SOPs, there are additional changes. First, VDB primitives are -now normally processed in-place. That is, rather than extract a -primitive's grid, make a deep copy of it and construct a new primitive to -hold the copy, one now requests read/write access to a primitive's grid and -then modifies the resulting grid. (SOPs that generate primitives or that -replace grids of one type with another type can still do so using the old -approach, however.) - -Second, grid metadata such as a grid's class (level set, fog volume, etc.), -value type (@c float, @c vec3s, etc.), background value and so on (the full -list is hardcoded into @c GEO_PrimVDB) is now exposed via "intrinsic" -attributes of grid primitives, rather than via primitive attributes as before. -As a result, this information no longer appears in a SOP's geometry -spreadsheet, nor does any extra metadata that a SOP might add to a grid during -processing. The metadata is still preserved in the @c Grid objects, though. - -Third, @c openvdb_houdini::processTypedGrid, which passes a shared grid -pointer to a functor that also takes a shared pointer, is now deprecated in -favor of @c openvdb_houdini::UTvdbProcessTypedGrid, which accepts shared -pointers, raw pointers or references to grids (provided that the functor -accepts an argument of the same kind). Below is a comparison of the old -and new usage in the typical case of a SOP that processes input grids: - - -Old API (0.97.0 and earlier) - -@code - struct MyGridProcessor - { - template - void operator()(typename GridT::Ptr grid) const - { - // Process the grid's tree. -(1) grid->tree()->pruneInactive(); - } - }; - - SOP_OpenVDB_Example::cookMySop(OP_Context& context) - { - ... - duplicateSource(0, context); - - // Process each VDB primitive that belongs to the selected group. - for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) { - - openvdb_houdini::GU_PrimVDB* vdbPrim = *it; - - // Deep copy the primitive's grid if it is going to be modified. - openvdb_houdini::GridPtr grid = vdbPrim->getGrid()->deepCopyGrid(); - // Otherwise, retrieve a read-only grid pointer. - //openvdb_houdini::GridCPtr grid = vdbPrim->getGrid(); - - // Process the grid. - MyGridProcessor proc; -(2) openvdb_houdini::processTypedGrid(grid, proc); - - // Create a new VDB primitive that contains the modified grid, - // and in the output detail replace the original primitive with - // the new one. -(3) openvdb_houdini::replaceVdbPrimitive(*gdp, grid, *vdbPrim); - } - } -@endcode - - -New API (0.98.0 and later) - -@code - struct MyGridProcessor { - template - void operator()(GridT& grid) const - { - // Request write access to the grid's tree, then process the tree. -(1) grid.treeRW().pruneInactive(); - } - }; - - SOP_OpenVDB_Example::cookMySop(OP_Context& context) - { - ... - duplicateSource(0, context); - - // Process each VDB primitive that belongs to the selected group. - for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) { - - openvdb_houdini::GU_PrimVDB* vdbPrim = *it; - - // Get write access to the grid associated with the primitive. - // If the grid is shared with other primitives, this will - // make a deep copy of it. - openvdb_houdini::Grid& grid = vdbPrim->getGridRW(); - - // If the grid is not going to be modified, get read-only access. - //const openvdb_houdini::Grid& grid = vdbPrim->getGrid(); - - // Process the grid. - MyGridProcessor proc; -(2) openvdb_houdini::UTvdbProcessTypedGrid( -(4) vdbPrim->getStorageType(), grid, proc); - } - } -@endcode - - -@b Notes -
    -
  1. -In the old API, @vdblink::Grid::tree() Grid::tree@endlink returned either -a shared, non-const pointer to a tree or a shared const pointer, depending -on whether the grid itself was non-const or const. In the new API, -@vdblink::Grid::tree() Grid::tree@endlink always returns a const reference, -and @c Grid::treeRW() always returns a non-const reference. - -
  2. -@c openvdb_houdini::processTypedGrid (old API) accepts only shared pointers -to grids (or shared pointers to const grids), together with functors that -accept shared pointers to grids. @c openvdb_houdini::UTvdbProcessTypedGrid -(new API) accepts const and non-const references, shared pointers and raw -pointers, together with matching functors. That is, all of the following -are valid pairs of grid and functor arguments to @c UTvdbProcessTypedGrid(): -@code -openvdb_houdini::Grid& grid = vdbPrim->getGridRW(); -struct MyProc { template operator()(GridT&) {...} }; - -const openvdb_houdini::Grid& grid = vdbPrim->getGrid(); -struct MyProc { template operator()(const GridT&) {...} }; - -openvdb_houdini::GridPtr grid = vdbPrim->getSharedGrid(); -struct MyProc { template operator()(typename GridT::Ptr) {...} }; - -openvdb_houdini::GridCPtr grid = vdbPrim->getSharedConstGrid(); -struct MyProc { template operator()(typename GridT::ConstPtr) {...} }; - -openvdb_houdini::Grid* grid = &vdbPrim->getGridRW(); -struct MyProc { template operator()(GridT*) {...} }; - -const openvdb_houdini::Grid* grid = &vdbPrim->getGrid(); -struct MyProc { template operator()(const GridT*) {...} }; -@endcode - -
  3. -In the old API, input grid primitives were (usually) deleted after -processing, and a new primitive was created for each output grid. -@c openvdb_houdini::replaceVdbPrimitive() did both operations in one step -and had the side effect of transferring the output grid's metadata to -primitive attributes. In the new API, @c replaceVdbPrimitive() is rarely -needed, because input grids can usually be processed in-place, and -most commonly-used metadata is exposed via intrinsic attributes, which -don't need to be manually updated. - -
  4. -The first argument to @c openvdb_houdini::UTvdbProcessTypedGrid() is the -grid's storage type, which can be retrieved either by passing the grid -to @c openvdb_houdini::UTvdbGetGridType() or by calling -@c GEO_PrimVDB::getStorageType() on the primitive. -
- -*/ diff --git a/openvdb_3_0_0_library/doc/changes.txt b/openvdb_3_0_0_library/doc/changes.txt deleted file mode 100755 index d092fd9..0000000 --- a/openvdb_3_0_0_library/doc/changes.txt +++ /dev/null @@ -1,1444 +0,0 @@ -/** - -@page changes Release Notes - - -@htmlonly @endhtmlonly -@par -Version 3.0.0 - January 14, 2015 -- The @vdblink::io::File File@endlink class now supports delayed loading of - .vdb files, meaning that memory is not allocated for voxel values - until the values are actually accessed. (This feature is enabled by default.) - Until a grid has been fully loaded, its source .vdb file must not be - modified or deleted, so for safety, - @vdblink::io::File::open() File::open@endlink automatically makes - private copies of source files that are smaller than a user-specified limit - (see @vdblink::io::File::setCopyMaxBytes() File::setCopyMaxBytes@endlink). - The limit can be set to zero to disable copying, but if it cannot be - guaranteed that a file will not be modified, then it is best not to enable - delayed loading for that file. -- .vdb files can now optionally be compressed with the Blosc LZ4 - codec. Blosc compresses almost as well - as ZLIB, but it is much faster. -- Added @vdblink::tools::PointPartitioner PointPartitioner@endlink, a tool - for fast spatial sorting of points stored in an external array, and - @link PointIndexGrid.h PointIndexGrid@endlink, an acceleration structure - for fast range and nearest-neighbor searches. -- Added @link NodeManager.h tree::NodeManager@endlink, - which linearizes a tree to facilitate efficient multithreading - across all tree levels. -- Added @vdblink::tools::prune() tools::prune@endlink (and other variants), - which replaces and outperforms @c Tree::prune. -- Added @vdblink::tools::signedFloodFill() tools::signedFloodFill@endlink, - which replaces and outperforms @c Tree::signedFloodFill. -- Added @vdblink::tools::changeBackground() tools::changeBackground@endlink - (and other variants), which replaces and outperforms @c Tree::setBackground(). -- Added a fast but approximate narrow-band level set - @vdblink::tools::LevelSetTracker::dilate() dilation@endlink method, a fast - narrow-band level set - @vdblink::tools::LevelSetTracker::erode() erosion@endlink - method, and a @vdblink::tools::LevelSetTracker::normalize(const MaskType*) - masked normalization@endlink method to - @vdblink::tools::LevelSetTracker LevelSetTracker@endlink. -- Added @vdblink::tools::Diagnose Diagnose@endlink, which performs - multithreaded diagnostics on grids to identify issues like values that - are NaNs or out-of-range. It optionally generates a boolean grid of all - values that fail user-defined tests. -- Added optional alpha masks to @vdblink::tools::LevelSetMorphing - LevelSetMorphing@endlink. -- Fixed an intermittent crash in - @vdblink::tools::LevelSetMorphing LevelSetMorphing@endlink. -- Added @c tools::topologyToLevelSet(), - which generates a level set from the implicit boundary between active - and inactive voxels in an arbitrary input grid. - [DWA internal] -- Improved the performance of point scattering (by orders of magnitude) - and added a - @vdblink::tools::DenseUniformPointScatter DenseUniformPointScatter@endlink - class as well as support for fractional numbers of particles per voxel. -- Improved the performance and memory footprint of - the @vdblink::tools::ParticlesToLevelSet ParticlesToLevelSet@endlink tool - for large numbers (tens to hundreds of millions) of particles. -- Added edge-adjacent (6+12=18 neighbors) and vertex-adjacent (6+12+8=26 - neighbors) dilation algorithms to - @vdblink::tools::Morphology::dilateVoxels Morphology::dilateVoxels@endlink. - The default dilation pattern is still face-adjacent (6 neighbors). -- Added @vdblink::tree::Tree::getNodes() Tree::getNodes@endlink, which allows - for fast construction of linear arrays of tree nodes for use in multithreaded - code such as the @vdblink::tree::LeafManager LeafManager@endlink or - @link NodeManager.h tree::NodeManager@endlink. -- Added @vdblink::math::Extrema math::Extrema@endlink and - @vdblink::tools::extrema() tools::extrema@endlink to efficiently - compute minimum and maximum values in a grid. -- Added support for material color grids to all level set - @vdblink::tools::BaseShader shaders@endlink, and added an option to - @c vdb_render that allows one to specify a reference grid to be used - for material color lookups. -- Added @vdblink::getLibraryVersionString() - getLibraryVersionString@endlink and - @link OPENVDB_LIBRARY_VERSION_STRING@endlink. -- Modified the mesh to volume converter to always set the grid background - value to the exterior narrow-band width, and added finite value checks - to narrow band parameters. -- @vdblink::tools::volumeToMesh() tools::volumeToMesh@endlink now compiles - for all grid types but throws an exception if the input grid does not - have a scalar value type. -- Added a - @vdblink::io::File::readGrid(const Name&, const BBoxd&) File::readGrid@endlink - overload and @vdblink::GridBase::readBuffers(std::istream&, const CoordBBox&) - readBuffers@endlink overloads to the grid, tree and node classes that allow - one to specify a bounding box against which to clip a grid while reading it. - For large grids, clipping while reading can result in significantly lower - memory usage than clipping after reading. -- Added @vdblink::GridBase::clipGrid() GridBase::clipGrid@endlink, which - clips a grid against a world-space bounding box, and - @vdblink::GridBase::clip() GridBase::clip@endlink and - @vdblink::tree::Tree::clip() Tree::clip@endlink, which clip against - an index-space bounding box. -- Added @vdblink::tools::clip() tools::clip@endlink, which clips a grid - either against a bounding box or against the active voxels of a mask grid. -- @vdblink::io::File::readGridPartial() File::readGridPartial@endlink - allocates the nodes of a grid’s tree as before, but it now allocates - leaf nodes without data buffers. (This feature is mainly for internal use. - Partially-read grids should be used with care if at all, and they should - be treated as read-only.) -- Grid names retrieved using a - @vdblink::io::File::NameIterator File::NameIterator@endlink now always - uniquely identify grids; they no longer generate ‘more than one grid - named “x”’ warnings when there are multiple - grids of the same name in a file (for files written starting with this - version of the OpenVDB library). -- Fixed a bug in @vdblink::tree::Tree::ValueOffIter Tree::ValueOffIter@endlink - that could cause - @vdblink::tree::TreeValueIteratorBase::setMaxDepth() depth-bounded@endlink - iterators to return incorrect values. -- Eliminated a recursive call in @vdblink::tree::TreeValueIteratorBase::next() - TreeValueIteratorBase::next@endlink that could cause crashes on systems - with a limited stack size. -- Fixed memory leaks in @vdblink::tree::RootNode::topologyDifference() - RootNode::topologyDifference@endlink and - @vdblink::tree::RootNode::topologyIntersection() - RootNode::topologyIntersection@endlink. -- Fixed a memory leak in @vdblink::io::Queue io::Queue@endlink when the queue - was full and a write task could not be added within the timeout interval. -- Fixed a potential division by zero crash in - @vdblink::tools::compDiv() tools::compDiv@endlink with integer-valued grids. -- Fixed kernel normalization in the @vdblink::tools::Filter filter tool@endlink - so that it is correct for integer-valued grids. -- Fixed a bug in @vdblink::tree::LeafNode::Buffer::getValue() - LeafNode::Buffer::getValue@endlink whereby Visual C++ would return - a reference to a temporary. - [Contributed by SESI] -- Fixed a bug in @vdblink::tools::ParticlesToLevelSet - tools::ParticlesToLevelSet@endlink related to attribute transfer - when leaf nodes are produced without active values. -- Added @vdblink::util::CpuTimer util::CpuTimer@endlink and removed - the more simplistic @c unittest_util::CpuTimer from @c unittest/util.h. -- Eliminated the use of @c getopt for command-line argument parsing - in @c vdb_test. -- @vdblink::initialize() openvdb::initialize@endlink now properly initializes - log4cplus if it is enabled, - eliminating “No appenders could be found” errors. -- Fixed a bug in the - @vdblink::math::QuantizedUnitVec::pack() QuantizedUnitVec::pack@endlink - method that caused quantization artifacts. -- Added convenience class @vdblink::tools::AlphaMask AlphaMask@endlink -- Added constructors and methods to both - @vdblink::math::RandInt RandInt@endlink and - @vdblink::math::Rand01 Rand01@endlink to set and reset the random seed value. -- Added convenience methods for - @vdblink::math::Transform::indexToWorld(const BBoxd&) const transforming@endlink - @vdblink::math::Transform::worldToIndex(const BBoxd&) const bounding@endlink - @vdblink::math::Transform::worldToIndexCellCentered(const BBoxd&) const boxes@endlink - to @vdblink::math::Transform math::Transform@endlink. -- @c vdb_view is now compatible with both GLFW 2 and GLFW 3. -- Made many small changes to address type conversion and other warnings - reported by newer compilers like GCC 4.8 and ICC 14. -- Replaced the @c HALF_INCL_DIR and @c HALF_LIB_DIR Makefile variables - with @c ILMBASE_INCL_DIR and @c ILMBASE_LIB_DIR and added @c ILMBASE_LIB, - to match OpenEXR’s - library organization. [Contributed by Double Negative] -- Eliminated most local (function-scope) static variables, because - Visual C++ doesn’t guarantee thread-safe initialization - of local statics. [Contributed by SESI] -- Fixed a bug in @vdblink::readString() readString@endlink related - to empty strings. - [Contributed by Fabio Piparo] -- Fixed a bug in the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink - simplification scheme that was creating visual artifacts. - -@par -API changes: -- The addition of a - @vdblink::GridBase::readBuffers(std::istream&, const CoordBBox&) - GridBase::readBuffers@endlink virtual function overload and the - @vdblink::GridBase::clip() GridBase::clip@endlink - @vdblink::GridBase::readNonresidentBuffers() - GridBase::readNonresidentBuffers@endlink and - @vdblink::tree::Tree::clipUnallocatedNodes() Tree::clipUnallocatedNodes@endlink - virtual functions changes the grid ABI so that it is incompatible with - earlier versions of the OpenVDB library (such as the ones in Houdini 12.5 - and 13). Define the macro @c OPENVDB_2_ABI_COMPATIBLE when compiling - OpenVDB to disable these changes and preserve ABI compatibility. -- All @vdblink::tools::BaseShader shaders@endlink now have a template argument - to specify the type of an optional material color grid, but the default type - mimics the old, uniform color behavior. -- Removed a deprecated - @vdblink::io::Stream::write() io::Stream::write@endlink overload. -- The point counts in - @vdblink::tools::UniformPointScatter UniformPointScatter@endlink - and @vdblink::tools::NonUniformPointScatter NonUniformPointScatter@endlink - are now specified and returned as @vdblink::Index64 Index64@endlink. -- @vdblink::math::RandInt RandInt@endlink has an extra template argument - to specify the integer type. - The @vdblink::math::RandomInt RandomInt@endlink typedef is unchanged. -- @vdblink::io::readData() io::readData@endlink, - @vdblink::io::HalfReader::read() io::HalfReader::read@endlink - and @vdblink::io::HalfWriter::write() io::HalfWriter::write@endlink - now take a @c uint32_t argument indicating the type of compression - instead of a @c bool indicating whether compression is enabled. -- Removed @c io::Archive::isCompressionEnabled() and - @c io::Archive::setCompressionEnabled() and renamed - @c io::Archive::compressionFlags() and @c io::Archive::setCompressionFlags() - to @vdblink::io::Archive::compression() io::Archive::compression@endlink and - @vdblink::io::Archive::setCompression() io::Archive::setCompression@endlink. -- Internal and leaf node classes are now required to provide - "PartialCreate" constructors that optionally bypass the allocation - of voxel buffers. Leaf node classes must now also provide - @vdblink::tree::LeafNode::allocate() allocate@endlink and - @vdblink::tree::LeafNode::isAllocated() isAllocated@endlink methods - to manage the allocation of their buffers. -- Removed @c pruneInactive and @c pruneLevelSet methods from the - @vdblink::tree::Tree Tree@endlink and various node classes. - These methods have been replaced by the much faster pruning functions - found in tools/Prune.h. -- Removed @c signedFloodFill methods from the @vdblink::Grid Grid@endlink, - @vdblink::tree::Tree Tree@endlink and various node classes. - These methods have been replaced by the much faster functions - found in tools/SignedFloodFill.h. -- Removed @c Grid::setBackground() and @c Tree::setBackground() (use the - faster @vdblink::tools::changeBackground() changeBackground@endlink tool - instead), and removed the default argument from - @vdblink::tree::RootNode::setBackground() RootNode::setBackground@endlink. - -@par -Python: -- Added grid methods @c convertToPolygons() and @c convertToQuads(), - which convert volumes to meshes, and @c createLevelSetFromPolygons(), - which converts meshes to volumes. - NumPy is required. - -@par -Maya: -- Added an adaptive polygonal surface extraction node. - -@par -Houdini: -- Added a new Resize Narrow Band SOP that can efficiently adjust the width - of a level set’s narrow band. This allows, for example, for a - level set to be created quickly from points or polygons with a very - narrow band that is then quickly resized to a desired width. -- Fixed bugs in the Smooth Level Set and Reshape Level Set SOPs that - caused them to ignore the selected discretization scheme. -- Added a Morph Level Set SOP. -- Added a From Points SOP to very quickly generate a level set - from a point cloud, ignoring any radius attribute. - [DWA internal] -- Added a Voxel Scale mode to the Resample SOP. -- Improved the performance and memory footprint of the From Particles SOP - for large numbers (tens to hundreds of millions) of particles. -- The Scatter SOP now accepts fractional numbers of particles per voxel. -- Improved the performance of the Scatter SOP by more than an order - of magnitude. -- The Clip SOP now has a toggle to choose explicitly between a mask grid - or a bounding box as the clipping region. As a consequence, the mask grid - can now be unnamed. -- Added the OpenVDB library version number to the Extended Operator - Information for all SOPs. -- SOPs are now linked with an rpath to the directory containing the - OpenVDB library. -- Like the native Houdini file SOP, the Read SOP now allows missing frames - to be reported either as errors or as warnings. -- The Read SOP now has an optional input for geometry, the bounding box - of which can be used to clip grids as they are read. For large grids, - clipping while reading can result in significantly lower memory usage - than clipping after reading. -- The From Polygons and Convert SOPs now default to using the polygon soup - mesh representation, which uses less memory. - -@htmlonly @endhtmlonly -@par -Version 2.3.0 - April 23, 2014 -- Added @vdblink::tools::extractSparseTree() extractSparseTree@endlink, - which selectively extracts and transforms data from a dense grid to - produce a sparse tree, and @vdblink::tools::extractSparseTreeWithMask() - extractSparseTreeWithMask@endlink, which copies data from the index-space - intersection of a sparse tree and a dense input grid. -- Added copy constructors to the - @vdblink::Grid::Grid(const Grid&) Grid@endlink, - @vdblink::tree::Tree::Tree(const Tree&) Tree@endlink, - @vdblink::tree::RootNode::RootNode(const RootNode&) - RootNode@endlink, - @vdblink::tree::InternalNode::InternalNode(const InternalNode&) - InternalNode@endlink and - @vdblink::tree::LeafNode::LeafNode(const LeafNode&) LeafNode@endlink - classes, and an assignment operator overload to - @vdblink::tree::RootNode::operator=(const RootNode&) - RootNode@endlink, that allow the source and destination to have different - value types. -- Modified @vdblink::tree::Tree::combine2() Tree::combine2@endlink to permit - combination of trees with different value types. -- Added @vdblink::CanConvertType CanConvertType@endlink and - @vdblink::tree::RootNode::SameConfiguration - RootNode::SameConfiguration@endlink metafunctions, which perform compile-time - tests for value type and tree type compatibility, and a - @vdblink::tree::RootNode::hasCompatibleValueType() - RootNode::hasCompatibleValueType@endlink method, which does runtime checking. -- Added optional support for logging using - log4cplus. - See logging.h and the @c INSTALL file for details. -- Added @vdblink::tools::VolumeRayIntersector::hits() - VolumeRayIntersector::hits@endlink, which returns all the hit segments - along a ray. This is generally more efficient than repeated calls to - @vdblink::tools::VolumeRayIntersector::march() - VolumeRayIntersector::march@endlink. -- Added member class @vdblink::math::Ray::TimeSpan Ray::TimeSpan@endlink - and method @vdblink::math::Ray::valid() Ray::valid@endlink, and deprecated - method @vdblink::math::Ray::test() Ray::test@endlink. -- Fixed a bug in @vdblink::math::VolumeHDDA VolumeHDDA@endlink that could - cause rendering artifacts when a ray’s start time was zero. - [Contributed by Mike Farnsworth] -- Added a @vdblink::tools::compositeToDense() compositeToDense@endlink tool, - which composites data from a sparse tree into a dense array, using a - sparse alpha mask. Over, Add, Sub, Min, Max, Mult, and Set are - supported operations. -- Added a @vdblink::tools::transformDense() transformDense@endlink tool, - which applies a functor to the value of each voxel of a dense grid - within a given bounding box. -- Improved the performance of node iterators. - -@par -API changes: -- Collected the digital differential analyzer code from math/Ray.h - and tools/RayIntersector.h into a new header file, math/DDA.h. -- Rewrote @vdblink::math::VolumeHDDA VolumeHDDA@endlink and made several - changes to its API. (@vdblink::math::VolumeHDDA VolumeHDDA@endlink - is used internally by @vdblink::tools::VolumeRayIntersector - VolumeRayIntersector@endlink, whose API is unchanged.) -- @vdblink::tree::Tree::combine2() Tree::combine2@endlink, - @vdblink::tree::RootNode::combine2() RootNode::combine2@endlink, - @vdblink::tree::InternalNode::combine2() InternalNode::combine2@endlink, - @vdblink::tree::LeafNode::combine2() LeafNode::combine2@endlink - and @vdblink::CombineArgs CombineArgs@endlink all now require an additional - template argument, which determines the type of the other tree. -- Assignment operators for - @vdblink::tree::LeafManager::LeafRange::Iterator::operator=() - LeafManager::LeafRange::Iterator@endlink, - @vdblink::util::BaseMaskIterator::operator=() BaseMaskIterator@endlink, - @vdblink::util::NodeMask::operator=() NodeMask@endlink and - @vdblink::util::RootNodeMask::operator=() RootNodeMask@endlink - now return references to the respective objects. -- Removed a number of methods that were deprecated in version 2.0.0 - or earlier. - -@par -Houdini: -- Added a Clip SOP, which does volumetric clipping. -- Added an Occlusion Mask SOP, which generates a mask of the voxels - inside a camera frustum that are occluded by objects in an input grid. -- The Combine SOP now applies the optional signed flood fill only to - level set grids, since that operation isn’t meaningful for other grids. -- The Filter SOP now processes all grid types, not just scalar grids. - - -@htmlonly @endhtmlonly -@par -Version 2.2.0 - February 20, 2014 -- Added a simple, multithreaded - @vdblink::tools::VolumeRender volume renderer@endlink, - and added volume rendering support to the @c vdb_render - command-line renderer. -- Added an option to the - @vdblink::tools::LevelSetRayIntersector LevelSetRayIntersector@endlink - and to @c vdb_render to specify the isovalue of the level set. -- Added methods to the - @vdblink::tools::LevelSetRayIntersector LevelSetRayIntersector@endlink - to return the time of intersection along a world or index ray and to - return the level set isovalue. -- Improved the performance of the - @vdblink::tools::VolumeRayIntersector VolumeRayIntersector@endlink - and added support for voxel dilation to account for interpolation kernels. -- Added a @ref sInterpolation "section" to the Cookbook on interpolation - using @vdblink::tools::BoxSampler BoxSampler@endlink, - @vdblink::tools::GridSampler GridSampler@endlink, - @vdblink::tools::DualGridSampler DualGridSampler@endlink, et al. -- Added a @ref secGrid "section" to the Overview on grids and grid metadata. -- Modified @vdblink::tools::DualGridSampler DualGridSampler@endlink so - it is more consistent with @vdblink::tools::GridSampler GridSampler@endlink. -- The @vdblink::tools::cpt() cpt@endlink, @vdblink::tools::curl() curl@endlink, - @vdblink::tools::laplacian() laplacian@endlink, - @vdblink::tools::meanCurvature() meanCurvature@endlink - and @vdblink::tools::normalize() normalize@endlink tools now output grids - with appropriate @vdblink::VecType vector types@endlink - (covariant, contravariant, etc.). -- Added a @vdblink::tools::transformVectors() transformVectors@endlink tool, - which applies an affine transformation to the voxel values of a - vector-valued grid in accordance with the grid’s - @vdblink::VecType vector type@endlink and - @vdblink::Grid::isInWorldSpace() world space/local space@endlink setting. -- Added a @vdblink::tools::compDiv() compDiv@endlink tool, which combines - grids by dividing the values of corresponding voxels. -- Fixed a bug in the mean curvature computation that could produce NaNs - in regions with constant values. -- Added a - @vdblink::Grid::topologyDifference() Grid::topologyDifference@endlink method. -- Added @vdblink::math::Vec3::exp() exp@endlink and - @vdblink::math::Vec3::sum() sum@endlink methods to - @vdblink::math::Vec2 Vec2@endlink, @vdblink::math::Vec3 Vec3@endlink - and @vdblink::math::Vec4 Vec4@endlink. -- Improved the @vdblink::tools::fillWithSpheres() fillWithSpheres@endlink - tool for small volumes that are just a few voxels across. -- Improved the accuracy of the mesh to volume converter. -- Fixed a bug in the mesh to volume converter that caused incorrect sign - classifications for narrow-band level sets. -- Fixed a bug in @vdblink::math::NonlinearFrustumMap::applyIJT() - NonlinearFrustumMap::applyIJT@endlink that resulted in incorrect values - when computing the gradient of a grid with a frustum transform. -- Fixed a file I/O bug whereby some .vdb files could not be read - correctly if they contained grids with more than two distinct inactive - values. -- Fixed an off-by-one bug in the numbering of unnamed grids in .vdb - files. The first unnamed grid in a file is now retrieved using the name - “[0]”, instead of “[1]”. -- Fixed a build issue reported by Clang 3.2 in tools/GridOperators.h. -- Fixed a memory leak in @vdblink::tools::Film Film@endlink. -- Added library and file format version number constants to the Python module. -- Improved convergence in the - @vdblink::tools::VolumeRender volume renderer@endlink. - [Contributed by Jerry Tessendorf and Mark Matthews] -- Made various changes for compatibility with Houdini 13 and with - C++11 compilers. - [Contributed by SESI] - -@par -API changes: -- @vdblink::tools::VolumeRayIntersector::march() - VolumeRayIntersector::march@endlink no longer returns an @c int - to distinguish tile vs. voxel hits. Instead, it now returns @c false - if no intersection is detected and @c true otherwise. Also, @e t0 and - @e t1 might now correspond to the first and last hits of multiple adjacent - leaf nodes and/or active tiles. -- @vdblink::tools::DualGridSampler DualGridSampler@endlink is no longer - templated on the target grid type, and the value accessor is now passed - as an argument. -- The .vdb file format has changed slightly. Tools built with older - versions of OpenVDB should be recompiled to ensure that they can read files - in the new format. - -@par -Houdini: -- Added topology union, intersection and difference operations to - the Combine SOP. These operations combine the active voxel topologies - of grids that may have different value types. -- Added a Divide operation to the Combine SOP. -- Added support for boolean grids to the Combine, Resample, Scatter, Prune - and Visualize SOPs. -- The Fill SOP now accepts a vector as the fill value, and it allows - the fill region bounds to be specified either in index space (as before), - in world space, or using the bounds of geometry connected to an optional - new reference input. -- Added a toggle to the Offset Level Set SOP to specify the offset in - either world or voxel units. -- Added a toggle to the Transform and Resample SOPs to apply the transform - to the voxel values of vector-valued grids, in accordance with those - grids’ @vdblink::VecType vector types@endlink and - @vdblink::Grid::isInWorldSpace() world space/local space@endlink settings. -- Added a Vector Type menu to the Vector Merge SOP. -- Removed masking options from the Renormalize SOP (since masking is - not supported yet). -- Reimplemented the Vector Merge SOP for better performance and - interruptibility and to fix a bug in the handling of tile values. - - -@htmlonly @endhtmlonly -@par -Version 2.1.0 - December 12, 2013 -- Added a small number of Maya nodes, primarily for conversion of geometry - to and from OpenVDB volumes and for visualization of volumes. -- Added an initial implementation of - @vdblink::tools::LevelSetMorphing level set morphing@endlink - (with improvements to follow soon). -- Added @vdblink::tools::LevelSetMeasure tools::LevelSetMeasure@endlink, - which efficiently computes the surface area, volume and average - mean-curvature of narrow-band level sets, in both world and voxel units. - Those quantities are now exposed as intrinsic attributes on the Houdini - VDB primitive and can be queried using the native Measure SOP. -- @vdblink::tools::Dense tools::Dense@endlink now supports the XYZ memory - layout used by Houdini and Maya in addition to the ZYX layout used in - OpenVDB trees. -- Improved the performance of masking in the - @vdblink::tools::LevelSetFilter level set filter@endlink tool and - added inversion and scaling of the mask input, so that any scalar-valued - volume can be used as a mask, not just volumes with a [0, 1] range. -- Added optional masking to the non-level-set filters, to the grid - operators (CPT, curl, divergence, gradient, Laplacian, mean curvature, - magnitude, and normalize) and to the Analysis and Filter SOPs. -- Added more narrow band controls to the Rebuild Level Set SOP. -- Improved the accuracy of the - @vdblink::tools::levelSetRebuild() level set rebuild@endlink tool. -- Added @vdblink::tools::activate() tools::activate@endlink and - @vdblink::tools::deactivate() tools::deactivate@endlink, which set the - active states of tiles and voxels whose values are equal to or approximately - equal to a given value, and added a Deactivate Background Voxels toggle - to the Combine SOP. -- Added @vdblink::math::BBox::applyMap() BBox::applyMap@endlink and - @vdblink::math::BBox::applyInverseMap() BBox::applyInverseMap@endlink, - which allow for transformation of axis-aligned bounding boxes. -- Added a @vdblink::tools::PositionShader position shader@endlink to the - level set ray-tracer (primarily for debugging purposes). -- Added an @vdblink::io::Queue io::Queue@endlink class that manages a - concurrent queue for asynchronous serialization of grids to files or streams. -- Fixed a bug in @vdblink::io::Archive io::Archive@endlink whereby writing - unnamed, instanced grids (i.e., grids sharing a tree) to a file rendered - the file unreadable. -- Fixed a bug in the @vdblink::tools::VolumeToMesh volume to mesh@endlink - converter that caused it to generate invalid polygons when the zero crossing - lay between active and inactive regions. -- Fixed a bug in the @vdblink::tools::UniformPointScatter point scatter@endlink - tool (and the Scatter SOP) whereby the last voxel always remained empty. -- Fixed a bug in the Read SOP that caused grids with the same name - to be renamed with a numeric suffix (e.g., “grid[1]” - “grid[2]”, etc.). -- Fixed some unit test failures on 64-bit Itanium machines. - -@par -API changes: -- The @vdblink::tools::Filter Filter@endlink tool is now templated on a - mask grid, and threading is controlled using a grain size, for consistency - with most of the other level set tools. -- The @vdblink::tools::LevelSetFilter LevelSetFilter@endlink tool is now - templated on a mask grid. -- All shaders now take a ray direction instead of a ray. - - -@htmlonly @endhtmlonly -@par -Version 2.0.0 - October 31, 2013 -- Added a @ref python "Python module" with functions for basic manipulation - of grids (but no tools, yet). -- Added ray intersector tools for efficient, hierarchical intersection - of rays with @vdblink::tools::LevelSetRayIntersector level-set@endlink - and @vdblink::tools::VolumeRayIntersector generic@endlink volumes. -- Added a @vdblink::math::Ray Ray@endlink class and a hierarchical - @vdblink::math::DDA Digital Differential Analyzer@endlink for fast - ray traversal. -- Added a fully multi-threaded @vdblink::tools::LevelSetRayTracer - level set ray tracer@endlink and - @vdblink::tools::PerspectiveCamera camera@endlink - @vdblink::tools::OrthographicCamera classes@endlink - that mimic Houdini’s cameras. -- Added a simple, command-line renderer (currently for level sets only). -- Implemented a new meshing scheme that produces topologically robust - two-manifold meshes and is twice as fast as the previous scheme. -- Implemented a new, topologically robust (producing two-manifold meshes) - level-set-based seamless fracture scheme. The new scheme eliminates - visible scarring seen in the previous implementation by subdividing - internal, nonplanar quads near fracture seams. In addition, - fracture seam points are now tagged, allowing them to be used - to drive pre-fracture dynamics such as local surface buckling. -- Improved the performance of @vdblink::tree::Tree::evalActiveVoxelBoundingBox() - Tree::evalActiveVoxelBoundingBox@endlink and - @vdblink::tree::Tree::activeVoxelCount() Tree::activeVoxelCount@endlink, - and significantly improved the performance of - @vdblink::tree::Tree::evalLeafBoundingBox() Tree::evalLeafBoundingBox@endlink - (by about 30x). -- Added a tool (and a Houdini SOP) that fills a volume with - adaptively-sized overlapping or non-overlapping spheres. -- Added a Ray SOP that can be used to perform geometry projections - using level-set ray intersections or closest-point queries. -- Added a @vdblink::tools::ClosestSurfacePoint tool@endlink that performs - accelerated closest surface point queries from arbitrary points in - world space to narrow-band level sets. -- Increased the speed of masked level set filtering by 20% for - the most common cases. -- Added @vdblink::math::BoxStencil math::BoxStencil@endlink, with support - for trilinear interpolation and gradient computation. -- Added @vdblink::tree::Tree::topologyIntersection() - Tree::topologyIntersection@endlink, which intersects a tree’s active - values with those of another tree, and - @vdblink::tree::Tree::topologyDifference() Tree::topologyDifference@endlink, - which performs topological subtraction of one tree’s active values - from another’s. In both cases, the ValueTypes of the two - trees need not be the same. -- Added @vdblink::tree::Tree::activeTileCount() Tree::activeTileCount@endlink, - which returns the number of active tiles in a tree. -- Added @vdblink::math::MinIndex() math::MinIndex@endlink and - @vdblink::math::MaxIndex() math::MaxIndex@endlink, which find the minimum - and maximum components of a vector without any branching. -- Added @vdblink::math::BBox::minExtent() BBox::minExtent@endlink, - which returns a bounding box’s shortest axis. -- The default @vdblink::math::BBox BBox@endlink constructor now - generates an invalid bounding box rather than an empty bounding box - positioned at the origin. The new behavior is consistent with - @vdblink::math::CoordBBox CoordBBox@endlink. - [Thanks to Rick Hankins for suggesting this fix.] -- Added @vdblink::math::CoordBBox::reset() CoordBBox::reset@endlink, - which resets a bounding box to its initial, invalid state. -- Fixed a bug in the default @vdblink::math::ScaleMap ScaleMap@endlink - constructor that left some data used in the inverse uninitialized. -- Added @vdblink::math::MapBase::applyJT MapBase::applyJT@endlink, which - applies the Jacobian transpose to a vector (the Jacobian transpose takes - a range-space vector to a domain-space vector, e.g., world to index), - and added @vdblink::math::MapBase::inverseMap() MapBase::inverseMap@endlink, - which returns a new map representing the inverse of the original map - (except for @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink, - which does not currently have a defined inverse map). -
@b Note: Houdini 12.5 uses an earlier version of OpenVDB, and maps - created with that version lack virtual table entries for these - new methods, so do not call these methods from Houdini 12.5. -- Reimplemented @vdblink::math::RandomInt math::RandomInt@endlink using - Boost.Random instead of @c rand() (which is not thread-safe), and deprecated - @c math::randUniform() and added - @vdblink::math::Random01 math::Random01@endlink to replace it. -- Modified @vdblink::tools::copyFromDense() tools::copyFromDense@endlink - and @vdblink::tools::copyToDense() tools::copyToDense@endlink to allow - for implicit type conversion (e.g., between a - @vdblink::tools::Dense Dense<Int32>@endlink and a - @vdblink::FloatTree FloatTree@endlink) and fixed several bugs - in @vdblink::tools::CopyFromDense tools::CopyFromDense@endlink. -- Fixed bugs in @vdblink::math::Stats math::Stats@endlink and - @vdblink::math::Histogram math::Histogram@endlink that could produce - NaNs or other incorrect behavior if certain methods were called - on populations of size zero. -- Renamed struct tolerance to - @vdblink::math::Tolerance math::Tolerance@endlink - and @c negative to @vdblink::math::negative() math::negative@endlink - and removed @c math::toleranceValue(). -- Implemented a closest point on line segment algorithm, - @vdblink::math::closestPointOnSegmentToPoint() - math::closestPointOnSegmentToPoint@endlink. -- Fixed meshing issues relating to masking and automatic partitioning. -- @vdblink::Grid::merge() Grid::merge@endlink and - @vdblink::tree::Tree::merge() Tree::merge@endlink now accept an optional - @vdblink::MergePolicy MergePolicy@endlink argument that specifies one of - three new merging schemes. (The old merging scheme, which is no longer - available, used logic for each tree level that was inconsistent with - the other levels and that could result in active tiles being replaced - with nodes having only inactive values.) -- Renamed @c LeafNode::coord2offset(), @c LeafNode::offset2coord() and - @c LeafNode::offset2globalCoord() to - @vdblink::tree::LeafNode::coordToOffset() coordToOffset@endlink, - @vdblink::tree::LeafNode::offsetToLocalCoord() offsetToLocalCoord@endlink, - and @vdblink::tree::LeafNode::offsetToGlobalCoord() - offsetToGlobalCoord@endlink, respectively, and likewise for - @vdblink::tree::InternalNode::offsetToGlobalCoord() InternalNode@endlink. - [Thanks to Rick Hankins for suggesting this change.] -- Replaced @vdblink::tree::Tree Tree@endlink methods @c setValueOnMin, - @c setValueOnMax and @c setValueOnSum with - @vdblink::tools::setValueOnMin() tools::setValueOnMin@endlink, - @vdblink::tools::setValueOnMax() tools::setValueOnMax@endlink and - @vdblink::tools::setValueOnSum() tools::setValueOnSum@endlink - (and a new @vdblink::tools::setValueOnMult() tools::setValueOnMult@endlink) - and added @vdblink::tree::Tree::modifyValue() Tree::modifyValue@endlink - and @vdblink::tree::Tree::modifyValueAndActiveState() - Tree::modifyValueAndActiveState@endlink, which modify voxel values - in-place via user-supplied functors. Similarly, replaced - @c ValueAccessor::setValueOnSum() with - @vdblink::tree::ValueAccessor::modifyValue() - ValueAccessor::modifyValue@endlink - and @vdblink::tree::ValueAccessor::modifyValueAndActiveState() - ValueAccessor::modifyValueAndActiveState@endlink, and added a - @vdblink::tree::TreeValueIteratorBase::modifyValue() modifyValue@endlink - method to all value iterators. -- Removed @c LeafNode::addValue and @c LeafNode::scaleValue. -- Added convenience classes @vdblink::tree::Tree3 tree::Tree3@endlink and - @vdblink::tree::Tree5 tree::Tree5@endlink for custom tree configurations. -- Added an option to the From Particles SOP to generate an alpha mask, - which can be used to constrain level set filtering so as to preserve - surface details. -- The mesh to volume converter now handles point-degenerate polygons. -- Fixed a bug in the Level Set Smooth, Level Set Renormalize and - Level Set Offset SOPs that caused the group name to be ignored. -- Fixed various OS X and Windows build issues. - [Contributions from SESI and DD] - - -@htmlonly @endhtmlonly -@par -Version 1.2.0 - June 28 2013 -- @vdblink::tools::LevelSetFilter Level set filters@endlink now accept - an optional alpha mask grid. -- Implemented sharp feature extraction for level set surfacing. - This enhances the quality of the output mesh and reduces aliasing - artifacts. -- Added masking options to the meshing tools, as well as a spatial - multiplier for the adaptivity threshold, automatic partitioning, - and the ability to preserve edges and corners when mesh adaptivity - is applied. -- The mesh to volume attribute transfer scheme now takes surface - orientation into account, which improves accuracy in proximity to - edges and corners. -- Added a @vdblink::tree::LeafManager::foreach() foreach@endlink method - to @vdblink::tree::LeafManager tree::LeafManager@endlink that, like - @vdblink::tools::foreach() tools::foreach@endlink, applies a user-supplied - functor to each leaf node in parallel. -- Rewrote the particle to level set converter, simplifying the API, - improving performance (especially when particles have a fixed radius), - adding the capability to transfer arbitrary point attributes, - and fixing a velocity trail bug. -- Added utility methods @vdblink::math::Sign() Sign@endlink, - @vdblink::math::SignChange() SignChange@endlink, - @vdblink::math::isApproxZero() isApproxZero@endlink, - @vdblink::math::Cbrt() Cbrt@endlink and - @vdblink::math::ZeroCrossing() ZeroCrossing@endlink to math/Math.h. -- Added a @vdblink::tree::ValueAccessor3::probeNode() probeNode@endlink method - to the value accessor and to tree nodes that returns a pointer to the node - that contains a given voxel. -- Deprecated @c LeafNode::addValue and @c LeafNode::scaleValue. -- Doubled the speed of the mesh to volume converter (which also improves - the performance of the fracture and level set rebuild tools) and - improved its inside/outside voxel classification near edges and corners. -- @vdblink::tools::GridSampler GridSampler@endlink now accepts either a grid, - a tree or a value accessor, and it offers faster index-based access methods - and much better performance in cases where many instances are allocated. -- Extended @vdblink::tools::Dense tools::Dense@endlink to make it more - compatible with existing tools. -- Fixed a crash in @vdblink::io::Archive io::Archive@endlink whenever - the library was unloaded from memory and then reloaded. - [Contributed by Ollie Harding] -- Fixed a bug in @c GU_PrimVDB::buildFromPrimVolume(), seen during the - conversion from Houdini volumes to OpenVDB grids, that could cause - signed flood fill to be applied to non-level set grids, resulting in - active tiles with incorrect values. -- Added a Prune SOP with several pruning schemes. - - -@htmlonly @endhtmlonly -@par -Version 1.1.1 - May 10 2013 -- Added a simple @vdblink::tools::Dense dense grid class@endlink and tools - to copy data from dense voxel arrays into OpenVDB grids and vice-versa. -- Starting with Houdini 12.5.396, plugins built with this version - of OpenVDB can coexist with native Houdini OpenVDB nodes. -- The level set fracture tool now smooths seam line edges during - mesh extraction, eliminating staircase artifacts. -- Significantly improved the performance of the - @vdblink::util::leafTopologyIntersection() - leafTopologyIntersection@endlink and - @vdblink::util::leafTopologyDifference() leafTopologyDifference@endlink - utilities and added a @vdblink::tree::LeafNode::topologyDifference() - LeafNode::topologyDifference@endlink method. -- Added convenience functions that provide simplified interfaces - to the @vdblink::tools::meshToLevelSet() mesh to volume@endlink - and @vdblink::tools::volumeToMesh() volume to mesh@endlink converters. -- Added a @vdblink::tools::accumulate() tools::accumulate@endlink function - that is similar to @vdblink::tools::foreach() tools::foreach@endlink - but can be used to accumulate the results of computations over the values - of a grid. -- Added @vdblink::tools::statistics() tools::statistics@endlink, - @vdblink::tools::opStatistics() tools::opStatistics@endlink and - @vdblink::tools::histogram() tools::histogram@endlink, which efficiently - compute statistics (mean, variance, etc.) and histograms of grid values - (using @vdblink::math::Stats math::Stats@endlink and - @vdblink::math::Histogram math::Histogram@endlink). -- Modified @vdblink::math::CoordBBox CoordBBox@endlink to adhere to - TBB’s splittable type requirements, so that, for example, - a @c CoordBBox can be used as a blocked iteration range. -- Added @vdblink::tree::Tree::addTile() Tree::addTile@endlink, - @vdblink::tree::Tree::addLeaf() Tree::addLeaf@endlink and - @vdblink::tree::Tree::stealNode() Tree::stealNode@endlink, for fine - control over tree construction. -- Addressed a numerical stability issue when performing Gaussian - filtering of level set grids. -- Changed the return type of @vdblink::math::CoordBBox::volume() - CoordBBox::volume@endlink to reduce the risk of overflow. -- When the input mesh is self-intersecting, the mesh to volume converter - now produces a level set with a monotonic gradient field. -- Fixed a threading bug in the mesh to volume converter that caused it - to produce different results for the same input. -- Fixed a bug in the particle to level set converter that prevented - particles with zero velocity from being rasterized in Trail mode. -- Added an optional input to the Create SOP into which to merge - newly-created grids. -- Fixed a bug in the Resample SOP that caused it to produce incorrect - narrow-band widths when resampling level set grids. -- Fixed a bug in the To Polygons SOP that caused intermittent crashes - when the optional reference input was connected. -- Fixed a bug in the Advect Level Set SOP that caused a crash - when the velocity input was connected but empty. -- The Scatter and Sample Point SOPs now warn instead of erroring - when given empty grids. -- Fixed a crash in @c vdb_view when stepping through multiple grids - after changing render modes. -- @c vdb_view can now render fog volumes and vector fields, and it now - features interactively adjustable clipping planes that enable - one to view the interior of a volume. - - -@htmlonly @endhtmlonly -@par -Version 1.1.0 - April 4 2013 -- The @vdblink::tools::resampleToMatch() resampleToMatch@endlink tool, - the Resample SOP and the Combine SOP now use level set rebuild to correctly - and safely resample level sets. Previously, scaling a level set would - invalidate the signed distance field, leading to holes and other artifacts. -- Added a mask-based topological - @vdblink::tools::erodeVoxels erosion tool@endlink, and rewrote and - simplified the @vdblink::tools::dilateVoxels dilation tool@endlink. -- The @vdblink::tools::LevelSetAdvection LevelSetAdvection@endlink tool - can now advect forward or backward in time. -- Tree::pruneLevelSet() now replaces each pruned node with a tile having - the inside or outside - background value, instead of arbitrarily selecting one of the node’s - tile or voxel values. -- When a grid is saved to a file with - @vdblink::Grid::saveFloatAsHalf() saveFloatAsHalf@endlink set to @c true, - the grid’s background value is now also quantized to 16 bits. - (Not quantizing the background value caused a mismatch with the values - of background tiles.) -- As with @vdblink::tools::foreach() tools::foreach@endlink, it is now - possible to specify whether functors passed to - @vdblink::tools::transformValues() tools::transformValues@endlink - should be shared across threads. -- @vdblink::tree::LeafManager tree::LeafManager@endlink can now be - instantiated with a @const tree, although buffer swapping with @const trees - is disabled. -- Added a @vdblink::Grid::signedFloodFill() Grid::signedFloodFill@endlink - overload that allows one to specify inside and outside values. -- Fixed a bug in Grid::setBackground() so that now only the values of - inactive voxels change. -- Fixed @vdblink::Grid::topologyUnion() Grid::topologyUnion@endlink so that - it actually unions tree topology, instead of just the active states - of tiles and voxels. The previous behavior broke multithreaded code - that relied on input and output grids having compatible tree topology. -- @vdblink::math::Transform math::Transform@endlink now includes an - @vdblink::math::Transform::isIdentity() isIdentity@endlink predicate - and methods to @vdblink::math::Transform::preMult(const Mat4d&) pre-@endlink - and @vdblink::math::Transform::postMult(const Mat4d&) postmultiply@endlink - by a matrix. -- Modified the @link NodeMasks.h node mask@endlink classes to permit - octree-like tree configurations (i.e., with a branching factor of two) - and to use 64-bit operations instead of 32-bit operations. -- Implemented a new, more efficient - @vdblink::math::closestPointOnTriangleToPoint() closest point - on triangle@endlink algorithm. -- Implemented a new vertex normal scheme in the volume to mesh - converter, and resolved some overlapping polygon issues. -- The volume to mesh converter now meshes not just active voxels - but also active tiles. -- Fixed a bug in the mesh to volume converter that caused unsigned - distance field conversion to produce empty grids. -- Fixed a bug in the level set fracture tool whereby the cutter overlap - toggle was ignored. -- Fixed an infinite loop bug in @c vdb_view. -- Updated @c vdb_view to use the faster and less memory-intensive - OpenVDB volume to mesh converter instead of marching cubes, - and rewrote the shader to be OpenGL 3.2 and GLSL 1.2 compatible. -- Given multiple input files or a file containing multiple grids, - @c vdb_view now displays one grid at a time. The left and right - arrow keys cycle between grids. -- The To Polygons SOP now has an option to associate the input grid’s - name with each output polygon. - - -@htmlonly @endhtmlonly -@par -Version 1.0.0 - March 14 2013 -- @vdblink::tools::levelSetRebuild() tools::levelSetRebuild@endlink - now throws an exception when given a non-scalar or non-floating-point grid. -- The tools in tools/GridOperators.h are now interruptible, as is - the Analysis SOP. -- Added a - @vdblink::tree::LeafManager::LeafRange::Iterator leaf node iterator@endlink - and a TBB-compatible - @vdblink::tree::LeafManager::LeafRange range class@endlink - to the LeafManager. -- Modified the @vdblink::tools::VolumeToMesh VolumeToMesh@endlink tool - to handle surface topology issues around fracture seam lines. -- Modified the Makefile to allow @c vdb_view to compile on OS X systems - (provided that GLFW is available). -- Fixed a bug in the Create SOP that resulted in "invalid parameter name" - warnings. -- The Combine SOP now optionally resamples the A grid into the B grid’s - index space (or vice-versa) if the A and B transforms differ. -- The Vector Split and Vector Merge SOPs now skip inactive voxels - by default, but they can optionally be made to include inactive voxels, - as they did before. -- The @vdblink::tools::LevelSetFracture LevelSetFracture@endlink tool now - supports custom rotations for each cutter instance, and the Fracture SOP - now uses quaternions to generate uniformly-distributed random rotations. - - -@htmlonly @endhtmlonly -@par -Version 0.104.0 - February 15 2013 -- Added a @vdblink::tools::levelSetRebuild() tool@endlink and a SOP - to rebuild a level set from any scalar volume. -- @c .vdb files are now saved using a mask-based compression scheme - that is an order of magnitude faster than ZLIB and produces comparable - file sizes for level set and fog volume grids. (ZLIB compression - is still enabled by default for other classes of grids). -- The @vdblink::tools::Filter Filter@endlink and - @vdblink::tools::LevelSetFilter LevelSetFilter@endlink tools now - include a Gaussian filter, and mean (box) filtering is now 10-50x faster. -- The isosurface @vdblink::tools::VolumeToMesh meshing tool@endlink - is now more robust (to level sets with one voxel wide narrow bands, - for example). -- Mesh to volume conversion is on average 1.5x faster and up to 5.5x - faster for high-resolution meshes where the polygon/voxel size ratio - is small. -- Added @vdblink::createLevelSet() createLevelSet@endlink and - @vdblink::createLevelSetSphere() createLevelSetSphere@endlink - factory functions for level set grids. -- @vdblink::tree::ValueAccessor tree::ValueAccessor@endlink is now faster - for trees of height 2, 3 and 4 (the latter is the default), and it now - allows one to specify, via a template argument, the number of node levels - to be cached, which can also improve performance in special cases. -- Added a toggle to @vdblink::tools::foreach() tools::foreach@endlink - to specify whether or not the functor should be shared across threads. -- Added @vdblink::Mat4SMetadata Mat4s@endlink and - @vdblink::Mat4DMetadata Mat4d@endlink metadata types. -- Added explicit pre- and postmultiplication methods to the @c Transform, - @c Map and @c Mat4 classes and deprecated the old accumulation methods. -- Modified @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink - to be more compatible with Houdini’s frustum transform. -- Fixed a @vdblink::tools::GridTransformer GridTransformer@endlink bug - that caused it to translate the output grid incorrectly in some cases. -- Fixed a bug in the tree-level - @vdblink::tree::LeafIteratorBase LeafIterator@endlink that resulted in - intermittent crashes in - @vdblink::tools::dilateVoxels() tools::dilateVoxels@endlink. -- The @c Hermite data type and Hermite grids are no longer supported. -- Added tools/GridOperators.h, which includes new, cleaner implementations - of the @vdblink::tools::cpt() closest point transform@endlink, - @vdblink::tools::curl() curl@endlink, - @vdblink::tools::divergence() divergence@endlink, - @vdblink::tools::gradient() gradient@endlink, - @vdblink::tools::laplacian() Laplacian@endlink, - @vdblink::tools::magnitude() magnitude@endlink, - @vdblink::tools::meanCurvature() mean curvature@endlink and - @vdblink::tools::normalize() normalize@endlink tools. -- Interrupt support has been improved in several tools, including - @vdblink::tools::ParticlesToLevelSet tools::ParticlesToLevelSet@endlink. -- Simplified the API of the @vdblink::math::BaseStencil Stencil@endlink class - and added an @vdblink::math::BaseStencil::intersects() intersects@endlink - method to test for intersection with a specified isovalue. -- Renamed @c voxelDimensions to @c voxelSize in transform classes - and elsewhere. -- Deprecated @c houdini_utils::ParmFactory::setChoiceList in favor of - @c houdini_utils::ParmFactory::setChoiceListItems, which requires - a list of token, label string pairs. -- Made various changes for Visual C++ compatibility. - [Contributed by SESI] -- Fixed a bug in @c houdini_utils::getNodeChain() that caused the - Offset Level Set, Smooth Level Set and Renormalize Level Set SOPs - to ignore frame changes. - [Contributed by SESI] -- The From Particles SOP now provides the option to write into - an existing grid. -- Added a SOP to edit grid metadata. -- The Fracture SOP now supports multiple cutter objects. -- Added a To Polygons SOP that complements the Fracture SOP and allows - for elimination of seam lines, generation of correct vertex normals - and grouping of polygons when surfacing fracture fragments, using - the original level set or mesh as a reference. - - -@htmlonly @endhtmlonly -@par -Version 0.103.1 - January 15 2013 -- @vdblink::tree::ValueAccessor tree::ValueAccessor@endlink read operations - are now faster for four-level trees. - (Preliminary benchmark tests suggest a 30-40% improvement.) -- For vector-valued grids, @vdblink::tools::compMin() tools::compMin@endlink - and @vdblink::tools::compMax() tools::compMax@endlink now compare - vector magnitudes instead of individual components. -- Migrated grid sampling code to a new file, Interpolation.h, - and deprecated old files and classes. -- Added a level-set @vdblink::tools::LevelSetFracture fracture tool@endlink - and a Fracture SOP. -- Added @vdblink::tools::sdfInteriorMask() tools::sdfInteriorMask@endlink, - which creates a mask of the interior region of a level set grid. -- Fixed a bug in the mesh to volume converter that produced unexpected - nonzero values for voxels at the intersection of two polygons, - and another bug that produced narrow-band widths that didn’t respect - the background value when the half-band width was less than three voxels. -- @c houdini_utils::ParmFactory can now correctly generate ramp multi-parms. -- Made various changes for Visual C++ compatibility. - [Contributed by SESI] -- The Convert SOP can now convert between signed distance fields and - fog volumes and from volumes to meshes. - [Contributed by SESI] -- For level sets, the From Mesh and From Particles SOPs now match - the reference grid’s narrow-band width. -- The Scatter SOP can now optionally scatter points in the interior - of a level set. - - -@htmlonly @endhtmlonly -@par -Version 0.103.0 - December 21 2012 -- The mesh to volume converter is now 60% faster at generating - level sets with wide bands, and the From Mesh SOP is now interruptible. -- Fixed a threading bug in the recently-added - @vdblink::tools::compReplace() compReplace@endlink tool - that caused it to produce incorrect output. -- Added a @vdblink::tree::Tree::probeConstLeaf() probeConstLeaf@endlink - method to the @vdblink::tree::Tree::probeConstLeaf() Tree@endlink, - @vdblink::tree::ValueAccessor::probeConstLeaf() ValueAccessor@endlink - and @vdblink::tree::RootNode::probeConstLeaf() node@endlink classes. -- The Houdini VDB primitive doesn’t create a @c name attribute - unnecessarily (i.e., if its grid’s name is empty), but it now - correctly allows the name to be changed to the empty string. -- Fixed a crash in the Vector Merge SOP when fewer than three grids - were merged. -- The From Particles SOP now features a "maximum half-width" parameter - to help avoid runaway computations. - - -@htmlonly @endhtmlonly -@par -Version 0.102.0 - December 13 2012 -- Added @vdblink::tools::compReplace() tools::compReplace@endlink, - which copies the active values of one grid into another, and added - a "Replace A With Active B" mode to the Combine SOP. -- @vdblink::Grid::signedFloodFill() Grid::signedFloodFill@endlink - no longer enters an infinite loop when filling an empty grid. -- Fixed a bug in the particle to level set converter that sometimes - produced level sets with holes, and fixed a bug in the SOP that - could result in random output. -- Fixed an issue in the frustum preview feature of the Create SOP - whereby rendering very large frustums could cause high CPU usage. -- Added streamline support to the constrained advection scheme - in the Advect Points SOP. -- Added an Advect Level Set SOP. - - -@htmlonly @endhtmlonly -@par -Version 0.101.1 - December 11 2012 (DWA internal release) -- Partially reverted the Houdini VDB primitive’s grid accessor methods - to their pre-0.98.0 behavior. A primitive’s grid can once again - be accessed by shared pointer, but now also by reference. - Accessor methods for grid metadata have also been added, and the - primitive now ensures that metadata and transforms are never shared. -- Fixed an intermittent crash in the From Particles SOP. - - -@htmlonly @endhtmlonly -@par -Version 0.101.0 - December 6 2012 (DWA internal release) -- Partially reverted the @vdblink::Grid Grid@endlink’s - @vdblink::Grid::tree() tree@endlink and - @vdblink::Grid::transform() transform@endlink accessor methods - to their pre-0.98.0 behavior, eliminating copy-on-write but - preserving their return-by-reference semantics. These methods - are now supplemented with a suite of - @vdblink::Grid::treePtr() shared@endlink - @vdblink::Grid::baseTreePtr() pointer@endlink - @vdblink::Grid::transformPtr() accessors@endlink. -- Restructured the @vdblink::tools::MeshToVolume - mesh to volume converter@endlink for a 40% speedup - and to be more robust to non-manifold geometry, to better preserve - sharp features, to support arbitrary tree configurations and - to respect narrow-band limits. -- Added a @c getNodeBoundingBox method to - @vdblink::tree::RootNode::getNodeBoundingBox() RootNode@endlink, - @vdblink::tree::InternalNode::getNodeBoundingBox() InternalNode@endlink - and @vdblink::tree::LeafNode::getNodeBoundingBox() LeafNode@endlink - that returns the index space spanned by a node. -- Made various changes for Visual C++ compatibility. - [Contributed by SESI] -- Renamed the Reshape Level Set SOP to Offset Level Set. -- Fixed a crash in the Convert SOP and added support for conversion - of empty grids. - - -@htmlonly @endhtmlonly -@par -Version 0.100.0 - November 30 2012 (DWA internal release) -- Greatly improved the performance of the level set to fog volume - @vdblink::tools::sdfToFogVolume() converter@endlink. -- Improved the performance of the - @vdblink::tools::Filter::median() median filter@endlink - and of level set @vdblink::tools::csgUnion() CSG@endlink operations. -- Reintroduced Tree::pruneLevelSet(), a specialized Tree::pruneInactive() - for level-set grids. -- Added utilities to the @c houdini_utils library to facilitate the - collection of a chain of adjacent nodes of a particular type - so that they can be cooked in a single step. (For example, - adjacent @c xform SOPs could be collapsed by composing their - transformation matrices into a single matrix.) -- Added pruning and flood-filling options to the Convert SOP. -- Reimplemented the Filter SOP, omitting level-set-specific filters - and adding node chaining (to reduce memory usage when applying - several filters in sequence). -- Added a toggle to the Read SOP to read grid metadata and - transforms only. -- Changed the attribute transfer scheme on the From Mesh and - From Particles SOPs to allow for custom grid names and - vector type metadata. - - -@htmlonly @endhtmlonly -@par -Version 0.99.0 - November 21 2012 -- Added @vdblink::Grid Grid@endlink methods that return non-const - tree and transform references without triggering deep copies, - as well as @c const methods that return @c const shared pointers. -- Added @c Grid methods to @vdblink::Grid::addStatsMetadata populate@endlink - a grid’s metadata with statistics like the active voxel count, and to - @vdblink::Grid::getStatsMetadata retrieve@endlink that metadata. - By default, statistics are now computed and added to grids - whenever they are written to .vdb files. -- Added @vdblink::io::File::readGridMetadata io::File::readGridMetadata@endlink - and @vdblink::io::File::readAllGridMetadata - io::File::readAllGridMetadata@endlink methods to read just the - grid metadata and transforms from a .vdb file. -- Fixed numerical precision issues in the - @vdblink::tools::csgUnion csgUnion@endlink, - @vdblink::tools::csgIntersection csgIntersection@endlink - and @vdblink::tools::csgDifference csgDifference@endlink - tools, and added toggles to optionally disable postprocess pruning. -- Fixed an issue in @c vdb_view with the ordering of GL vertex buffer calls. - [Contributed by Bill Katz] -- Fixed an intermittent crash in the - @vdblink::tools::ParticlesToLevelSet ParticlesToLevelSet@endlink tool, - as well as a race condition that could cause data corruption. -- The @c ParticlesToLevelSet tool and From Particles SOP can now transfer - arbitrary point attribute values from the input particles to output voxels. -- Fixed a bug in the Convert SOP whereby the names of primitives - were lost during conversion, and another bug that resulted in - arithmetic errors when converting empty grids. -- Fixed a bug in the Combine SOP that caused the Operation selection - to be lost. - - -@htmlonly @endhtmlonly -@par -Version 0.98.0 - November 16 2012 -- @vdblink::tree::Tree Tree@endlink and - @vdblink::math::Transform Transform@endlink objects (and - @vdblink::Grid Grid@endlink objects in the context of Houdini SOPs) - are now passed and accessed primarily by reference rather than by - shared pointer. See @subpage api_0_98_0 "Porting to OpenVDB 0.98.0" - for details about this important API change. - [Contributed by SESI] -- Reimplemented @vdblink::math::CoordBBox CoordBBox@endlink to address several - off-by-one bugs related to bounding box dimensions. -- Fixed an off-by-one bug in @vdblink::Grid::evalActiveVoxelBoundingBox() - evalActiveVoxelBoundingBox@endlink. -- Introduced the @vdblink::tree::LeafManager LeafManager@endlink class, - which will eventually replace the @c LeafArray class. @c LeafManager supports - dynamic buffers stored as a structure of arrays (SOA), unlike @c LeafArray, - which supports only static buffers stored as an array of structures (AOS). -- Improved the performance of the - @vdblink::tools::LevelSetFilter LevelSetFilter@endlink and - @vdblink::tools::LevelSetTracker LevelSetTracker@endlink tools by rewriting - them to use the new @vdblink::tree::LeafManager LeafManager@endlink class. -- Added @vdblink::tree::Tree::setValueOnly() Tree::setValueOnly@endlink and - @vdblink::tree::ValueAccessor::setValueOnly() - ValueAccessor::setValueOnly@endlink methods, which change the value of - a voxel without changing its active state, and - @vdblink::tree::Tree::probeLeaf() Tree::probeLeaf@endlink and - @vdblink::tree::ValueAccessor::probeLeaf() ValueAccessor::probeLeaf@endlink - methods that return the leaf node that contains a given voxel (unless - the voxel is represented by a tile). -- Added a @vdblink::tools::LevelSetAdvection LevelSetAdvection@endlink tool - that propagates and tracks narrow-band level sets. -- Introduced a new @vdblink::tools::GridSampler GridSampler@endlink class - that supports world-space (or index-space) sampling of grid values. -- Changed the interpretation of the - @vdblink::math::NonlinearFrustumMap NonlinearFrustumMap@endlink’s - @em taper parameter to be the ratio of the near and far plane depths. -- Added a @c ParmFactory::setChoiceList() overload that accepts - (@em token, @em label) string pairs, and a @c setDefault() overload that - accepts an STL string. -- Fixed a crash in the Combine SOP in Copy B mode. -- Split the Level Set Filter SOP into three separate SOPs, - Level Set Smooth, Level Set Reshape and Level Set Renormalize. - When two or more of these nodes are connected in sequence, they interact - to reduce memory usage: the last node in the sequence performs - all of the operations in one step. -- The Advect Points SOP can now output polyline streamlines - that trace the paths of the points. -- Added an option to the Analysis SOP to specify names for output grids. -- Added camera-derived frustum transform support to the Create SOP. - - -@htmlonly @endhtmlonly -@par -Version 0.97.0 - October 18 2012 -- Added a narrow-band @vdblink::tools::LevelSetTracker level set - interface tracking tool@endlink (up to fifth-order in space but currently - only first-order in time, with higher temporal orders to be added soon). -- Added a @vdblink::tools::LevelSetFilter level set filter tool@endlink - to perform unrestricted surface smoothing (e.g., Laplacian flow), - filtering (e.g., mean value) and morphological operations (e.g., - morphological opening). -- Added adaptivity to the @vdblink::tools::VolumeToMesh - level set meshing tool@endlink for faster mesh extraction with fewer - polygons, without postprocessing. -- Added a @vdblink::tree::ValueAccessor::touchLeaf() - ValueAccessor::touchLeaf@endlink method that creates (if necessary) - and returns the leaf node containing a given voxel. It can be used - to preallocate leaf nodes over which to run parallel algorithms. -- Fixed a bug in @vdblink::Grid::merge() Grid::merge@endlink whereby - active tiles were sometimes lost. -- Added @vdblink::tree::LeafManager LeafManager@endlink, which is similar - to @c LeafArray but supports a dynamic buffer count and allocates buffers - more efficiently. Useful for temporal integration (e.g., for level set - propagation and interface tracking), @c LeafManager is meant to replace - @c LeafArray, which will be deprecated in the next release. -- Added a @vdblink::tree::LeafNode::fill() LeafNode::fill@endlink method - to efficiently populate leaf nodes with constant values. -- Added a @vdblink::tree::Tree::visitActiveBBox() Tree::visitActiveBBox@endlink - method that applies a functor to the bounding boxes of all active tiles - and leaf nodes and that can be used to improve the performance of - ray intersection tests, rendering of bounding boxes, etc. -- Added a @vdblink::tree::Tree::voxelizeActiveTiles() - Tree::voxelizeActiveTiles@endlink method to densify active tiles. - While convenient and fast, this can produce large dense grids, so use - it with caution. -- Repackaged @c Tree::pruneLevelSet() as a Tree::pruneOp()-compatible - functor. Tree::LevelSetPrune is a specialized Tree::pruneInactive - for level-set grids and is used in interface tracking. -- Added a GridBase::pruneGrid() method. -- Added a @vdblink::Grid::hasUniformVoxels() Grid:hasUniformVoxels@endlink - method. -- Renamed @c tools::dilate to - @vdblink::tools::dilateVoxels() dilateVoxels@endlink and improved its - performance. The new name reflects the fact that the current - implementation ignores active tiles. -- Added a @vdblink::tools::resampleToMatch() tools::resampleToMatch@endlink - function that resamples an input grid into an output grid with a - different transform such that, after resampling, the input and output grids - coincide, but the output grid’s transform is preserved. -- Significantly improved the performance of depth-bounded value - iterators (@vdblink::tree::Tree::ValueOnIter ValueOnIter@endlink, - @vdblink::tree::Tree::ValueAllIter ValueAllIter@endlink, etc.) - when the depth bound excludes leaf nodes. -- Exposed the value buffers inside leaf nodes with - @vdblink::tree::LeafNode::buffer() LeafNode::buffer@endlink. - This allows for very fast access (const and non-const) to voxel - values using linear array offsets instead of @ijk coordinates. -- In openvdb_houdini/UT_VDBTools.h, added operators for use with - @c processTypedGrid that resample grids in several different ways. -- Added a policy mechanism to @c houdini_utils::OpFactory that allows for - customization of operator names, icons, and Help URLs. -- Renamed many of the Houdini SOPs to make the names more consistent. -- Added an Advect Points SOP. -- Added a Level Set Filter SOP that allows for unrestricted surface - deformations, unlike the older Filter SOP, which restricts surface - motion to the initial narrow band. -- Added staggered vector sampling to the Sample Points SOP. -- Added a minimum radius threshold to the particle voxelization tool - and SOP. -- Merged the Composite and CSG SOPs into a single Combine SOP. -- Added a tool and a SOP to efficiently generate narrow-band level set - representations of spheres. -- In the Visualize SOP, improved the performance of tree topology - generation, which is now enabled by default. - - -@htmlonly @endhtmlonly -@par -Version 0.96.0 - September 24 2012 -- Fixed a memory corruption bug in the mesh voxelizer tool. -- Temporarily removed the optional clipping feature from the level set mesher. -- Added "Staggered Vector Field" to the list of grid classes in the Create SOP. - - -@htmlonly @endhtmlonly -@par -Version 0.95.0 - September 20 2012 -- Added a quad @vdblink::tools::VolumeToMesh meshing@endlink tool for - higher-quality level set meshing and updated the Visualizer SOP - to use it. -- Fixed a precision error in the @vdblink::tools::MeshToVolume - mesh voxelizer@endlink and improved the quality of inside/outside - voxel classification. Output grids are now also - @vdblink::Grid::setGridClass() classified@endlink as either level sets - or fog volumes. -- Modified the @vdblink::tools::GridResampler GridResampler@endlink - to use the signed flood fill optimization only on grids that are - tagged as level sets. -- Added a @vdblink::math::Quat quaternion@endlink class to the - math library and a method to return the - @vdblink::math::Mat3::trace trace@endlink of a @c Mat3. -- Fixed a bug in the - @vdblink::tree::ValueAccessor::ValueAccessor(const ValueAccessor&) - ValueAccessor@endlink copy constructor that caused the copy to reference - the original. -- Fixed a bug in @vdblink::tree::RootNode::setActiveState() - RootNode::setActiveState@endlink that caused a crash - when marking a (virtual) background voxel as inactive. -- Added a @c Tree::pruneLevelSet method that is similar to but faster than - Tree::pruneInactive() for level set grids. -- Added fast leaf node voxel access - @vdblink::tree::LeafNode::getValue(Index) const methods@endlink - that index by linear offset (as returned by - @vdblink::tree::LeafNode::ValueOnIter::pos() ValueIter::pos@endlink) - instead of by @ijk coordinates. -- Added a @vdblink::tree::Tree::touchLeaf() Tree::touchLeaf@endlink - method that can be used to preallocate a static tree topology over which - to safely perform multithreaded processing. -- Added a grain size argument to @c LeafArray for finer control of parallelism. -- Modified the Makefile to make it easier to omit the doc, - @c vdb_test and @c vdb_view targets. -- Added utility functions (in houdini/UT_VDBUtils.h) to convert - between Houdini and OpenVDB matrix and vector types. - [Contributed by SESI] -- Added accessors to @c GEO_PrimVDB that make it easier to directly access - voxel data and that are used by the HScript volume expression functions - in Houdini 12.5. [Contributed by SESI] -- As of Houdini 12.1.77, the native transform SOP operates on OpenVDB - primitives. [Contributed by SESI] -- Added a Convert SOP that converts OpenVDB grids to Houdini volumes - and vice-versa. - - -@htmlonly @endhtmlonly -@par -Version 0.94.1 - September 7 2012 -- Fixed bugs in @vdblink::tree::RootNode RootNode@endlink and - @vdblink::tree::InternalNode InternalNode@endlink @c setValue*() and - @c fill() methods that could cause neighboring voxels to become inactive. -- Fixed a bug in - @vdblink::tree::Tree::hasSameTopology() Tree::hasSameTopology@endlink - that caused false positives when only active states and not values differed. -- Added a @vdblink::tree::Tree::hasActiveTiles() Tree::hasActiveTiles@endlink - method. -- For better cross-platform consistency, substituted bitwise AND operations - for right shifts in the @vdblink::tree::ValueAccessor ValueAccessor@endlink - hash key computation. -- @c vdb_view no longer aborts when asked to surface a vector-valued - grid—but it still doesn’t render the surface. -- Made various changes for Visual C++ compatibility. - [Contributed by SESI] -- Added an option to the MeshVoxelizer SOP to convert both open and - closed surfaces to unsigned distance fields. -- The Filter SOP now allows multiple filters to be applied in - user-specified order. - - -@htmlonly @endhtmlonly -@par -Version 0.94.0 - August 30 2012 -- Added a @vdblink::Grid::topologyUnion() method@endlink to union - just the active states of voxels from one grid with those of - another grid of a possibly different type. -- Fixed an incorrect scale factor in the Laplacian diffusion - @vdblink::tools::Filter::laplacian() filter@endlink. -- Fixed a bug in @vdblink::tree::Tree::merge() Tree::merge@endlink - that could leave a tree with invalid value accessors. -- Added @vdblink::tree::TreeValueIteratorBase::setActiveState() - TreeValueIteratorBase::setActiveState@endlink and deprecated - @c setValueOn. -- Removed @c tools/FastSweeping.h. It will be replaced with a much more - efficient implementation in the near future. -- ZLIB compression of .vdb files is now optional, - but enabled by default. [Contributed by SESI] -- Made various changes for Clang and Visual C++ compatibility. - [Contributed by SESI] -- The MeshVoxelizer SOP can now transfer arbitrary point and primitive - attribute values from the input mesh to output voxels. - - -@htmlonly @endhtmlonly -@par -Version 0.93.0 - August 24 2012 -- Renamed symbols in math/Operators.h to avoid ambiguities that - GCC 4.4 reports as errors. -- Simplified the API for the stencil version of the - closest-point transform @vdblink::math::CPT operator@endlink. -- Added logic to - @vdblink::io::Archive::readGrid() io::Archive::readGrid@endlink - to set the grid name metadata from the descriptor if the metadata - doesn’t already exist. -- Added guards to prevent nesting of @c openvdb_houdini::Interrupter::start() - and @c end() calls. - - -@htmlonly @endhtmlonly -@par -Version 0.92.0 - August 23 2012 -- Added a Laplacian diffusion - @vdblink::tools::Filter::laplacian() filter@endlink. -- Fixed a bug in the initialization of the sparse contour tracer - that caused mesh-to-volume conversion to fail in certain cases. -- Fixed a bug in the curvature stencil that caused mean curvature - filtering to produce wrong results. -- Increased the speed of the - @vdblink::tools::GridTransformer GridTransformer@endlink - by as much as 20% for fog volumes. -- Added optional pruning to the Resample SOP. -- Modified the PointSample SOP to allow it to work with ungrouped, - anonymous grids. -- Fixed a crash in the LevelSetNoise SOP. - - -@htmlonly @endhtmlonly -@par -Version 0.91.0 - August 16 2012 -- @vdblink::tools::GridTransformer tools::GridTransformer@endlink - and @vdblink::tools::GridResampler tools::GridResampler@endlink - now correctly (but not yet efficiently) process tiles in sparse grids. -- Added an optional @vdblink::CopyPolicy CopyPolicy@endlink argument - to @vdblink::GridBase::copyGrid() GridBase::copyGrid@endlink - and to @vdblink::Grid::copy() Grid::copy@endlink that specifies - whether and how the grid’s tree should be copied. -- Added a @vdblink::GridBase::newTree() GridBase::newTree@endlink - method that replaces a grid’s tree with a new, empty tree of the - correct type. -- Fixed a crash in - @vdblink::tree::Tree::setValueOff(const Coord& xyz, const ValueType& value) - Tree::setValueOff@endlink when the new value was equal to the - background value. -- Fixed bugs in Tree::prune() that could result in output tiles with - incorrect active states. -- Added @c librt to the link dependencies to address build failures - on Ubuntu systems. -- Made various small changes to the Makefile and the source code - that should help with Mac OS X compatibility. -- The Composite and Resample SOPs now correctly copy the input grid’s - metadata to the output grid. - - -@htmlonly @endhtmlonly -@par -Version 0.90.1 - August 7 2012 -- Fixed a bug in the - @vdblink::math::BBox::getCenter() BBox::getCenter()@endlink method. -- Added missing header files to various files. -- @vdblink::io::File::NameIterator::gridName() - io::File::NameIterator::gridName()@endlink now returns a unique name - of the form "name[1]", "name[2]", etc. if a file - contains multiple grids with the same name. -- Fixed a bug in the Writer SOP that caused grid names to be discarded. -- The Resample SOP now correctly sets the background value of the - output grid. - - -@htmlonly @endhtmlonly -@par -Version 0.90.0 - August 3 2012 (initial public release) -- Added a basic GL viewer for OpenVDB files. -- Greatly improved the performance of two commonly-used @c Tree methods, - @vdblink::tree::Tree::evalActiveVoxelBoundingBox() - evalActiveVoxelBoundingBox()@endlink - and @vdblink::tree::Tree::memUsage() memUsage()@endlink. -- Eliminated the @c GridMap class. File I/O now uses STL containers - of grid pointers instead. -- Refactored stencil-based tools (Gradient, Laplacian, etc.) and rewrote - some of them for generality and better performance. Most now behave - correctly for grids with nonlinear index-to-world transforms. -- Added a @link FiniteDifference.h library@endlink of index-space finite - difference operators. -- Added a @vdblink::math::Hermite "Hermite"@endlink grid type that compactly - stores each voxel’s upwind normals and can be used to convert volumes - to and from polygonal meshes. -- Added a @link PointScatter.h tool@endlink (and a Houdini SOP) - to scatter points randomly throughout a volume. - -*/ diff --git a/openvdb_3_0_0_library/doc/codingstyle.txt b/openvdb_3_0_0_library/doc/codingstyle.txt deleted file mode 100755 index 6bdee03..0000000 --- a/openvdb_3_0_0_library/doc/codingstyle.txt +++ /dev/null @@ -1,289 +0,0 @@ -/** - -@page codingStyle Coding Style - -@section Introduction - -This document details the coding practices that are used in the OpenVDB -codebase. Contributed code should conform to these guidelines to maintain -consistency and maintainability. If there is a rule that you would like -clarified, changed, or added, please send a note to openvdb@gmail.com. - - -@section Contents -- @ref sNamingConventions - - @ref sNamespaceConventions - - @ref sClassConventions - - @ref sClassMethods - - @ref sClassInstanceVariables - - @ref sClassStaticVariables - - @ref sLocalVariablesAndArguments - - @ref sConstants - - @ref sEnumerationNames - - @ref sEnumerationValues - - @ref sTypedefs - - @ref sGlobalVariables - - @ref sGlobalFunctions - - @ref sBooleans -- @ref sPractices - - @ref sGeneral - - @ref sFormatting - - @ref sIncludeStatements - - @ref sComments - - @ref sPrimitiveTypes - - @ref sMacros - - @ref sClasses - - @ref sConditionalStatements - - @ref sNamespaces - - @ref sExceptions - - @ref sTemplates - - @ref sMiscellaneous - -@section sNamingConventions Naming Conventions - - -@subsection sNamespaceConventions Namespaces --# Lowercase words, keep simple and short (e.g., @c tools, @c tree). - - -@subsection sClassConventions Classes and Structs --# Mixed case; first letter uppercase (e.g., @c AffineMap, @c TreeIterator) --# Do not use a prefix. - - -@subsection sClassMethods Class Methods --# Mixed case; first letter lowercase (e.g., getAccessor(), gridType()) --# Accessors that return a member variable by reference or a primitive type -by value are just the variable name (e.g., Grid::tree()). --# Accessors that involve construction of objects or other computations are -@c get + the variable name (e.g., Grid::getAccessor()). --# Simple mutators are @c set + the variable name (e.g., Grid::setTree(tree);). - - -@subsection sClassInstanceVariables Class Instance Variables --# Mixed case; always prefixed by @c m (e.g., @c mTree, @c mTransform) - - -@subsection sClassStaticVariables Class Static Variables --# Mixed case; always prefixed by @c s (e.g., @c sInitialized) - - -@subsection sLocalVariablesAndArguments Local Variables and Arguments --# Use mixed case with an initial lower case (e.g., @c ijk, @c offset, -@c range, @c rhsValue). - - -@subsection sConstants Constants --# All uppercase; words separated by underscores. If not in a namespace or -local to a source file, then prefixed with the library name in all caps -(e.g., @c HALF_FLOAT_TYPENAME_SUFFIX, @c ZIP_COMPRESSION_LEVEL). - - -@subsection sEnumerationNames Enumeration Names --# Mixed case; first letter uppercase (e.g., @c GridClass, @c VecType) - - -@subsection sEnumerationValues Enumeration Values --# Same as constants; all uppercase; words separated by underscores -(e.g., @c GRID_LEVEL_SET, @c VEC_INVARIANT) and with a common prefix -(@c GRID_, @c VEC_, etc.) - - -@subsection sTypedefs Typedefs --# Mixed case; first letter uppercase (e.g., @c ConstPtr, @c ValueType) --# Do not use a prefix. - - -@subsection sGlobalVariables Global Variables --# Mixed case; always prefixed by @c g (e.g., @c gRegistry) --# In general, try to use class static data instead of globals. - - -@subsection sGlobalFunctions Global Functions --# Mixed case; always prefixed by @c g (e.g., gFunc()). --# In general, try to use class static members instead of global functions. - - -@subsection sBooleans Booleans --# When naming boolean functions and variables, use names that read as a -condition (e.g., if (grid.empty()), -if (matrix.isInvertible())). - - -@section sPractices Practices - - -@subsection sGeneral General --# Code must compile without any warning messages. -if closely related. --# Prefer the C++ Standard Library to the C Standard Library. --# Restrict variables to the smallest scopes possible, and avoid defining -local variables before giving them values. Prefer declarations inside -conditionals: if (Grid::Ptr grid = createGrid()) { ... } instead of -Grid::Ptr grid = createGrid(); if (grid) { ... } --# For new files, be sure to use the right license boilerplate per our license -policy. - - -@subsection sFormatting Formatting --# Use Doxygen-style comments to document public code. --# Indentation is 4 spaces. Do not use tabs. --# Use Unix-style carriage returns ("\n") rather than Windows/DOS ones ("\r\n"). --# Don’t put an @c else right after a @c return. It’s unnecessary -and increases indentation level. --# Do not leave debug printfs or other debugging code lying around. --# Leave a blank line between a group of variable declarations and other code. --# Leave a space after the keywords @c if, @c switch, @c while, @c do, @c for, -and @c return. --# Leave a space on each side of binary operators such as +, -, *, /, &&, -and ||. For clarity in mathematical situations, you may omit the spaces on -either side of * and / operators to illustrate their precedence over + and -. --# Do not leave a space between any dereferencing operator -(such as *, &, [], ->, or .) and its operands. --# In parameter lists, leave a space after each comma. --# Do not leave a space after an opening parenthesis or before a closing -parenthesis. --# Parentheses should be used to clarify operator precedence in expressions. --# Do not leave a space before an end-of-statement semicolon. --# Do not use literal tabs in strings or character constants. Rather, use -spaces or "\t". --# If a parameter list is too long, break it between parameters. Group related -parameters on lines if appropriate. --# Modified spacing is allowed to vertically align repetitive expressions. --# Always begin numeric constants with a digit (e.g., 0.001 not .001). --# Use K&R-style brace placement in public code. --# You may leave off braces for simple, single line flow control statements. --# The return type in a function definition should go on a line by itself. - - -@subsection sIncludeStatements Include Statements --# Always use double quotes ("") to include header files that live in the same -directory as your source code. --# Use angle brackets (<>) to include header files from outside a file’s -directory. --# Do not use absolute paths in include directives. --# If there is a header corresponding to a given source file, list it first, -followed by other local headers, library headers and then system headers. - - -@subsection sHeaderFiles Header Files --# Header files have a .h extension. --# All header files should be bracketed by @c \#ifdef "guard" statements. --# In class definitions, list public, then protected, then private members. --# List methods before variables. --# Fully prototype all public functions and use descriptive naming for each -argument. --# Declare every function defined in a header but outside a class definition -explicitly as @c inline. --# Prefer forward declarations to @c \#include directives in headers. --# Do not take advantage of indirect inclusion of header files. - - -@subsection sSourceFiles Source Files --# Source files have a .cc extension. --# Properly prototype all file static functions with usefully named arguments. --# Whenever possible, put variables and functions in an anonymous namespace. --# Avoid global variables. --# For the main file of an executable, define @c main() at the top and then -utility functions below it in a top-down fashion. - - -@subsection sComments Comments --# Use @c // style comments instead of / * * / style, even for multi-line -comments. --# Use multi-line comments to describe following paragraphs of code. --# Use end-of-line comments to describe variable declarations or to clarify a -single statement. --# Large blocks of code should be commented out with \#if 0 and @c \#endif. --# Do not leave obsolete code fragments within comments as an historical trail. - - -@subsection sPrimitiveTypes Primitive Types --# Avoid writing code that is dependent on the bit size of primitive values, -but when specific bit sizes are required, use explicitly-sized types such as -@c int32_t or @c uint64_t. - - -@subsection sMacros Macros --# Avoid macros for constants. Use global static constants instead. (Local -static constants are not guaranteed to be initialized in a thread-safe manner.) --# Avoid macro functions. Use @c inline and templates instead. - - -@subsection sClasses Classes --# Constructors that can be called with only one argument should be prefixed -with the @c explicit keyword to avoid unintended type conversions. --# Always list the destructor. --# Never call virtual methods from destructors. --# If you have a copy constructor, make sure you have an assignment operator. --# If you have an assignment operator, you probably need a copy constructor. --# If you have data members that are pointers to dynamically allocated memory, -make sure you have a copy constructor and an assignment operator, both of -which do the right thing with that memory. --# Classes which are to be subclassed always have a virtual destructor, even if -it is empty. --# Check against self assignment and return *this in assignment -operators. --# Declare methods as const as much as possible. --# Declare object-valued input arguments as const references wherever -possible. Primitives may be passed by value, however. --# Arithmetic, logical, bitwise, dereference, and address of operators should -only be used when their semantics are clear, obvious, and unambiguous. --# The application operator [ () ] is allowed for functors. --# Conversion operators should be avoided. --# Never return const references to stack allocated or implicitly computed -objects. --# If a class does not have a copy constructor and/or assignment operator, -consider creating a private unimplemented copy constructor and/or assignment -operator to prevent automatically generated versions from being used. - - -@subsection sConditionalStatements Conditional Statements --# For test expressions, use a form that indicates as clearly as possible the -types of operands by avoiding implicit casts. --# Assignments that occur within conditional statements must have no effect in -the enclosing scope. --# Allow for arithmetic imprecision when comparing floating point values. --# In switch statements, always comment fallthroughs and empty cases. - - -@section sNamespaces Namespaces --# Namespaces should be used whenever possible. --# Avoid pulling in entire namespaces with @c using directives -(e.g., using namespace std;). --# @c using declarations are allowed for individual symbols (e.g., -using std::vector;), but they should never appear in a header file. --# Define global operators in the namespace of their arguments. --# Namespaces are not indented. - - -@subsection sExceptions Exceptions --# Appropriate use of exceptions is encouraged. --# Methods should declare all exceptions they might throw using comments, -but not exception specifications. --# Throw scope local exception instances, not pointers or references or globals. --# Catch exceptions by reference. --# Never allow an exception to escape from a destructor. - - -@subsection sTemplates Templates --# Use @c typename rather than @c class when declaring template type parameters. - - -@subsection sMiscellaneous Miscellaneous --# Don’t use pointers to run through arrays of non-primitive types. Use explicit array indexing, iterators or generic algorithms instead. --# Use C++ casts (static_cast<int>(x) or int(x)), -not C casts ((int)x). --# Multiple variables of the same data type may be declared on the same line --# Library code must never deliberately terminate the application in response -to an error condition. --# Avoid using malloc/free when new/delete can be used instead. --# Avoid @c goto. --# Avoid \"magic numbers\". Use named constants when necessary. --# If you use typeid/typeinfo, be aware that although all runtimes support -typeinfo::name(), the format of the string it returns varies -between compilers and even for a given compiler the value is not guaranteed -to be unique. - -*/ - diff --git a/openvdb_3_0_0_library/doc/doc.txt b/openvdb_3_0_0_library/doc/doc.txt deleted file mode 100755 index c0eafea..0000000 --- a/openvdb_3_0_0_library/doc/doc.txt +++ /dev/null @@ -1,520 +0,0 @@ -/** -@mainpage OpenVDB - -The @b OpenVDB library comprises a hierarchical data structure and a suite -of tools for the efficient manipulation of sparse, possibly time-varying, -volumetric data discretized on a three-dimensional grid. It is based on -VDB, which was developed by Ken Museth at DreamWorks Animation, and it -offers an effectively infinite 3D index space, compact storage (both in -memory and on disk), fast data access (both random and sequential), and -a collection of algorithms specifically optimized for the data structure -for common tasks such as filtering, CSG, compositing, sampling and -voxelization from other geometric representations. The technical details -of VDB are described in the paper “VDB: High-Resolution Sparse Volumes with Dynamic Topology”. - -@b OpenVDB is maintained by -DreamWorks Animation -and was developed primarily by -- Ken Museth -- Peter Cucka -- Mihai Aldén -- David Hill - -See the @subpage overview "Overview" for an introduction to the library. - -See @subpage transformsAndMaps "Transforms and Maps" for more -discussion of the transforms used in @b OpenVDB. - -See the @subpage faq "FAQ" for frequently asked questions about @b OpenVDB. - -See the @subpage codeExamples "Cookbook" to get started using @b OpenVDB. - -See @subpage python "Using OpenVDB in Python" to get started with the @b OpenVDB -Python module. - -See the @subpage changes "Release Notes" for what's new in this version -of @b OpenVDB. - -Contributors, please familiarize yourselves with our -@subpage codingStyle "coding standards". - - - -@page overview OpenVDB Overview - -@section Contents -- @ref secOverview -- @ref secTree - - @ref subsecTreeConfig -- @ref secSparsity - - @ref subsecValues - - @ref subsecInactive -- @ref secSpaceAndTrans - - @ref subsecVoxSpace - - @ref subsecWorSpace - - @ref subsecTrans -- @ref secGrid -- @ref secToolUtils -- @ref secIterator - - @ref subsecTreeIter - - @ref subsecNodeIter - - @ref subsecValueAccessor - - @ref subsecTraversal - - - -@section secOverview Introduction - -This document is a high-level summary of the terminology and basic -components of the OpenVDB library and is organized around two key -motivating concepts. First, OpenVDB is designed specifically to -work efficiently with sparse volumetric data locally sampled at a high -spatial frequency, although it will function well for dense volumetric -data. From this follows the need for a memory efficient representation of -this sparsity and the need for fast iterators (and other tools) that -respect sparsity. Second, data storage is separated from data -interpretation. OpenVDB uses unit-less three-dimensional integer -coordinates to address the sparse data, but introduces a unit-less -continuous index space for interpolation, along with a transform to -place the data in physical space. - -When manipulating data in OpenVDB, the three essential objects are (1) the -@vdblink::tree::Tree Tree@endlink, a B-tree-like three-dimensional data -structure; (2) the @vdblink::math::Transform Transform@endlink, which relates -voxel indices @ijk to physical locations @xyz in @ref subsecWorSpace -"world" space; and (3) the @vdblink::Grid Grid@endlink, a container -that associates a @c Tree with a @c Transform and additional metadata. -For instancing purposes (i.e., placing copies -of the same volume in multiple locations), the same tree may be referenced -(via smart pointers) by several different Grids, each having a -unique transform. - -We now proceed to discuss the @c Tree and ideas of sparsity in some -detail, followed by a briefer description of the different spaces and -transforms as well as some of the tools that act on the sparse data. - - -@section secTree The Tree - -In OpenVDB the @c Tree data structure exists to answer the question -What value is stored at location @ijk in three-dimensional index -space? Here i, j and k are arbitrary signed 32-bit -integers, and the data type of the associated value (float, -bool, vector, etc.) is the same for all @ijk. While the @c Tree -serves the same purpose as a large three-dimensional array, it is a -specially designed data structure that, given sparse unique values, -minimizes the overall memory footprint while retaining fast access times. -This is accomplished, as the name suggests, via a tree-based acceleration -structure comprising a @vdblink::tree::RootNode RootNode@endlink, -@vdblink::tree::LeafNode LeafNodes@endlink and usually one or more levels -of @vdblink::tree::InternalNode InternalNodes@endlink with prescribed -branching factors. - -@subsection subsecTreeConfig Tree Configuration - -The tree-based acceleration structure can be configured in various ways, -but with the restriction that for a given tree all the LeafNodes -are at the same depth. Conceptually, the @c RootNode and -@c InternalNodes increasingly subdivide the three-dimensional index -space, and the LeafNodes hold the actual unique voxels. - -The type of a @c Tree encodes both the type of the data to be -stored in the tree (float, bool, etc.) and the -tree's node configuration. In practice a four-level (root, -internal, internal, leaf) configuration is standard, and several -common tree types are defined in openvdb.h. For example, -@code -typedef tree::Tree4::Type FloatTree; -typedef tree::Tree4::Type BoolTree; -@endcode -These predefined tree types share the same branching factors, which dictate -the number of children of a given node. The branching factors (5, 4, 3) -are specified as base two logarithms and should be read backwards from the -leaf nodes up the tree. - -In the default tree configuration, each @c LeafNode holds a -three-dimensional grid of 23 voxels on a side (i.e., an -@f$8\times8\times8@f$ voxel grid). Internally, the @c LeafNode is said -to be at "level 0" of the tree. At "level 1" of this tree is the first -@c InternalNode, and it indexes a @f$2^4\times2^4\times2^4 = -16\times16\times16@f$ grid, each entry of which is either a @c LeafNode -or a constant value that represents an @f$8\times8\times8@f$ block of -voxels. At "level 2" is the second @c InternalNode in this -configuration; it in turn indexes a @f$2^5\times2^5\times2^5 = -32\times32\times32@f$ grid of level-1 InternalNodes and/or values, -and so the @c InternalNode at level 2 subsumes a three-dimensional -block of voxels of size @f$32\times16\times8 = 4096@f$ on a side. Unlike -the InternalNodes and LeafNodes, the @c RootNode ("level -3" for the default configuration) is not explicitly restricted in the number -of children it may have, so the overall index space is limited only by the -range of the integer indices, which are 32-bit by default. - - -@section secSparsity Sparse Values and Voxels - -Like a tree's node configuration, the type of data held by a tree is -determined at compile time. Conceptually the tree itself -employs two different notions of data sparsity to reduce the memory footprint -and at the same time accelerate access to its contents. The first is largely -hidden from the user and concerns ways in which large regions of uniform values -are compactly represented, and the second allows for fast sequential iteration, -skipping user-specified "uninteresting" regions (that may or may not have -uniform values). - -@subsection subsecValues Tile, Voxel, and Background Values - -Although the data in a tree is accessed and set on a per-voxel level -(i.e., the value at @ijk) it need not be internally stored in that way. -To reduce the memory footprint and accelerate data access, data values are -stored in three distinct forms internal to the tree: voxel values, -tile values, and a background value. A voxel value is a unique -value indexed by the location of a voxel and is stored in the @c LeafNode -responsible for that voxel. A tile value is a uniform value assigned to all -voxels subsumed by a given node. (For example, a tile Value belonging to an -@c InternalNode at level 1 is equivalent to a constant-value cube of voxels -of the same size, @f$8\times8\times8@f$, as a @c LeafNode.) The tile value -is returned when a request is made for the data associated with any @ijk -location within the uniform tile. The background value is a unique value -(stored at the root level) that is returned when accessing any @ijk location -that does not resolve to either a tile or a @c LeafNode. - - -@subsection subsecInactive Active and Inactive Voxels - -Any voxel or tile can be classified as either @b active or @b inactive. -The interpretation of this state is application-specific, but generally -active voxels are "interesting", and inactive somehow less so. The locations -of active values may be sparse in the overall voxel topology, and OpenVDB -provides @ref secIterator "iterators" that access active values only (as -well as iterators over inactive values, all values, and general topology). -An example of active vs. inactive: the voxels used to store the distance -values of a narrow-band level set (i.e., close to a given surface) will be -marked as active while the other ("far") voxel locations will be marked as -inactive and will generally represent regions of space with constant distance -values (e.g., two constant distance values of opposite sign to distinguish -the enclosed inside region from the infinite outside or background embedding). - -The @vdblink::tree::Tree::prune() prune()@endlink method replaces -with tile values any nodes that subsume voxels with the same values -and active states. -The resulting tree represents the same volume, but more sparsely. - -@section secSpaceAndTrans Coordinate Systems and Transforms - -The sampled data in the tree is accessed using signed index coordinates -@ijk, but associating each indicial coordinate with a specific physical -location is a job for a @c Transform. A simple linear transform assumes -a lattice-like structure with a fixed physical distance @f$\Delta@f$ between -indices, so that @f$(x,y,z) = (\Delta i, \Delta j, \Delta k)@f$. - -@subsection subsecVoxSpace Index Space - -To simplify transformations between physical space and lattice index -coordinates, a continuous generalization of the index lattice points called -index space is used. -For example, index space coordinate (1.0, 1.0, 1.0) corresponds to the same -point as (1,1,1) in the index lattice, but (1.5,1.0,1.0) also has meaning as -halfway between the index coordinates (1,1,1) and (2,1,1). Index space can -be used in constructing interpolated data values: given an arbitrary -location in physical space, one can use a transform to compute the point in -index space (which need not fall on an exact integer index) that maps to that -location and locally interpolate from values with neighboring index -coordinates. - -@subsection subsecWorSpace World Space - -The interpretation of the data in a tree takes place in world -space. For example, the tree might hold data sampled at discrete -physical locations in world space. @c Transform methods such as -@vdblink::math::Transform::indexToWorld() indexToWorld() @endlink -and its inverse @vdblink::math::Transform::worldToIndex() -worldToIndex() @endlink -may be used to relate coordinates in the two continuous spaces. In -addition, methods such as @vdblink::math::Transform::worldToIndexCellCentered() -worldToIndexCellCentered()@endlink actually return lattice points. - -@subsection subsecTrans Transforms and Maps -A @vdblink::math::Transform Transform @endlink provides a context for -interpreting the information held in a tree by associating a location -in world space with each entry in the tree. -The actual implementation of the @c Transform is managed by a -@vdblink::math::MapBase Map@endlink object, which is an -encapsulation of a continuous, mostly invertible function of three -variables. A @c Map is required to provide -@vdblink::math::MapBase::applyMap() applyMap()@endlink and -@vdblink::math::MapBase::applyInverseMap() applyInverseMap()@endlink -methods to relate locations in its domain to its range and vice versa. -A @c Map is also required to provide information about its local derivatives. -For more on these classes, see the -@subpage transformsAndMaps "Transforms and Maps" page. - - -@section secGrid The Grid - -For many applications, it might not be necessary ever to operate directly on -trees, though there are often significant performance improvements to be -gained by exploiting the tree structure. -The @vdblink::Grid Grid@endlink, however, is the preferred interface through -which to manage voxel data, in part because a grid associates with a tree -additional and often necessary information that is not accessible through -the tree itself. - -A @vdblink::Grid Grid@endlink contains smart pointers to a -@vdblink::tree::Tree Tree@endlink object and a -@vdblink::math::Transform Transform@endlink object, either or both of which -might be shared with other grids. -As mentioned above, the transform provides for the interpretation of voxel -locations. Other grid metadata, notably the grid class, the -vector type and the world space/local space toggle, affect -the interpretation of voxel values. - -OpenVDB is particularly well-suited (though by no means exclusively so) -to the representation of narrow-band level sets and -fog volumes. -A narrow-band level set is represented by three distinct regions of voxels: -an @b outside (or background) region of inactive voxels having a constant, -positive distance from the level set surface; an @b inside region of inactive -voxels having a constant, negative distance; and a thin band of active voxels -(normally three voxels wide on either side of the surface) whose values are -signed distances. -Similarly, a fog volume is represented by an outside region of inactive -voxels with value zero, an inside region of active voxels with value one, -and a thin band of active voxels, with values typically varying linearly -between zero and one, that separates the inside from the outside. -Identifying a grid as a level set or a fog volume, by setting its -@vdblink::GridClass grid class@endlink with -@vdblink::Grid::setGridClass() setGridClass@endlink, allows tools to invoke -alternative implementations that are better-suited or better-optimized -for those classes. -For example, resampling (in particular, scaling) a level set should normally -not be done without updating its signed distance values. -The @vdblink::tools::resampleToMatch() resampleToMatch@endlink tool -automatically recomputes signed distances for grids that are identified -as level sets. -(The lower-level @vdblink::tools::GridResampler GridResampler@endlink does not, -but it is optimized for level set grids in that it transforms only voxels -in the narrow band and relies on -@vdblink::Grid::signedFloodFill() signed flood fill@endlink to reconstruct -the inside and outside regions.) -Other tools whose behavior is affected by the grid class include the -@vdblink::tools::divergence() divergence@endlink operator (which has an -alternative implementation for @ref sStaggered "staggered velocity" grids), -the @vdblink::tools::volumeToMesh() volume to mesh@endlink converter, and -the @vdblink::tools::fillWithSpheres() sphere packing@endlink tool. -In addition, a number of level-set-specific tools, such as the -@vdblink::tools::LevelSetTracker level set tracker@endlink, throw -exceptions when invoked on grids that are not identified as level sets. -It is important, therefore, to set a grid’s class appropriately. - -When a vector-valued grid is transformed or resampled, it is often necessary -for the transform to be applied not just to voxel locations but also to -voxel values. -By default, grids are identified as “world-space”, meaning that -if the grid is vector-valued, its voxel values should be transformed. -Alternatively, voxel values of grids identified as -“local-space”, via -@vdblink::Grid::setIsInWorldSpace() setIsInWorldSpace@endlink, do not -undergo transformation. -A world-space grid’s @vdblink::VecType vector type@endlink, specified -with @vdblink::Grid::setVectorType() setVectorType@endlink, may be invariant, -covariant or contravariant, which determines how transforms are applied -to the grid’s voxel values (for details see, for example, - -Covariance and contravariance of vectors [Wikipedia]). -The @vdblink::tools::transformVectors() transformVectors@endlink tool can be -used to apply a transform to a grid’s voxel values, and it handles all -of the supported vector types. - -A grid can optionally be assigned @vdblink::Grid::setName() name@endlink and -@vdblink::Grid::setCreator() creator@endlink strings. -These are purely informational, though it might be desirable to name grids -so as to easily select which ones to read from files that contain multiple -grids. -In the absence of grid names, or at least of unique names, OpenVDB’s -file I/O routines recognize an ordinal suffix: -“[0]” refers to the first unnamed grid, -“[1]” refers to the second, and so on, and -“density[0]” and “density[1]” -refer to the first and second grids named “density”. -Also of interest for file I/O is a grid’s -“@vdblink::Grid::setSaveFloatAsHalf() save float as half@endlink” -setting, which allows it to be written more compactly using 16-bit -floating point values rather than full-precision values. -Finally, during file output certain statistics are computed and stored -as per-grid metadata. -These include the grid’s index-space active voxel bounding box, -its active voxel count and its memory usage in bytes. -This information can also be -@vdblink::io::File::readAllGridMetadata() retrieved@endlink -efficiently from a file. - - -@section secToolUtils Utilities and Tools - -OpenVDB provides utility functions and classes for the manipulation of grids -and the data they hold. -Tools such as those found in GridOperators.h compute vector quantities from -scalar data or vice-versa. -Other tools perform filtering (Filter.h and LevelSetFilter.h) and -interpolation (Interpolation.h) as well as sampling (GridTransformer.h), -compositing and constructive solid geometry (Composite.h), and other -transformations (ValueTransformer.h). -OpenVDB also supports advanced finite difference computations through -a variety of local support stencils (Stencils.h). - - -@section secIterator Iterators - -OpenVDB provides efficient, often multithreaded, implementations of a large -variety of morphological, filtering and other algorithms that address common -data manipulation tasks on three-dimensional grids. For more specialized -tasks, OpenVDB provides lower-level data accessors that enable fast -iteration over all or selected voxels and over the elements of a @c Tree. -These take several forms: iterator classes of various types, functor-based -@b visitor methods, and the -@vdblink::tree::ValueAccessor ValueAccessor@endlink, -an accelerator for indexed @ijk voxel lookups. - -Iterator classes follow a fairly consistent naming scheme. First, the -@b CIter and @b Iter suffixes denote @const and non-@const iterators, i.e., -iterators that offer, respectively, read-only and read/write access to the -underlying tree or node. Second, iterators over tile and voxel values are -denoted either @b On, @b Off or @b All, indicating that they visit only -active values, only inactive values, or both active and inactive values. -So, for example, @c Tree::ValueOnCIter is a read-only iterator over all -active values (both tile and voxel) of a tree, whereas -@c LeafNode::ValueAllIter is a read/write iterator over all values, both -active and inactive, of a single leaf node. - -OpenVDB iterators are not STL-compatible in that one can always request -an iterator that points to the beginning of a collection of elements (nodes, -voxels, etc.), but one usually cannot request an iterator that points to the -end of the collection. (This is because finding the end might require a -full tree traversal.) Instead, all OpenVDB iterators implement a @c test() -method that returns @c true as long as the iterator is not exhausted and -@c false as soon as it is. Typical usage is as follows: -@code -typedef openvdb::FloatGrid GridType; -GridType grid = ...; -for (GridType::ValueOnCIter iter = grid.cbeginValueOn(); iter.test(); ++iter) ... -@endcode -or more compactly -@code -for (GridType::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) ... -@endcode -Note that the naming scheme for methods that return "begin" iterators -closely mirrors that of the iterators themselves. That is, -@c Grid::cbeginValueOn() returns a @const iterator to the first of a grid's -active values, whereas @c LeafNode::beginValueAll() returns a non-@const -iterator to the first of a leaf node's values, both active and inactive. -(Const overloads of @c begin*() methods are usually provided, so that if -the @c Grid is itself @const, @c Grid::begin*() will actually return a -@const iterator. This makes it more convenient to use these methods in -templated code.) - -Finally, note that modifying the tree or node over which one is iterating -typically does not invalidate the iterator, though it might first need -to be incremented to point to the next existing element (for example, -if one deletes a child node to which the iterator is currently pointing). - -@subsection subsecTreeIter Tree Iterators -@anchor treeValueIterRef -@par Tree::ValueIter -Tree-level value iterators traverse an entire tree, visiting each value -(tile or voxel) exactly once. (It is also possible to restrict the -traversal to minimum and maximum levels of the tree.) In addition to the -methods common to all OpenVDB iterators, such as @c test() and @c next(), -a @c Tree::ValueIter provides methods that return the depth in the tree of -the node within which the iterator is pointing (the root node has depth 0) -and the @ijk axis-aligned bounding box of the tile or voxel to which it is -pointing, and methods to get and set both the value and the active state of -the tile or voxel. See the -@vdblink::tree::TreeValueIteratorBase TreeValueIteratorBase @endlink -class for the complete list. - -@anchor treeLeafIterRef -@par Tree::LeafIter -By convention in OpenVDB, voxels in the narrow band of a narrow-band -level set are stored only at the leaf level of a tree, so to facilitate the -implementation of level set algorithms that operate on narrow-band voxels, -OpenVDB provides an iterator that visits each @c LeafNode in a tree exactly -once. -See the @vdblink::tree::LeafIteratorBase LeafIteratorBase@endlink class -for details, and also the related -@vdblink::tree::LeafManager LeafManager@endlink acceleration structure. - -@anchor treeNodeIterRef -@par Tree::NodeIter -A node iterator traverses a tree in depth-first order, starting from its -root, and visits each node exactly once. (It is also possible to restrict -the traversal to minimum and maximum node depths—see the -@vdblink::tree::NodeIteratorBase NodeIteratorBase @endlink -class for details.) Like the tree-level value iterator, the node iterator -provides methods that return the depth in the tree of the node to which the -iterator is pointing (the root node has depth 0) and the @ijk axis-aligned -bounding box of the voxels subsumed by the node and all of its children. -@par -Naturally, a node iterator also provides access to the node to which it is -pointing, but this is complicated somewhat by the fact that nodes of the -various types (@c RootNode, @c InternalNode and @c LeafNode) do not inherit -from a common base class. For efficiency, OpenVDB generally avoids class -inheritance and virtual functions in favor of templates, allowing the -compiler to optimize away function calls. In particular, each node type is -templated on the type of its children, so even two InternalNodes at -different levels of a tree have distinct types. As a result, it is -necessary to know the type of the node to which a node iterator is pointing -in order to request access to that node. See the -@ref sNodeIterator "Cookbook" for an example of how to do this. - -@subsection subsecNodeIter Node Iterators - -Less commonly used than tree-level iterators (but found in the -implementations of some of the narrow-band level set algorithms referred to -@ref treeLeafIterRef "above") are node-level iterators. A node -value iterator visits the values (active, inactive or both) stored in -a single @c RootNode, @c InternalNode or @c LeafNode, whereas a node -child iterator visits the children of a single root or internal node. -(Recall that non-leaf nodes store either a tile value or a child node at -each grid position.) - - -@subsection subsecValueAccessor Value Accessor - -When traversing a grid by @ijk index in a spatially coherent pattern, -such as when iterating over neighboring voxels, request a -@vdblink::tree::ValueAccessor ValueAccessor@endlink from the grid -(with @vdblink::Grid::getAccessor() Grid::getAccessor()@endlink) -and use the accessor's -@vdblink::tree::ValueAccessor::getValue() getValue()@endlink and -@vdblink::tree::ValueAccessor::setValue() setValue()@endlink methods, since -these will usually be significantly faster (a factor of three is typical) -than accessing voxels directly in the grid's tree. -The accessor records the sequence of nodes -visited during the most recent access; on the next access, rather than -traversing the tree from the root node down, it performs an inverted -traversal from the deepest recorded node up. For neighboring voxels, the -traversal need only proceed as far as the voxels' common ancestor node, -which more often than not is the first node in the sequence. - -Multiple accessors may be associated with a single grid. In fact, for -multithreaded, read-only access to a grid, it is recommended that each -thread be assigned its own accessor. A thread-safe, mutex-locked accessor -is provided (see @vdblink::tree::ValueAccessorRW ValueAccessorRW@endlink), -but the locking negates much of the performance benefit of inverted traversal; -and because it is the accessor object that is thread-safe, not the grid, -concurrent reads and writes are not safe unless all threads share a single -accessor. - -All accessors associated with a grid must be cleared after any operation that -removes nodes from the grid's tree, such as pruning, CSG or compositing. -For those and other built-in operations, this is done automatically via -a callback mechanism, but developers must be careful to call -@vdblink::tree::Tree::clearAllAccessors() Tree::clearAllAccessors()@endlink -whenever deleting nodes directly. - - -@subsection subsecTraversal Tree Traversal - -To be written - -*/ diff --git a/openvdb_3_0_0_library/doc/examplecode.txt b/openvdb_3_0_0_library/doc/examplecode.txt deleted file mode 100755 index e43a713..0000000 --- a/openvdb_3_0_0_library/doc/examplecode.txt +++ /dev/null @@ -1,1265 +0,0 @@ -/** - -@page codeExamples OpenVDB Cookbook - -This section provides code snippets and some complete programs that -illustrate how to use OpenVDB and how to perform common tasks. - - -@section Contents -- @ref sHelloWorld - - @ref sCompilingHelloWorld -- @ref sAllocatingGrids -- @ref sPopulatingGrids -- @ref sModifyingGrids -- @ref sStreamIO -- @ref sHandlingMetadata - - @ref sAddingMetadata - - @ref sGettingMetadata - - @ref sRemovingMetadata -- @ref sIteration - - @ref sNodeIterator - - @ref sLeafIterator - - @ref sValueIterator - - @ref sIteratorRange -- @ref sInterpolation - - @ref sSamplers - - @ref sGridSampler - - @ref sDualGridSampler -- @ref sXformTools - - @ref sResamplingTools - - @ref sValueXformTools -- @ref sCombiningGrids - - @ref sCsgTools - - @ref sCompTools - - @ref sCombineTools -- @ref sGenericProg - - @ref sTypedGridMethods - - - -@section sHelloWorld "Hello, World" for OpenVDB -This is a very simple example showing how to create a grid and access -its voxels. OpenVDB supports both random access to voxels by coordinates -and sequential access by means of iterators. This example illustrates both -types of access: -@code -#include -#include - -int main() -{ - // Initialize the OpenVDB library. This must be called at least - // once per program and may safely be called multiple times. - openvdb::initialize(); - - // Create an empty floating-point grid with background value 0. - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(); - - std::cout << "Testing random access:" << std::endl; - - // Get an accessor for coordinate-based access to voxels. - openvdb::FloatGrid::Accessor accessor = grid->getAccessor(); - - // Define a coordinate with large signed indices. - openvdb::Coord xyz(1000, -200000000, 30000000); - - // Set the voxel value at (1000, -200000000, 30000000) to 1. - accessor.setValue(xyz, 1.0); - - // Verify that the voxel value at (1000, -200000000, 30000000) is 1. - std::cout << "Grid" << xyz << " = " << accessor.getValue(xyz) << std::endl; - - // Reset the coordinates to those of a different voxel. - xyz.reset(1000, 200000000, -30000000); - - // Verify that the voxel value at (1000, 200000000, -30000000) is - // the background value, 0. - std::cout << "Grid" << xyz << " = " << accessor.getValue(xyz) << std::endl; - - // Set the voxel value at (1000, 200000000, -30000000) to 2. - accessor.setValue(xyz, 2.0); - - // Set the voxels at the two extremes of the available coordinate space. - // For 32-bit signed coordinates these are (-2147483648, -2147483648, -2147483648) - // and (2147483647, 2147483647, 2147483647). - accessor.setValue(openvdb::Coord::min(), 3.0f); - accessor.setValue(openvdb::Coord::max(), 4.0f); - - std::cout << "Testing sequential access:" << std::endl; - - // Print all active ("on") voxels by means of an iterator. - for (openvdb::FloatGrid::ValueOnCIter iter = grid->cbeginValueOn(); iter; ++iter) { - std::cout << "Grid" << iter.getCoord() << " = " << *iter << std::endl; - } -} -@endcode -Output: -@code -Testing random access: -Grid[1000, -200000000, 30000000] = 1 -Grid[1000, 200000000, -30000000] = 0 -Testing sequential access: -Grid[-2147483648, -2147483648, -2147483648] = 3 -Grid[1000, -200000000, 30000000] = 1 -Grid[1000, 200000000, -30000000] = 2 -Grid[2147483647, 2147483647, 2147483647] = 4 -@endcode - -@subsection sCompilingHelloWorld Compiling -See the @c Makefile and @c INSTALL file included in this distribution for -details on how to build and install the OpenVDB library. -By default, installation is into the directory tree rooted at -/tmp/OpenVDB/, but this can be changed either by editing the value -of the @c INSTALL_DIR variable in the makefile or by setting the desired -value from the command line, as in the following example: -@code -make install INSTALL_DIR=/usr/local -@endcode -Once OpenVDB has been installed, the simplest way to compile a program -like the “Hello, World” example above is to examine the -commands that are used to build the @c vdb_print tool: -@code -rm vdb_print -make verbose=yes vdb_print -@endcode -and then replace “-o vdb_print” with, for example, -“-o helloworld” -and “cmd/openvdb_print/main.cc” -with “helloworld.cc”. - - - -@section sAllocatingGrids Creating and writing a grid -This example is a complete program that illustrates some of the basic steps -to create grids and write them to disk. (See @ref sPopulatingGrids, -below, for the implementation of the @c makeSphere() function.) -@code -#include - -int main() -{ - openvdb::initialize(); - - // Create a shared pointer to a newly-allocated grid of a built-in type: - // in this case, a FloatGrid, which stores one single-precision floating point - // value per voxel. Other built-in grid types include BoolGrid, DoubleGrid, - // Int32Grid and Vec3SGrid (see openvdb.h for the complete list). - // The grid comprises a sparse tree representation of voxel data, - // user-supplied metadata and a voxel space to world space transform, - // which defaults to the identity transform. - openvdb::FloatGrid::Ptr grid = - openvdb::FloatGrid::create(/*background value=*/2.0); - - // Populate the grid with a sparse, narrow-band level set representation - // of a sphere with radius 50 voxels, located at (1.5, 2, 3) in index space. - makeSphere(*grid, /*radius=*/50.0, /*center=*/openvdb::Vec3f(1.5, 2, 3)); - - // Associate some metadata with the grid. - grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); - - // Associate a scaling transform with the grid that sets the voxel size - // to 0.5 units in world space. - grid->setTransform( - openvdb::math::Transform::createLinearTransform(/*voxel size=*/0.5)); - - // Identify the grid as a level set. - grid->setGridClass(openvdb::GRID_LEVEL_SET); - - // Name the grid "LevelSetSphere". - grid->setName("LevelSetSphere"); - - // Create a VDB file object. - openvdb::io::File file("mygrids.vdb"); - - // Add the grid pointer to a container. - openvdb::GridPtrVec grids; - grids.push_back(grid); - - // Write out the contents of the container. - file.write(grids); - file.close(); -} -@endcode - -The OpenVDB library includes optimized routines for many common tasks. -For example, most of the steps given above are encapsulated in the function -@vdblink::tools::createLevelSetSphere() tools::createLevelSetSphere()@endlink, so that -the above can be written simply as follows: - -@code -#include -#include - -int main() -{ - openvdb::initialize(); - - // Create a FloatGrid and populate it with a narrow-band - // signed distance field of a sphere. - openvdb::FloatGrid::Ptr grid = - openvdb::tools::createLevelSetSphere( - /*radius=*/50.0, /*center=*/openvdb::Vec3f(1.5, 2, 3), - /*voxel size=*/0.5, /*width=*/4.0); - - // Associate some metadata with the grid. - grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); - - // Name the grid "LevelSetSphere". - grid->setName("LevelSetSphere"); - - // Create a VDB file object. - openvdb::io::File file("mygrids.vdb"); - - // Add the grid pointer to a container. - openvdb::GridPtrVec grids; - grids.push_back(grid); - - // Write out the contents of the container. - file.write(grids); - file.close(); -} -@endcode - - - -@section sPopulatingGrids Populating a grid with values -The following code is templated so as to operate on grids containing values -of any scalar type, provided that the value type supports negation and -comparison. Note that this algorithm is only meant as an example and should -never be used in production; use the much more efficient routines in -tools/LevelSetSphere.h instead. - -See @ref sGenericProg for more on processing grids of arbitrary type. -@anchor makeSphereCode -@code -// Populate the given grid with a narrow-band level set representation of a sphere. -// The width of the narrow band is determined by the grid's background value. -// (Example code only; use tools::createSphereSDF() in production.) -template -void -makeSphere(GridType& grid, float radius, const openvdb::Vec3f& c) -{ - typedef typename GridType::ValueType ValueT; - - // Distance value for the constant region exterior to the narrow band - const ValueT outside = grid.background(); - - // Distance value for the constant region interior to the narrow band - // (by convention, the signed distance is negative in the interior of - // a level set) - const ValueT inside = -outside; - - // Use the background value as the width in voxels of the narrow band. - // (The narrow band is centered on the surface of the sphere, which - // has distance 0.) - int padding = int(openvdb::math::RoundUp(openvdb::math::Abs(outside))); - // The bounding box of the narrow band is 2*dim voxels on a side. - int dim = int(radius + padding); - - // Get a voxel accessor. - typename GridType::Accessor accessor = grid.getAccessor(); - - // Compute the signed distance from the surface of the sphere of each - // voxel within the bounding box and insert the value into the grid - // if it is smaller in magnitude than the background value. - openvdb::Coord ijk; - int &i = ijk[0], &j = ijk[1], &k = ijk[2]; - for (i = c[0] - dim; i < c[0] + dim; ++i) { - const float x2 = openvdb::math::Pow2(i - c[0]); - for (j = c[1] - dim; j < c[1] + dim; ++j) { - const float x2y2 = openvdb::math::Pow2(j - c[1]) + x2; - for (k = c[2] - dim; k < c[2] + dim; ++k) { - - // The distance from the sphere surface in voxels - const float dist = openvdb::math::Sqrt(x2y2 - + openvdb::math::Pow2(k - c[2])) - radius; - - // Convert the floating-point distance to the grid's value type. - ValueT val = ValueT(dist); - - // Only insert distances that are smaller in magnitude than - // the background value. - if (val < inside || outside < val) continue; - - // Set the distance for voxel (i,j,k). - accessor.setValue(ijk, val); - } - } - } - - // Propagate the outside/inside sign information from the narrow band - // throughout the grid. - grid.signedFloodFill(); -} -@endcode - - - -@section sModifyingGrids Reading and modifying a grid -@code -#include - -openvdb::initialize(); - -// Create a VDB file object. -openvdb::io::File file("mygrids.vdb"); - -// Open the file. This reads the file header, but not any grids. -file.open(); - -// Loop over all grids in the file and retrieve a shared pointer -// to the one named "LevelSetSphere". (This can also be done -// more simply by calling file.readGrid("LevelSetSphere").) -openvdb::GridBase::Ptr baseGrid; -for (openvdb::io::File::NameIterator nameIter = file.beginName(); - nameIter != file.endName(); ++nameIter) -{ - // Read in only the grid we are interested in. - if (nameIter.gridName() == "LevelSetSphere") { - baseGrid = file.readGrid(nameIter.gridName()); - } else { - std::cout << "skipping grid " << nameIter.gridName() << std::endl; - } -} - -file.close(); - -// From the example above, "LevelSetSphere" is known to be a FloatGrid, -// so cast the generic grid pointer to a FloatGrid pointer. -openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast(baseGrid); - -// Convert the level set sphere to a narrow-band fog volume, in which -// interior voxels have value 1, exterior voxels have value 0, and -// narrow-band voxels have values varying linearly from 0 to 1. - -const float outside = grid->background(); -const float width = 2.0 * outside; - -// Visit and update all of the grid's active values, which correspond to -// voxels on the narrow band. -for (openvdb::FloatGrid::ValueOnIter iter = grid->beginValueOn(); iter; ++iter) { - float dist = iter.getValue(); - iter.setValue((outside - dist) / width); -} - -// Visit all of the grid's inactive tile and voxel values and update the values -// that correspond to the interior region. -for (openvdb::FloatGrid::ValueOffIter iter = grid->beginValueOff(); iter; ++iter) { - if (iter.getValue() < 0.0) { - iter.setValue(1.0); - iter.setValueOff(); - } -} - -// Set exterior voxels to 0. -grid->setBackground(0.0); -@endcode - - - -@section sStreamIO Stream I/O -The @vdblink::io::Stream io::Stream@endlink class allows grids -to be written to and read from streams that do not support random access, -with the restriction that all grids must be written or read at once. -(With @vdblink::io::File io::File@endlink, -grids can be read individually by name, provided that they were originally -written with @c io::File, rather than streamed to a file.) - -@code -#include -#include - -openvdb::initialize(); - -openvdb::GridPtrVecPtr grids(new GridPtrVec); -grids->push_back(...); - -// Stream the grids to a string. -std::ostringstream ostr(std::ios_base::binary); -openvdb::io::Stream(ostr).write(*grids); - -// Stream the grids to a file. -std::ofstream ofile("mygrids.vdb", std::ios_base::binary); -openvdb::io::Stream(ofile).write(*grids); - -// Stream in grids from a string. -// Note that io::Stream::getGrids() returns a shared pointer -// to an openvdb::GridPtrVec. -std::istringstream istr(ostr.str(), std::ios_base::binary); -openvdb::io::Stream strm(istr); -grids = strm.getGrids(); - -// Stream in grids from a file. -std::ifstream ifile("mygrids.vdb", std::ios_base::binary); -grids = openvdb::io::Stream(ifile).getGrids(); -@endcode - - - -@section sHandlingMetadata Handling metadata -Metadata of various types (string, floating point, integer, etc.—see -metadata/Metadata.h for more) can be attached both to individual Grids -and to files on disk. -The examples that follow refer to Grids, but the usage is the same -for the @vdblink::MetaMap MetaMap@endlink that can optionally be supplied -to a @vdblink::io::File::write() file@endlink or -@vdblink::io::Stream::write() stream@endlink for writing. - -@subsection sAddingMetadata Adding metadata -The @vdblink::Grid::insertMeta() Grid::insertMeta()@endlink method either -adds a new (@em name, @em value) pair if the name is unique, or overwrites -the existing value if the name matches an existing one. An existing value -cannot be overwritten with a new value of a different type; the old metadata -must be removed first. -@code -#include - -openvdb::Vec3SGrid::Ptr grid = openvdb::Vec3SGrid::create(); - -grid->insertMeta("vector type", openvdb::StringMetadata("covariant (gradient)")); -grid->insertMeta("radius", openvdb::FloatMetadata(50.0)); -grid->insertMeta("center", openvdb::Vec3SMetadata(openvdb::Vec3S(10, 15, 10))); - -// OK, overwrites existing value: -grid->insertMeta("center", openvdb::Vec3SMetadata(openvdb::Vec3S(10.5, 15, 30))); - -// Error (throws openvdb::TypeError), can't overwrite a value of type Vec3S -// with a value of type float: -grid->insertMeta("center", openvdb::FloatMetadata(0.0)); -@endcode - -@subsection sGettingMetadata Retrieving metadata -Call @vdblink::Grid::metaValue() Grid::metaValue()@endlink to retrieve -the value of metadata of a known type. For example, -@code -std::string s = grid->metaValue("vector type"); - -float r = grid->metaValue("radius"); - -// Error (throws openvdb::TypeError), can't read a value of type Vec3S as a float: -float center = grid->metaValue("center"); -@endcode - -@vdblink::Grid::beginMeta() Grid::beginMeta()@endlink and -@vdblink::Grid::beginMeta() Grid::beginMeta()@endlink return STL @c std::map -iterators over all of the metadata associated with a grid: -@code -for (openvdb::MetaMap::MetaIterator iter = grid->beginMeta(); - iter != grid->endMeta(); ++iter) -{ - const std::string& name = iter->first; - openvdb::Metadata::Ptr value = iter->second; - std::string valueAsString = value->str(); - std::cout << name << " = " << valueAsString << std::endl; -} -@endcode - -If the type of the metadata is not known, use the -@vdblink::Grid::operator[]() index operator@endlink to retrieve -a shared pointer to a generic @vdblink::Metadata Metadata@endlink object, -then query its type: -@code -openvdb::Metadata::Ptr metadata = grid["center"]; - -// See typenameAsString() in Types.h for a list of strings that can be -// returned by the typeName() method. -std::cout << metadata->typeName() << std::endl; // prints "vec3s" - -// One way to process metadata of arbitrary types: -if (metadata->typeName() == openvdb::StringMetadata::staticTypeName()) { - std::string s = static_cast(*metadata).value(); -} else if (metadata->typeName() == openvdb::FloatMetadata::staticTypeName()) { - float f = static_cast(*metadata).value(); -} else if (metadata->typeName() == openvdb::Vec3SMetadata::staticTypeName()) { - openvdb::Vec3S v = static_cast(*metadata).value(); -} -@endcode - -@subsection sRemovingMetadata Removing metadata -@vdblink::Grid::removeMeta() Grid::removeMeta()@endlink removes metadata -by name. If the given name is not found, the call has no effect. -@code -grid->removeMeta("vector type"); -grid->removeMeta("center"); -grid->removeMeta("vector type"); // OK (no effect) -@endcode - - - -@section sIteration Iteration - -@subsection sNodeIterator Node Iterator -A @vdblink::tree::Tree::NodeIter Tree::NodeIter@endlink visits each node in -a tree exactly once. In the following example, the tree is known to have a -depth of 4; see the @ref treeNodeIterRef "Overview" for a discussion of -why node iteration can be complicated when the tree depth is not known. -There are techniques (beyond the scope of this Cookbook) for operating -on trees of arbitrary depth. -@code -#include - -typedef openvdb::FloatGrid GridType; -typedef GridType::TreeType TreeType; -typedef TreeType::RootNodeType RootType; // level 3 RootNode -assert(RootType::LEVEL == 3); -typedef RootType::ChildNodeType Int1Type; // level 2 InternalNode -typedef Int1Type::ChildNodeType Int2Type; // level 1 InternalNode -typedef TreeType::LeafNodeType LeafType; // level 0 LeafNode - -GridType::Ptr grid = ...; - -for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) { - switch (iter.getDepth()) { - case 0: { RootType* node = NULL; iter.getNode(node); if (node) ...; break; } - case 1: { Int1Type* node = NULL; iter.getNode(node); if (node) ...; break; } - case 2: { Int2Type* node = NULL; iter.getNode(node); if (node) ...; break; } - case 3: { LeafType* node = NULL; iter.getNode(node); if (node) ...; break; } - } -} -@endcode - - -@subsection sLeafIterator Leaf Node Iterator -A @vdblink::tree::Tree::LeafIter Tree::LeafIter@endlink visits each leaf -node in a tree exactly once. -@code -#include - -typedef openvdb::FloatGrid GridType; -typedef GridType::TreeType TreeType; - -GridType::Ptr grid = ...; - -// Iterate over references to const LeafNodes. -for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) { - const TreeType::LeafNodeType& leaf = *iter; - ... -} -// Iterate over references to non-const LeafNodes. -for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) { - TreeType::LeafNodeType& leaf = *iter; - ... -} -// Iterate over pointers to const LeafNodes. -for (TreeType::LeafCIter iter = grid->tree().cbeginLeaf(); iter; ++iter) { - const TreeType::LeafNodeType* leaf = iter.getLeaf(); - ... -} -// Iterate over pointers to non-const LeafNodes. -for (TreeType::LeafIter iter = grid->tree().beginLeaf(); iter; ++iter) { - TreeType::LeafNodeType* leaf = iter.getLeaf(); - ... -} -@endcode -See the @ref treeLeafIterRef "Overview" for more on leaf node iterators. - - -@subsection sValueIterator Value Iterator -A @vdblink::tree::Tree::ValueAllIter Tree::ValueIter@endlink visits each -@ref subsecValues "value" (both tile and voxel) in a tree exactly once. -Iteration can be unrestricted or can be restricted to only active values -or only inactive values. Note that tree-level value iterators (unlike -the node iterators described above) can be accessed either through a -grid's tree or directly through the grid itself, as in the following example: -@code -#include - -typedef openvdb::Vec3SGrid GridType; -typedef GridType::TreeType TreeType; - -GridType::Ptr grid = ...; - -// Iterate over all active values but don't allow them to be changed. -for (GridType::ValueOnCIter iter = grid->cbeginValueOn(); iter.test(); ++iter) { - const openvdb::Vec3f& value = *iter; - - // Print the coordinates of all voxels whose vector value has - // a length greater than 10, and print the bounding box coordinates - // of all tiles whose vector value length is greater than 10. - if (value.length() > 10.0) { - if (iter.isVoxelValue()) { - std::cout << iter.getCoord() << std::endl; - } else { - openvdb::CoordBBox bbox; - iter.getBoundingBox(bbox); - std::cout << bbox << std::endl; - } - } -} - -// Iterate over and normalize all inactive values. -for (GridType::ValueOffIter iter = grid->beginValueOff(); iter.test(); ++iter) { - openvdb::Vec3f value = *iter; - value.normalize(); - iter.setValue(value); -} - -// Normalize the (inactive) background value as well. -grid->setBackground(grid->background().unit()); -@endcode -See the @ref treeValueIterRef "Overview" for more on value iterators. - - -@subsection sIteratorRange Iterator Range -A @vdblink::tree::IteratorRange tree::IteratorRange@endlink wraps any grid or -tree iterator and gives the iterator -TBB splittable range -semantics, so that it can be used as the Range argument to functions like -@c tbb::parallel_for() and @c tbb::parallel_reduce(). -(This is in fact how @vdblink::tools::foreach() tools::foreach()@endlink and -@vdblink::tools::transformValues() tools::transformValues()@endlink are -implemented; see @ref sValueXformTools, below, for more on those functions.) -There is some overhead to splitting, since grid and tree iterators are not -random-access, but the overhead should typically be negligible compared with -the amount of work done per subrange. - -The following is a complete program that uses -@vdblink::tree::IteratorRange tree::IteratorRange@endlink. -The program iterates in parallel over the leaf nodes of a tree (by splitting -the iteration range of a -@vdblink::tree::Tree::LeafCIter Tree::LeafCIter@endlink) and computes -the total number of active leaf-level voxels by incrementing a global, -thread-safe counter. -@code -#include -#include -#include -#include -#include -#include - -// Global active voxel counter, atomically updated from multiple threads -tbb::atomic activeLeafVoxelCount; - -// Functor for use with tbb::parallel_for() that operates on a grid's leaf nodes -template -struct LeafProcessor -{ - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::LeafNodeType LeafNode; - // Define an IteratorRange that splits the iteration space of a leaf iterator. - typedef openvdb::tree::IteratorRange IterRange; - - void operator()(IterRange& range) const - { - // Note: this code must be thread-safe. - - // Iterate over a subrange of the leaf iterator's iteration space. - for ( ; range; ++range) { - // Retrieve the leaf node to which the iterator is pointing. - const LeafNode& leaf = *range.iterator(); - // Update the global counter. - activeLeafVoxelCount.fetch_and_add(leaf.onVoxelCount()); - } - } -}; - - -int -main() -{ - openvdb::initialize(); - - // Generate a level set grid. - openvdb::FloatGrid::Ptr grid = - openvdb::tools::createLevelSetSphere(/*radius=*/20.0, - /*center=*/openvdb::Vec3f(1.5, 2, 3), /*voxel size=*/0.5); - - // Construct a functor for use with tbb::parallel_for() - // that processes the leaf nodes of a FloatGrid. - typedef LeafProcessor FloatLeafProc; - FloatLeafProc proc; - - // Wrap a leaf iterator in an IteratorRange. - FloatLeafProc::IterRange range(grid->tree().cbeginLeaf()); - // Iterate over leaf nodes in parallel. - tbb::parallel_for(range, proc); - - std::cout << activeLeafVoxelCount << " active leaf voxels" << std::endl; - - // The computed voxel count should equal the grid's active voxel count, - // since all of the active voxels in a level set grid are stored at the - // leaf level (that is, there are no active tiles in a level set grid). - assert(activeLeafVoxelCount == grid->activeVoxelCount()); -} -@endcode - - - -@section sInterpolation Interpolation of grid values - -Applications such as rendering require evaluation of grids at arbitrary, -fractional coordinates in either index or world space. -This is achieved, of course, by interpolating between known grid values -at neighboring whole-voxel locations, that is, at integer coordinates -in index space. -The following sections introduce OpenVDB’s various interpolation schemes -as well as the @ref sGridSampler and @ref sDualGridSampler classes for -efficient, continuous sampling of grids. -In most cases, GridSampler is the preferred interface for interpolation, -but note that when a fixed transform is to be applied to all values in a grid -(that is, the grid is to be resampled), it is both easier and more efficient to -use the multithreaded @vdblink::tools::GridTransformer GridTransformer@endlink -class, introduced in @ref sXformTools. - - -@subsection sSamplers Index-space samplers -OpenVDB offers low-level zero-, first- and second-order interpolators -@vdblink::tools::PointSampler PointSampler@endlink, -@vdblink::tools::BoxSampler BoxSampler@endlink and -@vdblink::tools::QuadraticSampler QuadraticSampler@endlink, in addition to the -variants @vdblink::tools::StaggeredPointSampler StaggeredPointSampler@endlink, -@vdblink::tools::StaggeredBoxSampler StaggeredBoxSampler@endlink and -@vdblink::tools::StaggeredQuadraticSampler StaggeredQuadraticSampler@endlink -for @ref sStaggered "staggered" velocity grids. - -@code -#include -#include - -const GridType grid = ...; - -// Choose fractional coordinates in index space. -const openvdb::Vec3R ijk(10.5, -100.2, 50.3); - -// Compute the value of the grid at ijk via nearest-neighbor (zero-order) -// interpolation. -GridType::ValueType v0 = openvdb::tools::PointSampler::sample(grid.tree(), ijk); - -// Compute the value via trilinear (first-order) interpolation. -GridType::ValueType v1 = openvdb::tools::BoxSampler::sample(grid.tree(), ijk); - -// Compute the value via triquadratic (second-order) interpolation. -GridType::ValueType v2 = openvdb::tools::QuadraticSampler::sample(grid.tree(), ijk); -@endcode - -These examples invoke the @vdblink::tree::Tree::getValue() getValue@endlink -method on the grid’s tree to fetch sample values in the neighborhood -of @ijk. -Accessing values via the tree is thread-safe due to the lack of caching, -but for that reason it is also suboptimal. -For better performance, use @ref subsecValueAccessor "value accessors" -(but be careful to use one accessor per computational thread): -@code -GridType::ConstAccessor accessor = grid.getConstAccessor(); - -GridType::ValueType v0 = openvdb::tools::PointSampler::sample(accessor, ijk); -GridType::ValueType v1 = openvdb::tools::BoxSampler::sample(accessor, ijk); -GridType::ValueType v2 = openvdb::tools::QuadraticSampler::sample(accessor, ijk); -@endcode - -Another issue with these low-level interpolators is that they operate only -in index space. -To interpolate in world space, use the higher-level classes discussed below. - - -@subsection sGridSampler Grid Sampler - -The @vdblink::tools::GridSampler GridSampler@endlink class allows for -continuous sampling in both world space and index space and can be used -with grids, trees or value accessors. - -@code -#include -#include - -const GridType grid = ...; - -// Instantiate the GridSampler template on the grid type and on a box sampler -// for thread-safe but uncached trilinear interpolation. -openvdb::tools::GridSampler sampler(grid); - -// Compute the value of the grid at fractional coordinates in index space. -GridType::ValueType indexValue = sampler.isSample(openvdb::Vec3R(10.5, -100.2, 50.3)); - -// Compute the value of the grid at a location in world space. -GridType::ValueType worldValue = sampler.wsSample(openvdb::Vec3R(0.25, 1.4, -1.1)); - -// Request a value accessor for accelerated access. -// (Because value accessors employ a cache, it is important to declare -// one accessor per thread.) -GridType::ConstAccessor accessor = grid.getConstAccessor(); - -// Instantiate the GridSampler template on the accessor type and on -// a box sampler for accelerated trilinear interpolation. -openvdb::tools::GridSampler - fastSampler(accessor, grid.transform()); - -// Compute the value of the grid at fractional coordinates in index space. -indexValue = fastSampler.isSample(openvdb::Vec3R(10.5, -100.2, 50.3)); - -// Compute the value of the grid at a location in world space. -worldValue = fastSampler.wsSample(openvdb::Vec3R(0.25, 1.4, -1.1)); -@endcode -Note that when constructing a GridSampler with either a tree or a -value accessor, you must also supply an index-to-world transform. -When constructing a GridSampler with a grid, the grid's transform is used -automatically. - - -@subsection sDualGridSampler Dual Grid Sampler - -It might sometimes be necessary to interpolate values from a source grid -into the index space of a target grid. -If this transformation is to be applied to all of the values in the source grid, -then it is best to use the tools in GridTransformer.h. -For other cases, consider using the -@vdblink::tools::DualGridSampler DualGridSampler@endlink class. -Like the GridSampler class, this class can be used with grids, trees or value -accessors. -In addition, DualGridSampler checks if the source and target grids are aligned -(that is, they have the same transform), in which case it avoids unnecessary -interpolation. - -@code -#include -#include - -const GridType sourceGrid = ...; - -// Instantiate the DualGridSampler template on the grid type and on -// a box sampler for thread-safe but uncached trilinear interpolation. -openvdb::tools::DualGridSampler - sampler(sourceGrid, targetGrid.constTransform()); - -// Compute the value of the source grid at a location in the -// target grid's index space. -GridType::ValueType value = sampler(openvdb::Coord(-23, -50, 202)); - -// Request a value accessor for accelerated access to the source grid. -// (Because value accessors employ a cache, it is important to declare -// one accessor per thread.) -GridType::ConstAccessor accessor = sourceGrid.getConstAccessor(); - -// Instantiate the DualGridSampler template on the accessor type and on -// a box sampler for accelerated trilinear interpolation. -openvdb::tools::DualGridSampler - fastSampler(accessor, sourceGrid.constTransform(), targetGrid.constTransform()); - -// Compute the value of the source grid at a location in the -// target grid's index space. -value = fastSampler(openvdb::Coord(-23, -50, 202)); -@endcode -Note that interpolation is done by invoking a DualGridSampler as a functor, -in contrast to the more general-purpose GridSampler. - - - -@section sXformTools Transforming grids - -@subsection sResamplingTools Geometric transformation -A @vdblink::tools::GridTransformer GridTransformer@endlink applies a -geometric transformation to an input grid using one of several sampling -schemes, and stores the result in an output grid. The operation is -multithreaded by default, though threading can be disabled by calling -@vdblink::tools::GridTransformer::setThreaded() setThreaded(false)@endlink. -A @c GridTransformer object can be reused to apply the same transformation -to multiple input grids, optionally using different sampling schemes. -@code -#include -#include - -openvdb::FloatGrid::Ptr - sourceGrid = ... - targetGrid = ...; - -// Get the source and target grids' index space to world space transforms. -const openvdb::math::Transform - &sourceXform = sourceGrid->transform(), - &targetXform = targetGrid->transform(); -// Compute a source grid to target grid transform. -// (For this example, we assume that both grids' transforms are linear, -// so that they can be represented as 4 x 4 matrices.) -openvdb::Mat4R xform = - sourceXform.baseMap()->getAffineMap()->getMat4() * - targetXform.baseMap()->getAffineMap()->getMat4().inverse(); - -// Create the transformer. -openvdb::tools::GridTransformer transformer(xform); - -// Resample using nearest-neighbor interpolation. -transformer.transformGrid( - *sourceGrid, *targetGrid); - -// Resample using trilinear interpolation. -transformer.transformGrid( - *sourceGrid, *targetGrid); - -// Resample using triquadratic interpolation. -transformer.transformGrid( - *sourceGrid, *targetGrid); - -// Prune the target tree for optimal sparsity. -targetGrid->tree().prune(); -@endcode - - -@subsection sValueXformTools Value transformation - -This example uses @vdblink::tools::foreach() tools::foreach()@endlink to -multiply all values (both tile and voxel and both active and inactive) -of a scalar, floating-point grid by two: -@code -#include -#include - -// Define a local function that doubles the value to which the given -// value iterator points. -struct Local { - static inline void op(const openvdb::FloatGrid::ValueAllIter& iter) { - iter.setValue(*iter * 2); - } -}; - -openvdb::FloatGrid::Ptr grid = ...; - -// Apply the function to all values. -openvdb::tools::foreach(grid->beginValueAll(), Local::op); -@endcode - -This example uses @vdblink::tools::foreach() tools::foreach()@endlink to -rotate all active vectors of a vector-valued grid by 45 degrees about the -@em y axis: -@code -#include -#include - -// Define a functor that multiplies the vector to which the given -// value iterator points by a fixed matrix. -struct MatMul { - openvdb::math::Mat3s M; - MatMul(const openvdb::math::Mat3s& mat): M(mat) {} - inline void operator()(const openvdb::Vec3SGrid::ValueOnIter& iter) const { - iter.setValue(M.transform(*iter)); - } -}; - -openvdb::Vec3SGrid::Ptr grid = ...; - -// Construct the rotation matrix. -openvdb::math::Mat3s rot45 = - openvdb::math::rotation(openvdb::math::Y_AXIS, M_PI_4); - -// Apply the functor to all active values. -openvdb::tools::foreach(grid->beginValueOn(), MatMul(rot45)); -@endcode - -@vdblink::tools::transformValues() tools::transformValues()@endlink is -similar to @vdblink::tools::foreach() tools::foreach()@endlink, but it populates -an output grid with transformed values from an input grid that may have a -different value type. The following example populates a scalar, -floating-point grid with the lengths of all active vectors from a -vector-valued grid -(like @vdblink::tools::magnitude() tools::magnitude()@endlink): -@code -#include -#include - -// Define a local function that, given an iterator pointing to a vector value -// in an input grid, sets the corresponding tile or voxel in a scalar, -// floating-point output grid to the length of the vector. -struct Local { - static inline void op( - const openvdb::Vec3SGrid::ValueOnCIter& iter, - openvdb::FloatGrid::ValueAccessor& accessor) - { - if (iter.isVoxelValue()) { // set a single voxel - accessor.setValue(iter.getCoord(), iter->length()); - } else { // fill an entire tile - openvdb::CoordBBox bbox; - iter.getBoundingBox(bbox); - accessor.getTree().fill(bbox, iter->length()); - } - } -}; - -openvdb::Vec3SGrid::ConstPtr inGrid = ...; - -// Create a scalar grid to hold the transformed values. -openvdb::FloatGrid::Ptr outGrid = openvdb::FloatGrid::create(); - -// Populate the output grid with transformed values. -openvdb::tools::transformValues(inGrid->cbeginValueOn(), *outGrid, Local::op); -@endcode - - - -@section sCombiningGrids Combining grids - -The following examples show various ways in which a pair of grids can be -combined in @ref subsecVoxSpace "index space". The assumption is that index -coordinates @ijk in both grids correspond to the same physical, @ref -subsecWorSpace "world space" location. When the grids have different -transforms, it is usually necessary to first @ref sResamplingTools "resample" -one grid into the other grid's @ref subsecVoxSpace "index space". - -@subsection sCsgTools Level set CSG operations -The level set CSG functions in tools/Composite.h operate on pairs of grids -of the same type, using sparse traversal for efficiency. These operations -always leave the second grid empty. -@code -#include -#include - -// Two grids of the same type containing level set volumes -openvdb::FloatGrid::Ptr gridA(...), gridB(...); - -// Save copies of the two grids; CSG operations always modify -// the A grid and leave the B grid empty. -openvdb::FloatGrid::ConstPtr - copyOfGridA = gridA->deepCopy(), - copyOfGridB = gridB->deepCopy(); - -// Compute the union (A u B) of the two level sets. -openvdb::tools::csgUnion(*gridA, *gridB); - -// Restore the original level sets. -gridA = copyOfGridA->deepCopy(); -gridB = copyOfGridB->deepCopy(); - -// Compute the intersection (A n B) of the two level sets. -openvdb::tools::csgIntersection(gridA, gridB); - -// Restore the original level sets. -gridA = copyOfGridA->deepCopy(); -gridB = copyOfGridB->deepCopy(); - -// Compute the difference (A / B) of the two level sets. -openvdb::tools::csgDifference(gridA, gridB); -@endcode - - -@subsection sCompTools Compositing operations -Like the @ref sCsgTools "CSG operations", the compositing functions in -tools/Composite.h operate on pairs of grids of the same type, and they -always leave the second grid empty. -@code -#include -#include - -// Two grids of the same type -openvdb::FloatGrid::Ptr gridA = ..., gridB = ...; - -// Save copies of the two grids; compositing operations always -// modify the A grid and leave the B grid empty. -openvdb::FloatGrid::ConstPtr - copyOfGridA = gridA->deepCopy(), - copyOfGridB = gridB->deepCopy(); - -// At each voxel, compute a = max(a, b). -openvdb::tools::compMax(*gridA, *gridB); - -// Restore the original grids. -gridA = copyOfGridA->deepCopy(); -gridB = copyOfGridB->deepCopy(); - -// At each voxel, compute a = min(a, b). -openvdb::tools::compMin(*gridA, *gridB); - -// Restore the original grids. -gridA = copyOfGridA->deepCopy(); -gridB = copyOfGridB->deepCopy(); - -// At each voxel, compute a = a + b. -openvdb::tools::compSum(*gridA, *gridB); - -// Restore the original grids. -gridA = copyOfGridA->deepCopy(); -gridB = copyOfGridB->deepCopy(); - -// At each voxel, compute a = a * b. -openvdb::tools::compMul(*gridA, *gridB); -@endcode - - -@subsection sCombineTools Generic combination -The @vdblink::tree::Tree::combine() Tree::combine()@endlink family of -methods apply a user-supplied operator to pairs of corresponding values -of two trees. These methods are efficient because they take into account -the sparsity of the trees; they are not multithreaded, however. - -This example uses the @vdblink::tree::Tree::combine() Tree::combine()@endlink -method to compute the difference between corresponding voxels of two -floating-point grids: -@code -#include - -// Define a local function that subtracts two floating-point values. -struct Local { - static inline void diff(const float& a, const float& b, float& result) { - result = a - b; - } -}; - -openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; - -// Compute the difference between corresponding voxels of aGrid and bGrid -// and store the result in aGrid, leaving bGrid empty. -aGrid->tree().combine(bGrid->tree(), Local::diff); -@endcode - -Another @vdblink::tree::Tree::combine() Tree::combine()@endlink example, -this time using a functor to preserve state: -@code -#include - -// Define a functor that computes f * a + (1 - f) * b for pairs of -// floating-point values a and b. -struct Blend { - Blend(float f): frac(f) {} - inline void operator()(const float& a, const float& b, float& result) const { - result = frac * a + (1.0 - frac) * b; - } - float frac; -}; - -openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; - -// Compute a = 0.25 * a + 0.75 * b for all corresponding voxels of -// aGrid and bGrid. Store the result in aGrid and empty bGrid. -aGrid->tree().combine(bGrid->tree(), Blend(0.25)); -@endcode - -The @vdblink::tree::Tree::combineExtended() Tree::combineExtended()@endlink -method invokes a function of the form void f(CombineArgs\& args), -where the @vdblink::CombineArgs CombineArgs@endlink object encapsulates an -@em a and a @em b value and their active states as well as a result value -and its active state. In the following example, voxel values in -floating-point @c aGrid are replaced with corresponding values from -floating-point @c bGrid (leaving @c bGrid empty) wherever the @em b values -are larger. The active states of any transferred values are preserved. -@code -#include - -// Define a local function that retrieves a and b values from a CombineArgs -// struct and then sets the result member to the maximum of a and b. -struct Local { - static inline void max(CombineArgs& args) { - if (args.b() > args.a()) { - // Transfer the B value and its active state. - args.setResult(args.b()); - args.setResultIsActive(args.bIsActive()); - } else { - // Preserve the A value and its active state. - args.setResult(args.a()); - args.setResultIsActive(args.aIsActive()); - } - } -}; - -openvdb::FloatGrid::Ptr aGrid = ..., bGrid = ...; - -aGrid->tree().combineExtended(bGrid->tree(), Local::max); -@endcode - -Like @c combine(), @vdblink::tree::Tree::combine2() Tree::combine2()@endlink -applies an operation to pairs of corresponding values of two trees. -However, @c combine2() writes the result to a third, output tree and does -not modify either of the two input trees. (As a result, it is less -space-efficient than the @c combine() method.) Here, the voxel differencing -example above is repeated using @c combine2(): -@code #include - - -struct Local { - static inline void diff(const float& a, const float& b, float& result) { - result = a - b; - } -}; - -openvdb::FloatGrid::ConstPtr aGrid = ..., bGrid = ...; -openvdb::FloatGrid::Ptr resultGrid = openvdb::FloatGrid::create(); - -// Combine aGrid and bGrid and write the result into resultGrid. -// The input grids are not modified. -resultGrid->tree().combine2(aGrid->tree(), bGrid->tree(), Local::diff); -@endcode -An @vdblink::tree::Tree::combine2Extended() extended combine2()@endlink -is also available. - - - -@section sGenericProg Generic programming - -@subsection sTypedGridMethods Calling Grid methods -A common task is to perform some operation on all of the grids in a file, -where the operation involves @vdblink::Grid Grid@endlink method calls -and the grids are of different types. -Only a handful of @c Grid methods, such as -@vdblink::Grid::activeVoxelCount() activeVoxelCount()@endlink, -are virtual and can be called through a @vdblink::GridBase GridBase@endlink -pointer; most are not, because they require knowledge of the Grid's -value type. -For example, one might want to @vdblink::tree::Tree::prune() prune()@endlink -the trees of all of the grids in a file regardless of their type, but -@c Tree::prune() is non-virtual because it accepts an optional pruning -tolerance argument whose type is the grid's value type. - -The @c processTypedGrid() function below makes this kind of task easier. -It is called with a @c GridBase pointer and a functor whose call operator -accepts a pointer to a @c Grid of arbitrary type. The call operator should -be templated on the grid type and, if necessary, overloaded for specific -grid types. - -@code -template -void processTypedGrid(openvdb::GridBase::Ptr grid, OpType& op) -{ -#define CALL_OP(GridType) \ - op.template operator()(openvdb::gridPtrCast(grid)) - - if (grid->isType()) CALL_OP(openvdb::BoolGrid); - else if (grid->isType()) CALL_OP(openvdb::FloatGrid); - else if (grid->isType()) CALL_OP(openvdb::DoubleGrid); - else if (grid->isType()) CALL_OP(openvdb::Int32Grid); - else if (grid->isType()) CALL_OP(openvdb::Int64Grid); - else if (grid->isType()) CALL_OP(openvdb::Vec3IGrid); - else if (grid->isType()) CALL_OP(openvdb::Vec3SGrid); - else if (grid->isType()) CALL_OP(openvdb::Vec3DGrid); - else if (grid->isType()) CALL_OP(openvdb::StringGrid); - -#undef CALL_OP -} -@endcode - -The following example shows how to use @c processTypedGrid() to implement -a generic pruning operation for grids of all built-in types: -@code -#include - -// Define a functor that prunes the trees of grids of arbitrary type -// with a fixed pruning tolerance. -struct PruneOp { - double tolerance; - PruneOp(double t): tolerance(t) {} - - template - void operator()(typename GridType::Ptr grid) const - { - grid->tree().prune(typename GridType::ValueType(tolerance)); - } - // Overload to handle string-valued grids - void operator()(openvdb::StringGrid::Ptr grid) const - { - grid->tree().prune(); - } -}; - -// Read all grids from a file. -openvdb::io::File file("mygrids.vdb"); -file.open(); -openvdb::GridPtrVecPtr myGrids = file.getGrids(); -file.close(); - -// Prune each grid with a tolerance of 1%. -const PruneOp pruner(/*tolerance=*/0.01); -for (openvdb::GridPtrVecIter iter = myGrids->begin(); - iter != myGrids->end(); ++iter) -{ - openvdb::GridBase::Ptr grid = *iter; - processTypedGrid(grid, pruner); -} -@endcode - -*/ diff --git a/openvdb_3_0_0_library/doc/faq.txt b/openvdb_3_0_0_library/doc/faq.txt deleted file mode 100755 index 1066307..0000000 --- a/openvdb_3_0_0_library/doc/faq.txt +++ /dev/null @@ -1,241 +0,0 @@ -/** - -@page faq Frequently Asked Questions - -@section Contents -- @ref sWhatIsVDB -- @ref sWhatLicense -- @ref sWhatCLA -- @ref sWhyUseVDB -- @ref sVersionNumbering -- @ref sGeneralizedOctree -- @ref sLevelSet -- @ref sCustomizeVDB -- @ref sAdaptiveGrid -- @ref sMeaningOfVDB -- @ref sAccessor -- @ref sValue -- @ref sState -- @ref sVoxel -- @ref sTile -- @ref sBackground -- @ref sThreadSafe -- @ref sMaxRes -- @ref sCompareVDB -- @ref sReplaceDense -- @ref sFuture -- @ref sContribute - -@section sWhatIsVDB What is OpenVDB? -OpenVDB is a library comprising a compact hierarchical data structure and a -suite of tools for the efficient manipulation of sparse, possibly time-varying, -volumetric data discretized on a three-dimensional grid. It is based on -VDB, which was developed by Ken Museth at DreamWorks Animation, and it -offers an effectively infinite 3D index space, compact storage (both in -memory and on disk), fast data access (both random and sequential), and -a collection of algorithms specifically optimized for the data structure -for common tasks such as filtering, constructive solid geometry (CSG), -discretization of partial differential equations, voxelization of polygons, -skinning of particles, volumetric compositing and sampling. The technical -details of VDB are described in the paper -"VDB: High-Resolution Sparse Volumes with Dynamic Topology". - -@section sWhatLicense What license is OpenVDB distributed under? -OpenVDB is released under the Mozilla Public License Version 2.0, which is a -free, open source, and detailed software license developed and maintained by -the Mozilla Foundation. It is characterized as a hybridization of the modified -BSD license and GNU General Public License (GPL) that seeks to balance the -concerns of proprietary and open source developers. For more information -about this license, see the -Mozilla FAQ. - -@section sWhatCLA Is there a Contributor License Agreement for OpenVDB? -Yes, developers who wish to contribute code to be considered for inclusion -in the OpenVDB distribution must first complete this -Contributor License Agreement -and submit it to DreamWorks (directions are in the CLA). - -@section sWhyUseVDB Why should I use OpenVDB? -The typical reasons to adopt OpenVDB are if you are storing sparse -data and/or if you are performing sparse computations. OpenVDB -is also effectively unbounded, which makes it very convenient for -applications where the topology of the data is dynamic or unknown. Unlike -many existing sparse data structures, OpenVDB is also optimized for -numerical simulations, multithreaded volume compositing, near real-time -boolean CSG operations, fast random and sequential data access and -voxelization of points and polygons. - -@section sVersionNumbering What is the version numbering system for OpenVDB? -We currently use a major.minor.patch version numbering system, -and with every release of OpenVDB we change one or more of the three numbers. -The patch number is incremented for new features and bug fixes that change -neither the API nor the file format of the library nor the ABIs of the @c Grid -and @c Transform classes and their constituent classes. -The minor version is incremented for releases that change the API without -changing the @c Grid or @c Transform ABIs, and for releases that change -the file format in such a way that older files can still be read. -The major version is incremented when the @c Grid or @c Transform ABIs -change, or when the file format changes in a non-backward-compatible way -(which should be rare). -No release of OpenVDB guarantees ABI compatibility across the entire library, -but rather only for the @c Grid and @c Transform classes, and primarily -to allow third-party app plugins compiled against different versions of -the library to coexist and exchange data. - -@section sCustomizeVDB Can I customize the configuration of OpenVDB? -Yes! OpenVDB is specifically developed to be highly customizable. That is, -the user can define the sizes of all the nodes at each level of a tree as -well as the number of tree levels and the data type of values stored in the -tree. However, note that since OpenVDB makes extensive use of C++ -templating, configurations are fixed at compile time rather than at run -time. This is a fundamental design characteristic of OpenVDB, and it leads -to very high performance, thanks to techniques like inlining and template -metaprogramming. - -@section sGeneralizedOctree Is OpenVDB merely a generalized octree or N-tree? -No! While OpenVDB can conceptually be configured as a (height-balanced) -octree, it is much more than an octree or N-tree. Whereas octrees and -N-trees have fixed branching factors of respectively two and N in each -coordinate direction, OpenVDB's branching factors typically vary between -tree levels and are only limited to be powers of two. To understand why -and also learn about other unique features of OpenVDB, refer to the -paper in ACM Transactions on Graphics. - -@section sLevelSet Is OpenVDB primarily for level set applications? -No! Don't let the fact that OpenVDB can represent and operate so well on -level sets mislead you into thinking that it is limited to or even focusing -on this special type of sparse volumetric application. OpenVDB was developed -for general-purpose volumetric processing and numerical simulation, and we -have even had success using it for volumetric applications that traditionally -call for blocked or dense grids. However, the fact remains that narrow-band -level sets play an essential role in many volumetric applications, and this -explains why OpenVDB includes so many tools and algorithms specifically -for level sets. - -@section sAdaptiveGrid Is OpenVDB an adaptive grid? -Let's first stress that the term "adaptive grid" is somewhat ambiguous. Some -use it to mean a grid that can store data sampled at adaptive voxel sizes -typically derived from a so-called "refinement oracle", whereas others mean -multiple grids with different fixed voxel sizes all sampling the same data. -An example of the former is an octree and of the latter is a mipmap. Since -OpenVDB stores both data values and child nodes at each level of the tree, it -is adaptive only in the first sense, not the second. The level of adaptivity -or refinement between the tree levels is defined by the branching factors of -the nodes, which are fixed at compile time. - -@section sMeaningOfVDB What does "VDB" stand for? -Over the years VDB has been interpreted to mean different things, none of -which are very descriptive: "Voxel Data Base", "Volumetric Data Blocks", -"Volumetric Dynamic B+tree", etc. In early presentations of VDB we even used -a different name, "DB+Grid", which was abandoned to emphasize its -distinction from similarly named, but different, existing sparse data -structures like DT-Grid or DB-Grid. The simple truth is that "VDB" is just a -name. :-) - -@section sAccessor Why are there no coordinate-based access methods on the grid? -It might surprise you that the @c Grid class doesn't directly provide access -to voxels via their @ijk coordinates. Instead, the recommended procedure -is to ask the grid for a "value accessor", which is an accelerator object -that performs bottom-up tree traversal using cached information from -previous traversals. Caching greatly improves performance, but it is -inherently not thread-safe. However, a single grid may have multiple -value accessors, so each thread can safely be assigned its own value accessor. -Uncached—and therefore slower, but thread-safe—random access is possible -through a grid's tree, for example with a call like -grid.tree().getValue(ijk). - -@section sValue How and where does OpenVDB store values? -OpenVDB stores voxel data in a tree with a fixed maximum height (chosen -at compile time), with a root node that has a dynamic branching factor, -with internal nodes that have fixed branching factors, and with leaf nodes -of fixed dimensions. Values can be stored in nodes at all levels of -the tree. Values stored in leaf nodes correspond to individual voxels; -all other values correspond to "tiles" (see below). - -@section sState What are active and inactive values? -Every value in a grid has a binary state that we refer to as its -"active state". -The interpretation of this binary state is application-specific, but -typically an active (on) value is "interesting" in some sense, and an -inactive (off) value is less interesting or uninteresting. -For example, the values in a narrow-band level set are all active, and -values outside the narrow band are all inactive. -Active states of values are stored in very compact bit masks that -support sparse iteration, so visiting all active (or inactive) values -in a grid can be done very efficiently. - -@section sVoxel How are voxels represented in OpenVDB? -Values stored in nodes of type @c LeafNode (which, when they exist, -have a fixed depth), correspond to individual voxels. -These are the smallest addressable units of index space. - -@section sTile What are tiles? -Values stored in nodes of type @c RootNode or @c InternalNode correspond to -regions of index space with a constant value and active state and with -power of two dimensions. We refer to such regions as "tiles". By -construction, tiles have no child nodes. - -@section sBackground What is the background value? -A tree's background value is the value that is returned whenever -one accesses a region of index space that is not explicitly represented by -voxels or tiles in the tree. Thus, you can think of the background value -as the default value associated with an empty tree. -Note that the background value is always inactive! - -@section sThreadSafe Is OpenVDB thread-safe? -Yes and no. If you're asking if OpenVDB can safely be used in a -multithreaded application then the answer is a resounding yes. In fact, many -of the tools included in OpenVDB are multithreaded (using Intel's Threading -Building Blocks library). However, like virtually all data structures that -employ caching and allocate-on-insert, certain operations in OpenVDB are not -thread-safe in the general sense. In particular, it is not safe to retrieve -voxels from a grid while another thread is inserting voxels. -For multithreaded insertion operations we typically assign a separate grid -to each thread and then merge the grids as threads terminate. -This technique works remarkably well: because OpenVDB -is sparse and hierarchical, merging is very efficient. -For more details, please consult the @subpage codeExamples and -Appendix B in the Transactions on Graphics paper. - -@section sMaxRes Is OpenVDB unbounded? -Yes, to within available memory and the 32-bit precision of the coordinates -used to index voxels. And OpenVDB supports signed coordinates, unlike most -existing sparse data structures, so there are almost no restrictions on the -available grid resolution or the index range of OpenVDB grids. - -@section sCompareVDB How does OpenVDB compare to existing sparse data structures? -OpenVDB is very different from existing sparse data structures that you are -likely to have heard of. Foremost it is hierarchical (unlike DT-Grid and -Field3D), supports simulations and dynamic topology (unlike GigaVoxels), is -effectively unbounded (unlike Field3D), and offers fast random and sequential -voxel access. - -@section sReplaceDense Does OpenVDB replace dense grids? -This depends a lot on your application of dense grids and your configuration -of OpenVDB. Clearly, if you are storing or processing sparse data, OpenVDB -will offer a smaller memory footprint and faster (sparse) data processing. -However, even in some cases where both data and computation are dense, OpenVDB -can offer benefits like improved CPU cache performance due to its underlying -blocking and hierarchical tree structure. Exceptions are of course algorithms -that expect dense data to be laid out linearly in memory, or applications that -use very small grids. The simple truth is only a benchmark comparison can tell -you the preferred data structure, but for what it's worth it is our experience -that for the volumetric applications we encounter in production, OpenVDB is -almost always superior. - -@section sFuture What future improvements to OpenVDB are planned? -We are continuing to expand the OpenVDB toolset and improve its performance. -In the near future we plan to add OpenVDB Maya plugins, Python bindings to -more library tools, support for accelerated particle storage and lookup, level -set morphing and measures (e.g. area and volume), more rendering options, a fluid -pressure solver, improved methods for particle skinning, asynchronous I/O, -optimization by means of SIMD instructions, out-of-core support, advection of -densities (vs. level sets) and much more. We would very much like to hear your -suggestions and preferences. - -@section sContribute How can I contribute to OpenVDB? -If you have bug reports or ideas for improvements or new features, -please contact us! If you want to contribute code, please see our -License page. - -*/ diff --git a/openvdb_3_0_0_library/doc/math.txt b/openvdb_3_0_0_library/doc/math.txt deleted file mode 100755 index 5bd11c2..0000000 --- a/openvdb_3_0_0_library/doc/math.txt +++ /dev/null @@ -1,416 +0,0 @@ -/** - -@page transformsAndMaps Transforms and Maps - -@section Contents -- @ref sTransforms - - @ref sLinearTransforms - - @ref sFrustumTransforms - - @ref sCellVsVertex - - @ref sVoxels - - @ref sStaggered -- @ref sMaps - - @ref sGettingMat4 - - @ref sCostOfMaps - - @ref sGradientAndMaps - -@section sTransforms Transforms in OpenVDB -The OpenVDB @vdblink::tree::Tree Tree@endlink is a sparse representation -of a three-dimensional array of voxels, each element of which is addressed via -discrete, three-dimensional index space coordinates, typically in the form of -a @vdblink::math::Coord Coord@endlink. -For example, the following code retrieves the floating-point value of -a voxel with index coordinates (1, 2, 3): -@code -openvdb::FloatGrid grid = ...; -openvdb::FloatGrid::Accessor accessor = grid.getAccessor(); -openvdb::Coord ijk(1,2,3); -float value = accessor.getValue(ijk); -@endcode - -A @vdblink::math::Transform Transform@endlink relates index space coordinates -to world space coordinates that give a spatial context for the discretized data.Translation from index coordinates @ijk to world space coordinates @xyz is -done with a call to the -@vdblink::math::Transform::indexToWorld() indexToWorld@endlink -method, and from world space coordinates to index space coordinates with -a call to @vdblink::math::Transform::worldToIndex() worldToIndex@endlink: -@code -// Create a linear transform that scales i, j and k by 0.1 -openvdb::math::Transform::Ptr linearTransform = - openvdb::math::Transform::createLinearTransform(0.1); - -// Compute the location in world space that is the image of (1,2,3). -// The result will be (0.1, 0.2, 0.3). -openvdb::Coord ijk(1,2,3); -openvdb::Vec3d worldSpacePoint = linearTransform->indexToWorld(ijk); - -// Compute the location in index space that is the pre-image of (0.1, 0.2, 0.3). -// The result will be (1.0, 2.0, 3.0). -openvdb::Vec3d indexSpacePoint = linearTransform->worldToIndex(worldSpacePoint); -@endcode -In the above example, there are two things to notice. -First, world space locations are specified as three-dimensional, -double-precision, floating-point vectors, and second, @c worldToIndex -does not return discrete coordinates, but rather a floating-point vector. -This is a reflection of the fact that not every location in a continuous -world space, i.e., not every @xyz, is the image of discrete integral -coordinates @ijk. - -@subsection sLinearTransforms Linear Transforms -Currently two different types of transforms are supported: linear and -frustum transforms. -A linear transform can be composed of scale, translation, rotation, and shear; -essentially those things that can be mathematically represented by an -invertible, constant-coefficient, @f$3 \times 3@f$ matrix and a translation -(mathematically, an affine map). -An essential feature of a linear transformation is that it treats all regions -of index space equally: a small box in index space about origin @ijk=(0,0,0) -is mapped (sheared, scaled, rotated, etc.) in just the same way that -a small box about any other index point is mapped. -@code -// Create a linear transform from a 4x4 matrix (identity in this example). -openvdb::math::Mat4d mat = openvdb::math::Mat4d::identity(); -openvdb::math::Transform::Ptr linearTransform = - openvdb::math::Transform::createLinearTransform(mat); - -// Rotate the transform by 90 degrees about the X axis. -// As a result the j-index will now map into the -z physical direction, -// and the k-index will map to the +y physical direction. -linearTransform->preRotate(M_PI/2, openvdb::math::X_AXIS); -@endcode - -@subsection sFrustumTransforms Frustum Transforms -The frustum transform is a nonlinear transform that treats different -index points differently. -And while the linear transform can be applied to any point in index -or world space, the frustum transform is designed to operate on a subset -of space. Specifically, it transforms a given box in index space to -a tapered box in world space that is a frustum of a rectangular pyramid. -@code -// Create the bounding box that will be mapped by the transform into -// the shape of a frustum. -// The points (0,0,0), (100,0,0), (0,50,0) and (100,50,0) will map to -// the corners of the near plane of the frustum, while the corners -// of the far plane will be the images of (0,0,120), (100,0,120), -// (0,50,120) and (100,50,120). -const openvdb::math::BBoxd bbox(/*min=*/openvdb::math::Vec3d(0,0,0), - /*max=*/openvdb::math::Vec3d(100,50,120)); - -// The far plane of the frustum will be twice as big as the near plane. -const double taper = 2; - -// The depth of the frustum will be 10 times the x-width of the near plane. -cosnt double depth = 10; - -// The x-width of the frustum in world space units -const double xWidth = 100; - -// Construct a frustum transform that results in a frustum whose -// near plane is centered on the origin in world space. -openvdb::math::Transform::Ptr frustumTransform = - openvdb::math:::Transform::createFrustumTransform( - bbox, taper, depth, xWidth); - -// The frustum shape can be rotated, scaled, translated and even -// sheared if desired. For example, the following call translates -// the frustum by 10,15,0 in world space: -frustumTransform->postTranslate(openvdb::math::Vec3d(10,15,0)); - -// Compute the world space image of a given point within -// the index space bounding box that defines the frustum. -openvdb::Coord ijk(20,10,18); -openvdb::Vec3d worldLocation = frustumTransform->indexToWorld(ijk); -@endcode - -@subsection sCellVsVertex Cell-Centered vs. Vertex-Centered Transforms -When partitioning world space with a regular grid, two popular -configurations are cell-centered and vertex-centered grids. This is really -a question of interpretation and transforms. - -The cell-centered interpretation imagines world space as divided -into discrete cells (e.g., cubes) centered on the image of the -index-space lattice points. -So the physical location @xyz that is the image (result of @c indexToWorld) -of a lattice point @ijk is the center of a cube. -In the vertex-centered approach, the images of the lattice points form the -vertices of cells, so the location @xyz would be a corner, not the -center, of a cube. - -The link between transforms and cell-centered or vertex-centered -partitioning of world space is tenuous. -It boils down to this: the “first” cell vertex often is aligned -with the origin. -In the cell-centered case, when the cells are cubes of length @f$\Delta@f$ -on a side, the transform -@f$(x,y,z) = (\Delta i + \Delta/2, \Delta j + \Delta/2, \Delta k + \Delta /2 )@f$ -will place the center of the first cube (i.e., the image of @f$(0,0,0)@f$) -at the world space location of @f$(\Delta/2, \Delta/2, \Delta/2)@f$, -and the cube will have walls coincident with the @f$x=0@f$, @f$y=0@f$ -and @f$z=0@f$ planes. -Using the OpenVDB transforms to create a so-called cell-centered transform -could be done like this: -@code -// -- Constructing a uniform, cell-centered transform -- - -// The grid spacing -const double delta = 0.1; - -// The offset to cell-center points -const openvdb::math::Vec3d offset(delta/2., delta/2., delta/2.); - -// A linear transform with the correct spacing -openvdb::math::Transform::Ptr transform = - openvdb::math:::Transform::createLinearTransform(delta); - -// Add the offset. -transform->postTranslate(offset); -@endcode -In contrast, for the vertex-centered partitions of space the first -vertex is just the image of the first lattice point @f$ijk = (0,0,0)@f$, -and the transform would lack the offset used in the cell-centered case; -so it would simply be @f$(x,y,z) = (\Delta i , \Delta j ,\Delta k)@f$ -@code -// -- Constructing a uniform, vertex-centered transform -- - -// The grid spacing -const double delta = 0.1; - -// A linear transform with the correct spacing -openvdb::math::Transform::Ptr transform = - openvdb::math:::Transform::createLinearTransform(delta); -@endcode - -@subsection sVoxels Voxel Interpretations -A similar and often related concept to cell- and vertex-centered -partitioning of world space is the idea of a voxel. -A voxel historically refers to the volumetric equivalent of a pixel -and as such implies a small region of world space. -A voxel could, for instance, be the image under transform of a vertex-centered -(or cell-centered) box in index space. -In this way the voxel can be seen as a generalization of regular grid cells. -The interpretation of data stored in a grid can be related to the concept -of a voxel but need not be. -An application might interpret the grid value indexed by @ijk as the -spatial average of a quantity in a defined world-space voxel centered -on the image of that lattice point. -But in other situations the value stored at @ijk might be a discrete sample -taken from a single point in world space. - -The @vdblink::math::Transform Transform@endlink class does include -methods such as @vdblink::math::Transform::voxelSize() voxelSize@endlink -and @vdblink::math::Transform::voxelVolume() voxelVolume@endlink that suppose -a particular interpretation of a voxel. -They assume a voxel that is the image of a vertex-centered cube in index space, -so the @c voxelSize methods return the lengths of line segments in world space -that connect vertices: -@code -openvdb::Coord ijk(0,0,0); -openvdb::Coord tmp0(1,0,0), tmp1(0,1,0), tmp2(0,0,1); - -openvdb::math::Vec3d size; -size.x() = (xform.indexToWorld(ijk + tmp0) - xform.indexToWorld(ijk)).length(); -size.y() = (xform.indexToWorld(ijk + tmp1) - xform.indexToWorld(ijk)).length(); -size.z() = (xform.indexToWorld(ijk + tmp2) - xform.indexToWorld(ijk)).length(); - -// The voxelSize() for the voxel at (0,0,0) is consistent with -// the computation above. -assert(xform.voxelSize(ijk) == size); -@endcode -In the case where the transform is linear, the result of @c voxelSize -will be independent of the actual location @ijk, but the voxel size for a -nonlinear transform such as a frustum will be spatially varying. -The related @c voxelVolume can not in general be computed from the -@c voxelSize, because there is no guarantee that a general transform -will convert a cube-shaped voxel into another cube. -As a result, the @c voxelVolume actually returns the determinant of the -transform, which will be a correct measure of volume even if the voxel -is sheared into a general parallelepiped. - -@subsection sStaggered Staggered Velocity Grids -Staggered velocity data is often used in fluid simulations, and the -relationship between data interpretation and transforms is -somewhat peculiar when using a vector grid to hold -staggered velocity data. -In this case the lattice point @ijk identifies a cell in world space -by mapping to the cell’s center, but each element of the velocity -vector is identified with a different face of the cell. -The first element of the vector is identified with the image of the -@f$(i-1/2,j,k)@f$ face, the second element with @f$(i,j-1/2,k)@f$, -and the third element with @f$(i,j,k-1/2)@f$. - - -@section sMaps Maps in OpenVDB Transforms -The actual work of a @vdblink::math::Transform Transform@endlink is performed -by an implementation object called a @vdblink::math::MapBase Map@endlink. -The map in turn is a polymorphic object whose derived types are designed to -optimally represent the most common transformations. -Specifically, the @vdblink::math::Transform Transform@endlink holds a -@vdblink::math::MapBase MapBase@endlink pointer to a derived type that -has been simplified to minimize calculations. -When the transform is updated by prepending or appending a linear operation -(e.g., with @vdblink::math::Transform::preRotate() preRotate@endlink), -the implementation map is recomputed and simplified if possible. -For example, in many level-set-oriented applications the transform -between index space and world space is simply a uniform scaling of the -index points, i.e., @f$(x,y,z) = (\Delta i, \Delta j, \Delta k)@f$, -where @f$\Delta@f$ has some world space units. -For transforms such as this, the implementation is a -@vdblink::math::UniformScaleMap UniformScaleMap@endlink. -@code -// Create a linear transform that scales i, j and k by 0.1 -openvdb::math::Transform::Ptr linearTransform = - openvdb::math::Transform::createLinearTransform(0.1); - -// Create an equivalent map. -openvdb::math::UniformScaleMap uniformScale(0.1); - -// At this time the map holds a openvdb::math::UniformScaleMap. -assert(linearTransform->mapType() == openvdb::math::UniformScaleMap::type()); - -openvdb::Coord ijk(1,2,3); - -// Applying the transform... -openvdb::math::Vec3d transformResult = linearTransform->indexToWorld(ijk); - -// ...is equivalent to applying the map. -openvdb::math::Vec3d mapResult = uniformScale.applyMap(ijk); - -assert(mapResult == transformResult); -@endcode - -There are specialized maps for a variety of common linear transforms: -pure translation (@vdblink::math::TranslationMap TranslationMap@endlink), -uniform scale (@vdblink::math::UniformScaleMap UniformScaleMap@endlink), -uniform scale and translation -(@vdblink::math::UniformScaleTranslateMap UniformScaleTranslateMap@endlink), -non-uniform scale (@vdblink::math::ScaleMap ScaleMap@endlink), and -non-uniform scale and translation -(@vdblink::math::ScaleTranslateMap ScaleTranslateMap@endlink). -A general affine map (@vdblink::math::AffineMap AffineMap@endlink) is used -for all other cases (those that include non-degenerate rotation or shear). - -@subsection sGettingMat4 An Equivalent Matrix Representation -The matrix representation used within OpenVDB adheres to the minority -convention of right-multiplication of the matrix against a vector: -@code -// Example matrix transform that scales, next translates, -// and finally rotates an incoming vector -openvdb::math::Mat4d transform = openvdb::math::Mat4d::identity(); -transform.preScale(openvdb::math::Vec3d(2,3,2)); -transform.postTranslate(openvdb::math::Vec3d(1,0,0)); -transform.postRotate(openvdb::math::X_AXIS, M_PI/3.0); - -// Location of a point in index space -openvdb::math::Vec3d indexSpace(1,2,3); - -// Apply the transform by right-multiplying the matrix. -openvdb::math::Vec3d worldSpace = indexSpace * transform; -@endcode -Any linear map can produce an equivalent -@vdblink::math::AffineMap AffineMap@endlink, which in turn can produce -an equivalent @f$4 \times 4@f$ matrix. -Starting with a linear transform one can produce a consistent matrix as follows: -@code -openvdb::math::Mat4d matrix; -if (transform->isLinear()) { - // Get the equivalent 4x4 matrix. - matrix = transform->getBaseMap()->getAffineMap()->getMat4(); -} -@endcode - -This could be used as an intermediate form when constructing new linear -transforms by combining old ones. -@code -// Get the matrix equivalent to linearTransformA. -openvdb::math::Mat4d matrixA = - linearTransformA->getBaseMap()->getAffineMap()->getMat4(); - -// Invert the matrix equivalent to linearTransformB. -openvdb::math::Mat4d matrixBinv = - (linearTransformB->getBaseMap()->getAffineMap()->getMat4()).inverse(); - -// Create a new transform that maps the index space of linearTransformA -// to the index space of linearTransformB. -openvdb::math::Transform::Ptr linearTransformAtoB = - openvdb::math::Trasform::createLinearTransform(matrixA * matrixBinv); -@endcode -Notice that in the above example, the internal representation used by -the transform will be simplified if possible to use one of the various -map types. - -@subsection sCostOfMaps Working Directly with Maps -Accessing a transform’s map through virtual function calls -introduces some overhead and precludes compile-time optimizations -such as inlining. -For this reason, the more computationally intensive OpenVDB tools are -templated to work directly with any underlying map. -This allows the tools direct access to the map’s simplified -representation and gives the compiler a free hand to inline. - -Maps themselves know nothing of index space and world space, but are -simply functions @f$x_{range} = f(x_{domain})@f$ that map 3-vectors from -one space (the domain) to another (the range), or from the range back to -the domain (@f$x_{domain} = f^{-1}(x_{range})@f$), by means of the methods -@vdblink::math::MapBase::applyMap() applyMap@endlink and -@vdblink::math::MapBase::applyInverseMap() applyInverseMap@endlink. - -@code -// Create a simple uniform scale map that scales by 10. -openvdb::math::UniformScaleMap usm(10.0); - -// A point in the domain -openvdb::math::Vec3d domainPoint(0,1,3); - -// The resulting range point -openvdb::math::Vec3d rangePoint = usm.applyMap(domainPoint); - -// The map is inverted thus: -assert(domainPoint == usm.applyInverseMap(rangePoint)); -@endcode - -In many tools, the actual map type is not known a priori and -must be deduced at runtime prior to calling the appropriate -map-specific or map-templated code. The type of map currently being -used by a transform can be determined using the -@vdblink::math::Transform::mapType() mapType@endlink method: -@code -// Test for a uniform scale map. -if (transform->mapType() == openvdb::math::UniformScaleMap::type()) { - - // This call would return a null pointer in the case of a map type mismatch. - openvdb::math::UniformScaleMap::ConstPtr usm = - transform->map(); - - // Call a function that accepts UniformScaleMaps. - dofoo(*usm) -} -@endcode - -To simplify this process, the function -@vdblink::math::processTypedMap processTypedMap@endlink has been provided. -It accepts a transform and a functor templated on the map type. - -@subsection sGradientAndMaps Maps and Mathematical Operations -In addition to supporting the mapping of a point from one space to another, -maps also support mapping of local gradients. -This results from use of the chain rule of calculus in computing the -Jacobian of the map. -Essentially, the gradient calculated in the domain of a map can be converted -to the gradient in the range of the map, allowing one to compute a gradient -in index space and then transform it to a gradient in world space. -@code -// Compute the gradient at a point in index space in a -// floating-point grid using the second-order central difference. -openvdb::FloatGrid grid = ...; -openvdb::Coord ijk(2,3,5) -openvdb::math::Vec3d isGrad = - openvdb::math::ISGradient::result(grid, ijk); - -// Apply the inverse Jacobian transform to convert the result to the -// gradient in the world space defined by a map that scales index space -// to create voxels of size 0.1 x 0.2 x 0.1 -openvdb::math::ScaleMap scalemap(0.1, 0.2, 0.1); -openvdb::math::Vec3d wsGrad = scalemap.applyIJT(isGrad); -@endcode - -*/ diff --git a/openvdb_3_0_0_library/doc/python.txt b/openvdb_3_0_0_library/doc/python.txt deleted file mode 100755 index e3a6d86..0000000 --- a/openvdb_3_0_0_library/doc/python.txt +++ /dev/null @@ -1,652 +0,0 @@ -/** - -@page python Using OpenVDB in Python - -This section describes the OpenVDB Python module and includes Python code -snippets and some complete programs that illustrate how to perform common tasks. -(An API reference is also available, -if Epydoc is installed.) -As of OpenVDB 2.0, the Python module exposes most of the functionality -of the C++ @vdblink::Grid Grid@endlink class, including I/O, metadata -management, voxel access and iteration, but almost none of the many -@ref secToolUtils "tools". -We expect to add support for tools in forthcoming releases. - -The Python module supports a fixed set of grid types. -If the symbol @c PY_OPENVDB_WRAP_ALL_GRID_TYPES is defined at compile time, -most of the grid types declared in openvdb.h are accessible in Python, -otherwise only @b FloatGrid, @b BoolGrid and @b Vec3SGrid are accessible. -To add support for grids with other value types or configurations, -search for @c PY_OPENVDB_WRAP_ALL_GRID_TYPES in the module source code, -update the code as appropriate and recompile the module. -(It is possible that this process will be streamlined in the future -with a plugin mechanism.) -Note however that adding grid types can significantly increase the time -and memory needed to compile the module and can significantly increase -the size of the resulting executable. -In addition, grids of custom types that are saved to .vdb files -or pickled will not be readable by clients using the standard version -of the module. - -Also note that the @vdblink::tree::Tree Tree@endlink class is not exposed -in Python. -Much of its functionality is either available through the -@vdblink::Grid Grid@endlink or is too low-level to be generally useful -in Python. -Although trees are not accessible in Python, they can of course be operated on -indirectly. -Of note are the grid methods @b copy, which returns a new grid that shares -its tree with the original grid, @b deepCopy, which returns a new grid -that owns its own tree, and @b sharesWith, which reports whether two grids -share a tree. - - - -@section Contents -- @ref sPyBasics -- @ref sPyHandlingMetadata -- @ref sPyAccessors -- @ref sPyIteration -- @ref sPyNumPy -- @ref sPyMeshConversion -- @ref sPyCppAPI - - - -@section sPyBasics Getting started - -The following example is a complete program that illustrates some of the -basic steps to create grids and write them to disk: -@code{.py} -import pyopenvdb as vdb - -# A grid comprises a sparse tree representation of voxel data, -# user-supplied metadata and a voxel space to world space transform, -# which defaults to the identity transform. -# A FloatGrid stores one single-precision floating point value per voxel. -# Other grid types include BoolGrid and Vec3SGrid. The module-level -# attribute pyopenvdb.GridTypes gives the complete list. -cube = vdb.FloatGrid() -cube.fill(min=(100, 100, 100), max=(199, 199, 199), value=1.0) - -# Name the grid "cube". -cube.name = 'cube' - -# Populate another FloatGrid with a sparse, narrow-band level set -# representation of a sphere with radius 50 voxels, located at -# (1.5, 2, 3) in index space. -sphere = vdb.createLevelSetSphere(radius=50, center=(1.5, 2, 3)) - -# Associate some metadata with the grid. -sphere['radius'] = 50.0 - -# Associate a scaling transform with the grid that sets the voxel size -# to 0.5 units in world space. -sphere.transform = vdb.createLinearTransform(voxelSize=0.5) - -# Name the grid "sphere". -sphere.name = 'sphere' - -# Write both grids to a VDB file. -vdb.write('mygrids.vdb', grids=[cube, sphere]) -@endcode - -This example shows how to read grids from files, and some ways to modify -grids: -@code{.py} -import pyopenvdb as vdb - -# Read a .vdb file and return a list of grids populated with -# their metadata and transforms, but not their trees. -filename = 'mygrids.vdb' -grids = vdb.readAllGridMetadata(filename) - -# Look for and read in a level-set grid that has certain metadata. -sphere = None -for grid in grids: - if (grid.gridClass == vdb.GridClass.LEVEL_SET and 'radius' in grid - and grid['radius'] > 10.0): - sphere = vdb.read(filename, grid.name) - else: - print 'skipping grid', grid.name - -if sphere: - # Convert the level set sphere to a narrow-band fog volume, in which - # interior voxels have value 1, exterior voxels have value 0, and - # narrow-band voxels have values varying linearly from 0 to 1. - - outside = sphere.background - width = 2.0 * outside - - # Visit and update all of the grid's active values, which correspond to - # voxels in the narrow band. - for iter in sphere.iterOnValues(): - dist = iter.value - iter.value = (outside - dist) / width - - # Visit all of the grid's inactive tile and voxel values and update - # the values that correspond to the interior region. - for iter in sphere.iterOffValues(): - if iter.value < 0.0: - iter.value = 1.0 - iter.active = False - - # Set exterior voxels to 0. - sphere.background = 0.0 - - sphere.gridClass = vdb.GridClass.FOG_VOLUME -@endcode - - - -@section sPyHandlingMetadata Handling metadata - -Metadata of various types (string, bool, int, float, and 2- and 3-element -sequences of ints or floats) can be attached both to individual grids -and to files on disk, either by supplying a Python dictionary of -(name, value) pairs or, in the case of grids, through -a dictionary-like interface. - -Add (name, value) metadata pairs to a grid as you would to a dictionary. -A new value overwrites an existing value if the name matches an existing name. -@code{.py} ->>> import pyopenvdb as vdb - ->>> grid = vdb.Vec3SGrid() - ->>> grid['vector'] = 'gradient' ->>> grid['radius'] = 50.0 ->>> grid['center'] = (10, 15, 10) - ->>> grid.metadata -{'vector': 'gradient', 'radius': 50.0, 'center': (10, 15, 10)} - ->>> grid['radius'] -50.0 - ->>> 'radius' in grid, 'misc' in grid -(True, False) - -# OK to overwrite an existing value with a value of another type: ->>> grid['center'] = 0.0 - -# A 4-element sequence is not a supported metadata value type: ->>> grid['center'] = (0, 0, 0, 0) - File "", line 1, in -TypeError: metadata value "(0, 0, 0, 0)" of type tuple is not allowed - -# Metadata names must be strings: ->>> grid[0] = (10.5, 15, 30) - File "", line 1, in -TypeError: expected str, found int as argument 1 to __setitem__() -@endcode -Alternatively, replace all or some of a grid’s metadata by supplying -a (name, value) dictionary: -@code{.py} ->>> metadata = { -... 'vector': 'gradient', -... 'radius': 50.0, -... 'center': (10, 15, 10) -... } - -# Replace all of the grid's metadata. ->>> grid.metadata = metadata - ->>> metadata = { -... 'center': [10.5, 15, 30], -... 'scale': 3.14159 -... } - -# Overwrite "center" and add "scale": ->>> grid.updateMetadata(metadata) -@endcode - -Iterate over a grid’s metadata as you would over a dictionary: -@code{.py} ->>> for key in grid: -... print '%s = %s' % (key, grid[key]) -... -vector = gradient -radius = 50.0 -scale = 3.14159 -center = (10.5, 15.0, 30.0) -@endcode - -Removing metadata is also straightforward: -@code{.py} ->>> del grid['vector'] ->>> del grid['center'] ->>> del grid['vector'] # error: already removed - File "", line 1, in -KeyError: 'vector' - ->>> grid.metadata = {} # remove all metadata -@endcode - -Some grid metadata is exposed in the form of properties, either because -it might be frequently accessed (a grid’s name, for example) -or because its allowed values are somehow restricted: -@code{.py} ->>> grid = vdb.createLevelSetSphere(radius=10.0) ->>> grid.metadata -{'class': 'level set'} - ->>> grid.gridClass = vdb.GridClass.FOG_VOLUME ->>> grid.metadata -{'class': 'fog volume'} - -# The gridClass property requires a string value: ->>> grid.gridClass = 123 - File "", line 1, in -TypeError: expected str, found int as argument 1 to setGridClass() - -# Only certain strings are recognized; see pyopenvdb.GridClass -# for the complete list. ->>> grid.gridClass = 'Hello, world.' ->>> grid.metadata -{'class': 'unknown'} - ->>> grid.metadata = {} ->>> grid.vectorType = vdb.VectorType.COVARIANT ->>> grid.metadata -{'vector_type': 'covariant'} - ->>> grid.name = 'sphere' ->>> grid.creator = 'Python' ->>> grid.metadata -{'vector_type': 'covariant', 'name': 'sphere', 'creator': 'Python'} -@endcode -Setting these properties to @c None removes the corresponding metadata, -but the properties retain default values: -@code{.py} ->>> grid.creator = grid.vectorType = None ->>> grid.metadata -{'name': 'sphere'} - ->>> grid.creator, grid.vectorType -('', 'invariant') -@endcode - -Metadata can be associated with a .vdb file at the time the file -is written, by supplying a (name, value) dictionary -as the optional @c metadata argument to the @b write function: -@code{.py} ->>> metadata = { -... 'creator': 'Python', -... 'time': '11:05:00' -... } ->>> vdb.write('mygrids.vdb', grids=grid, metadata=metadata) -@endcode -File-level metadata can be retrieved with either the @b readMetadata -function or the @b readAll function: -@code{.py} ->>> metadata = vdb.readMetadata('mygrids.vdb') ->>> metadata -{'creator': 'Python', 'time': '11:05:00'} - ->>> grids, metadata = vdb.readAll('mygrids.vdb') ->>> metadata -{'creator': 'Python', 'time': '11:05:00'} ->>> [grid.name for grid in grids] -['sphere'] -@endcode - - - -@section sPyAccessors Voxel access - -Grids provide read-only and read/write accessors for voxel lookup via @ijk -index coordinates. -Accessors store references to their parent grids, so a grid will not -be deleted while it has accessors in use. - -@code{.py} ->>> import pyopenvdb as vdb - -# Read two grids from a file. ->>> grids, metadata = vdb.readAll('smoke2.vdb') ->>> [grid.name for grid in grids] -['density', 'v'] - -# Get read/write accessors to the two grids. ->>> dAccessor = grids[0].getAccessor() ->>> vAccessor = grids[1].getAccessor() - ->>> ijk = (100, 103, 101) - ->>> dAccessor.probeValue(ijk) -(0.17614534497261047, True) -# Change the value of a voxel. ->>> dAccessor.setValueOn(ijk, 0.125) ->>> dAccessor.probeValue(ijk) -(0.125, True) - ->>> vAccessor.probeValue(ijk) -((-2.90625, 9.84375, 0.84228515625), True) -# Change the active state of a voxel. ->>> vAccessor.setActiveState(ijk, False) ->>> vAccessor.probeValue(ijk) -((-2.90625, 9.84375, 0.84228515625), False) - -# Get a read-only accessor to one of the grids. ->>> dAccessor = grids[0].getConstAccessor() ->>> dAccessor.setActiveState(ijk, False) - File "", line 1, in -TypeError: accessor is read-only - -# Delete the accessors once they are no longer needed, -# so that the grids can be garbage-collected. ->>> del dAccessor, vAccessor -@endcode - - - -@section sPyIteration Iteration - -Grids provide read-only and read/write iterators over their values. -Iteration is over sequences of value objects (BoolGrid.Values, -FloatGrid.Values, etc.) that expose properties such as the number -of voxels spanned by a value (one, for a voxel value, more than one -for a tile value), its coordinates and its active state. -Value objects returned by read-only iterators are immutable; those -returned by read/write iterators permit assignment to their active state -and value properties, which modifies the underlying grid. -Value objects store references to their parent grids, so a grid will not -be deleted while one of its value objects is in use. - -@code{.py} ->>> import pyopenvdb as vdb - ->>> grid = vdb.read('smoke2.vdb', gridname='v') ->>> grid.__class__.__name__ -'Vec3SGrid' - -# Iterate over inactive values and print the coordinates of the first -# five voxel values and the bounding boxes of the first five tile values. ->>> voxels = tiles = 0 -... N = 5 -... for item in grid.citerOffValues(): # read-only iterator -... if voxels == N and tiles == N: -... break -... if item.count == 1: -... if voxels < N: -... voxels += 1 -... print 'voxel', item.min -... else: -... if tiles < N: -... tiles += 1 -... print 'tile', item.min, item.max -... -tile (0, 0, 0) (7, 7, 7) -tile (0, 0, 8) (7, 7, 15) -tile (0, 0, 16) (7, 7, 23) -tile (0, 0, 24) (7, 7, 31) -tile (0, 0, 32) (7, 7, 39) -voxel (40, 96, 88) -voxel (40, 96, 89) -voxel (40, 96, 90) -voxel (40, 96, 91) -voxel (40, 96, 92) - -# Iterate over and normalize all active values. ->>> from math import sqrt ->>> for item in grid.iterOnValues(): # read/write iterator -... vector = item.value -... magnitude = sqrt(sum(x * x for x in vector)) -... item.value = [x / magnitude for x in vector] -... -@endcode - -For some operations, it might be more convenient to use one of -the grid methods @b mapOn, @b mapOff or @b mapAll. -These methods iterate over a grid’s tiles and voxels -(active, inactive or both, respectively) and replace each value x -with f(x), where f is a callable object. -These methods are not multithreaded. -@code{.py} ->>> import pyopenvdb as vdb ->>> from math import sqrt - ->>> grid = vdb.read('smoke2.vdb', gridname='v') - ->>> def normalize(vector): -... magnitude = sqrt(sum(x * x for x in vector)) -... return [x / magnitude for x in vector] -... ->>> grid.mapOn(normalize) -@endcode - -Similarly, the @b combine method iterates over corresponding pairs of values -(tile and voxel) of two grids @e A and @e B of the same type -(FloatGrid, Vec3SGrid, etc.), replacing values in @e A -with f(a, b), where f is a callable object. -This operation assumes that index coordinates @ijk in both grids correspond -to the same physical, world space location. -Also, the operation always leaves grid @e B empty. -@code{.py} ->>> import pyopenvdb as vdb - ->>> density = vdb.read('smoke2.vdb', gridname='density') ->>> density.__class__.__name__ -'FloatGrid' - ->>> sphere = vdb.createLevelSetSphere(radius=50.0, center=(100, 300, 100)) - ->>> density.combine(sphere, lambda a, b: min(a, b)) -@endcode -For now, @b combine operates only on tile and voxel values, -not on their active states or other attributes. - - - -@section sPyNumPy Working with NumPy arrays - -Large data sets are often handled in Python using -NumPy. -The OpenVDB Python module can optionally be compiled with NumPy support. -With NumPy enabled, the @b copyFromArray and @b copyToArray grid methods -can be used to exchange data efficiently between scalar-valued grids -and three-dimensional NumPy arrays and between vector-valued grids and -four-dimensional NumPy arrays. -@code{.py} ->>> import pyopenvdb as vdb ->>> import numpy - ->>> array = numpy.random.rand(200, 200, 200) ->>> array.dtype -dtype('float64') - -# Copy values from a three-dimensional array of doubles -# into a grid of floats. ->>> grid = vdb.FloatGrid() ->>> grid.copyFromArray(array) ->>> grid.activeVoxelCount() == array.size -True ->>> grid.evalActiveVoxelBoundingBox() -((0, 0, 0), (199, 199, 199)) - -# Copy values from a four-dimensional array of ints -# into a grid of float vectors. ->>> vecarray = numpy.ndarray((60, 70, 80, 3), int) ->>> vecarray.fill(42) ->>> vecgrid = vdb.Vec3SGrid() ->>> vecgrid.copyFromArray(vecarray) ->>> vecgrid.activeVoxelCount() == 60 * 70 * 80 -True ->>> vecgrid.evalActiveVoxelBoundingBox() -((0, 0, 0), (59, 69, 79)) -@endcode - -When copying from a NumPy array, values in the array that are equal to -the destination grid’s background value (or close to it, if the -@c tolerance argument to @b copyFromArray is nonzero) are set to the -background value and are marked inactive. -All other values are marked active. -@code{.py} ->>> grid.clear() ->>> grid.copyFromArray(array, tolerance=0.2) ->>> print '%d%% of copied voxels are active' % ( -... round(100.0 * grid.activeVoxelCount() / array.size)) -80% of copied voxels are active -@endcode - -The optional @c ijk argument specifies the index coordinates of the voxel -in the destination grid into which to start copying values. -That is, array index (0, 0, 0) maps to voxel @ijk. -@code{.py} ->>> grid.clear() ->>> grid.copyFromArray(array, ijk=(-1, 2, 3)) ->>> grid.evalActiveVoxelBoundingBox() -((-1, 2, 3), (198, 201, 202)) -@endcode - -The @b copyToArray method also accepts an @c ijk argument. -It specifies the index coordinates of the voxel to be copied to array -index (0, 0, 0). -@code{.py} ->>> grid = vdb.createLevelSetSphere(radius=10.0) ->>> array = numpy.ndarray((40, 40, 40), int) ->>> array.fill(0) -# Copy values from a grid of floats into -# a three-dimensional array of ints. ->>> grid.copyToArray(array, ijk=(-15, -20, -35)) ->>> array[15, 20] -array([ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, - -3, -3, -3, -3, -3, -3, -3, -3, -3, -3]) -@endcode -@b copyToArray has no @c tolerance argument, because there is no distinction -between active and inactive values in the destination array. - - - -@section sPyMeshConversion Mesh conversion - -Also available if the OpenVDB Python module is compiled with NumPy support -(see @ref sPyNumPy "above") are grid methods to convert polygonal meshes to -level sets (see @vdblink::tools::meshToLevelSet() tools::meshToLevelSet@endlink -for some restrictions) and to convert isosurfaces of scalar-valued grids -to meshes. -@code{.py} ->>> import pyopenvdb as vdb ->>> import numpy - ->>> grid = vdb.read('bunny.vdb', 'ls_bunny') - -# Convert a volume to a quadrilateral mesh. ->>> points, quads = grid.convertToQuads() - -# World-space vertices of the mesh: ->>> points -array([[-14.05082607, -0.10118673, -0.40250054], - [-14.05230808, -0.05570767, -0.45693323], - [-14.05613995, -0.0734246 , -0.42150033], - ..., - [ 7.25201273, 13.25417805, 6.45283508], - [ 7.25596714, 13.31225586, 6.40827513], - [ 7.30518484, 13.21096039, 6.40724468]], dtype=float32) - -# Quadrilateral faces of the mesh, given by -# 4-tuples of indices into the vertex list: ->>> quads -array([[ 5, 2, 1, 4], - [ 11, 7, 6, 10], - [ 14, 9, 8, 13], - ..., - [1327942, 1327766, 1339685, 1339733], - [1339728, 1327921, 1327942, 1339733], - [1339733, 1339685, 1339661, 1339728]], dtype=uint32) - -# Convert the mesh back to a (single-precision) volume. -# Give the resulting grid the original grid's transform. ->>> gridFromQuads = vdb.FloatGrid.createLevelSetFromPolygons( -... points, quads=quads, transform=grid.transform) - - -# Alternatively, mesh a volume adaptively for a lower polygon count. -# Adaptive meshing generates both triangular and quadrilateral faces. ->>> points, triangles, quads = grid.convertToPolygons(adaptivity=0.5) - -# World-space vertices of the mesh: ->>> points -array([[-14.02906322, -0.07213751, -0.49265194], - [-14.11877823, -0.11127799, -0.17118289], - [-13.85006142, -0.08145611, -0.86669081], - ..., - [ 7.31098318, 12.97358608, 6.55133963], - [ 7.20240211, 12.80632019, 6.80356836], - [ 7.23679161, 13.28100395, 6.45595646]], dtype=float32) - -# Triangular faces of the mesh, given by -# triples of indices into the vertex list: ->>> triangles -array([[ 8, 7, 0], - [ 14, 9, 8], - [ 14, 11, 9], - ..., - [22794, 22796, 22797], - [22784, 22783, 22810], - [22796, 22795, 22816]], dtype=uint32) - -# Quadrilateral faces of the mesh, given by -# 4-tuples of indices into the vertex list: ->>> quads -array([[ 4, 3, 6, 5], - [ 8, 9, 10, 7], - [ 11, 12, 10, 9], - ..., - [23351, 23349, 23341, 23344], - [23344, 23117, 23169, 23351], - [23169, 23167, 23349, 23351]], dtype=uint32) - -# Convert the mesh to a double-precision volume. ->>> doubleGridFromPolys = vdb.DoubleGrid.createLevelSetFromPolygons( -... points, triangles, quads, transform=grid.transform) -@endcode - -The mesh representation is similar to that of the commonly-used - -Wavefront .obj file format, -except that the vertex array is indexed starting from 0 rather than 1. -To output mesh data to a file in .obj format, one might do -the following: -@code{.py} ->>> def writeObjFile(filename, points, triangles=[], quads=[]): -... f = open(filename, 'w') -... # Output vertices. -... for xyz in points: -... f.write('v %g %g %g\n' % tuple(xyz)) -... f.write('\n') -... # Output faces. -... for ijk in triangles: -... f.write('f %d %d %d\n' % -... (ijk[0]+1, ijk[1]+1, ijk[2]+1)) # offset vertex indices by one -... for ijkl in quads: -... f.write('f %d %d %d %d\n' % -... (ijkl[0]+1, ijkl[1]+1, ijkl[2]+1, ijkl[3]+1)) -... f.close() -... ->>> mesh = grid.convertToPolygons(adaptivity=0.8) ->>> writeObjFile('bunny.obj', *mesh) -@endcode - - -@section sPyCppAPI C++ glue routines - -Python objects of type @b FloatGrid, @b Vec3SGrid, etc. are backed by -C structs that “inherit” from @c PyObject. -The OpenVDB Python extension module includes public functions that you can -call in your own extension modules to convert between -@vdblink::Grid openvdb::Grids@endlink and PyObjects. -See the pyopenvdb.h reference for a description of these functions -and a usage example. - -Your extension module might need to link against the OpenVDB extension module -in order to access these functions. -On UNIX systems, it might also be necessary to specify the @c RTLD_GLOBAL -flag when importing the OpenVDB module, to allow its symbols to be shared -across modules. -See @b setdlopenflags in the Python @b sys module for one way to do this. - -*/ diff --git a/openvdb_3_0_0_library/doxygen-config b/openvdb_3_0_0_library/doxygen-config deleted file mode 100755 index 39dd2d5..0000000 --- a/openvdb_3_0_0_library/doxygen-config +++ /dev/null @@ -1,1242 +0,0 @@ -# Doxyfile 1.4.7 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = OpenVDB - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 3.0.0 - -ALIASES += vdbnamespace="openvdb::v3_0_0" -PREDEFINED = OPENVDB_VERSION_NAME=v3_0_0 - -PREDEFINED += __declspec(x):= __attribute__(x):= -#EXPAND_AS_DEFINED = \ -# OPENVDB_API \ -# OPENVDB_HOUDINI_API \ -# OPENVDB_EXPORT \ -# OPENVDB_IMPORT \ -# OPENVDB_DEPRECATED -# OPENVDB_STATIC_SPECIALIZATION - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = obj/doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, -# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, -# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, -# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, -# Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = YES - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. - -JAVADOC_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES += ijk="@f$(i,j,k)@f$" -ALIASES += xyz="@f$(x,y,z)@f$" -ALIASES += const="const" -# Use this command to create a link to an OpenVDB class, function, etc. -# Usage is "@vdblink:: @endlink", where is a fully -# namespace-qualified symbol minus the openvdb and version number namespaces -# and is the text of the link. -# Example: @vdblink::tree::RootNode root node@endlink -ALIASES += vdblink="@link @vdbnamespace" - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = YES - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = YES - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = YES - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = NO - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = . \ - io \ - math \ - metadata \ - python/pyopenvdb.h \ - tools \ - tree \ - util \ - doc/doc.txt \ - doc/faq.txt \ - doc/math.txt \ - doc/changes.txt \ - doc/codingstyle.txt \ - doc/api_0_98_0.txt \ - doc/examplecode.txt \ - doc/python.txt - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -#PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = NO - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that a graph may be further truncated if the graph's -# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH -# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), -# the graph is not depth-constrained. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/openvdb_3_0_0_library/io/Archive.cc b/openvdb_3_0_0_library/io/Archive.cc deleted file mode 100755 index 09e45a1..0000000 --- a/openvdb_3_0_0_library/io/Archive.cc +++ /dev/null @@ -1,1362 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Archive.h" - -#include "GridDescriptor.h" -#include "io.h" - -#include -#include -#include - -// Boost.Interprocess uses a header-only portion of Boost.DateTime -#define BOOST_DATE_TIME_NO_LIB -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef _MSC_VER -#include // open_existing_file(), close_file() -extern "C" __declspec(dllimport) bool __stdcall GetFileTime( - void* fh, void* ctime, void* atime, void* mtime); -// boost::interprocess::detail was renamed to boost::interprocess::ipcdetail in Boost 1.48. -// Ensure that both namespaces exist. -namespace boost { namespace interprocess { namespace detail {} namespace ipcdetail {} } } -#else -#include // for struct stat -#include // for stat() -#include // for unlink() -#endif -#include // for std::find_if() -#include // for errno -#include // for getenv() -#include // for std::memcpy() -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -// Indices into a stream's internal extensible array of values used by readers and writers -struct StreamState -{ - static const long MAGIC_NUMBER; - - StreamState(); - ~StreamState(); - - int magicNumber; - int fileVersion; - int libraryMajorVersion; - int libraryMinorVersion; - int dataCompression; - int writeGridStatsMetadata; - int gridBackground; - int gridClass; - int halfFloat; - int mappedFile; - int metadata; -} -sStreamState; - -const long StreamState::MAGIC_NUMBER = - long((uint64_t(OPENVDB_MAGIC) << 32) | (uint64_t(OPENVDB_MAGIC))); - -#ifdef OPENVDB_USE_BLOSC -const uint32_t Archive::DEFAULT_COMPRESSION_FLAGS = (COMPRESS_BLOSC | COMPRESS_ACTIVE_MASK); -#else -const uint32_t Archive::DEFAULT_COMPRESSION_FLAGS = (COMPRESS_ZIP | COMPRESS_ACTIVE_MASK); -#endif - - -//////////////////////////////////////// - - -StreamState::StreamState(): magicNumber(std::ios_base::xalloc()) -{ - // Having reserved an entry (the one at index magicNumber) in the extensible array - // associated with every stream, store a magic number at that location in the - // array belonging to the cout stream. - std::cout.iword(magicNumber) = MAGIC_NUMBER; - std::cout.pword(magicNumber) = this; - - // Search for a lower-numbered entry in cout's array that already contains the magic number. - /// @todo This assumes that the indices returned by xalloc() increase monotonically. - int existingArray = -1; - for (int i = 0; i < magicNumber; ++i) { - if (std::cout.iword(i) == MAGIC_NUMBER) { - existingArray = i; - break; - } - } - - if (existingArray >= 0 && std::cout.pword(existingArray) != NULL) { - // If a lower-numbered entry was found to contain the magic number, - // a coexisting version of this library must have registered it. - // In that case, the corresponding pointer should point to an existing - // StreamState struct. Copy the other array indices from that StreamState - // into this one, so as to share state with the other library. - const StreamState& other = - *static_cast(std::cout.pword(existingArray)); - fileVersion = other.fileVersion; - libraryMajorVersion = other.libraryMajorVersion; - libraryMinorVersion = other.libraryMinorVersion; - dataCompression = other.dataCompression; - writeGridStatsMetadata = other.writeGridStatsMetadata; - gridBackground = other.gridBackground; - gridClass = other.gridClass; - if (other.mappedFile != 0) { // memory-mapped file support was added in OpenVDB 3.0.0 - mappedFile = other.mappedFile; - metadata = other.metadata; - halfFloat = other.halfFloat; - } else { - mappedFile = std::ios_base::xalloc(); - metadata = std::ios_base::xalloc(); - halfFloat = std::ios_base::xalloc(); - } - } else { - // Reserve storage for per-stream file format and library version numbers - // and other values of use to readers and writers. Each of the following - // values is an index into the extensible arrays associated with all streams. - // The indices are common to all streams, but the values stored at those indices - // are unique to each stream. - fileVersion = std::ios_base::xalloc(); - libraryMajorVersion = std::ios_base::xalloc(); - libraryMinorVersion = std::ios_base::xalloc(); - dataCompression = std::ios_base::xalloc(); - writeGridStatsMetadata = std::ios_base::xalloc(); - gridBackground = std::ios_base::xalloc(); - gridClass = std::ios_base::xalloc(); - mappedFile = std::ios_base::xalloc(); - metadata = std::ios_base::xalloc(); - halfFloat = std::ios_base::xalloc(); - } -} - - -StreamState::~StreamState() -{ - // Ensure that this StreamState struct can no longer be accessed. - std::cout.iword(magicNumber) = 0; - std::cout.pword(magicNumber) = NULL; -} - - -//////////////////////////////////////// - - -struct StreamMetadata::Impl -{ - Impl() - : mFileVersion(OPENVDB_FILE_VERSION) - , mLibraryVersion(OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION) - , mCompression(COMPRESS_NONE) - , mGridClass(GRID_UNKNOWN) - , mBackgroundPtr(NULL) - , mHalfFloat(false) - , mWriteGridStats(false) - { - } - - uint32_t mFileVersion; - VersionId mLibraryVersion; - uint32_t mCompression; - uint32_t mGridClass; - const void* mBackgroundPtr; ///< @todo use Metadata::Ptr? - bool mHalfFloat; - bool mWriteGridStats; - MetaMap mGridMetadata; - AuxDataMap mAuxData; -}; // struct StreamMetadata - - -StreamMetadata::StreamMetadata(): mImpl(new Impl) -{ -} - - -StreamMetadata::StreamMetadata(const StreamMetadata& other): mImpl(new Impl(*other.mImpl)) -{ -} - - -StreamMetadata::StreamMetadata(std::ios_base& strm): mImpl(new Impl) -{ - mImpl->mFileVersion = getFormatVersion(strm); - mImpl->mLibraryVersion = getLibraryVersion(strm); - mImpl->mCompression = getDataCompression(strm); - mImpl->mGridClass = getGridClass(strm); - mImpl->mHalfFloat = getHalfFloat(strm); - mImpl->mWriteGridStats = getWriteGridStatsMetadata(strm); -} - - -StreamMetadata::~StreamMetadata() -{ -} - - -StreamMetadata& -StreamMetadata::operator=(const StreamMetadata& other) -{ - if (&other != this) { - mImpl.reset(new Impl(*other.mImpl)); - } - return *this; -} - - -void -StreamMetadata::transferTo(std::ios_base& strm) const -{ - io::setVersion(strm, mImpl->mLibraryVersion, mImpl->mFileVersion); - io::setDataCompression(strm, mImpl->mCompression); - io::setGridBackgroundValuePtr(strm, mImpl->mBackgroundPtr); - io::setGridClass(strm, mImpl->mGridClass); - io::setHalfFloat(strm, mImpl->mHalfFloat); - io::setWriteGridStatsMetadata(strm, mImpl->mWriteGridStats); -} - - -uint32_t StreamMetadata::fileVersion() const { return mImpl->mFileVersion; } -VersionId StreamMetadata::libraryVersion() const { return mImpl->mLibraryVersion; } -uint32_t StreamMetadata::compression() const { return mImpl->mCompression; } -uint32_t StreamMetadata::gridClass() const { return mImpl->mGridClass; } -const void* StreamMetadata::backgroundPtr() const { return mImpl->mBackgroundPtr; } -bool StreamMetadata::halfFloat() const { return mImpl->mHalfFloat; } -bool StreamMetadata::writeGridStats() const { return mImpl->mWriteGridStats; } -MetaMap& StreamMetadata::gridMetadata() { return mImpl->mGridMetadata; } -const MetaMap& StreamMetadata::gridMetadata() const { return mImpl->mGridMetadata; } - -StreamMetadata::AuxDataMap& StreamMetadata::auxData() { return mImpl->mAuxData; } -const StreamMetadata::AuxDataMap& StreamMetadata::auxData() const { return mImpl->mAuxData; } - -void StreamMetadata::setFileVersion(uint32_t v) { mImpl->mFileVersion = v; } -void StreamMetadata::setLibraryVersion(VersionId v) { mImpl->mLibraryVersion = v; } -void StreamMetadata::setCompression(uint32_t c) { mImpl->mCompression = c; } -void StreamMetadata::setGridClass(uint32_t c) { mImpl->mGridClass = c; } -void StreamMetadata::setBackgroundPtr(const void* ptr) { mImpl->mBackgroundPtr = ptr; } -void StreamMetadata::setHalfFloat(bool b) { mImpl->mHalfFloat = b; } -void StreamMetadata::setWriteGridStats(bool b) { mImpl->mWriteGridStats = b; } - - -std::string -StreamMetadata::str() const -{ - std::ostringstream ostr; - ostr << "version: " << libraryVersion().first << "." << libraryVersion().second - << "/" << fileVersion() << "\n"; - ostr << "class: " << GridBase::gridClassToString(static_cast(gridClass())) << "\n"; - ostr << "compression: " << compressionToString(compression()) << "\n"; - ostr << "half_float: " << (halfFloat() ? "true" : "false") << "\n"; - ostr << "write_grid_stats_metadata: " << (writeGridStats() ? "true" : "false") << "\n"; - if (!auxData().empty()) ostr << auxData(); - if (gridMetadata().metaCount() != 0) { - ostr << "grid_metadata:\n" << gridMetadata().str(/*indent=*/" "); - } - return ostr.str(); -} - - -std::ostream& -operator<<(std::ostream& os, const StreamMetadata& meta) -{ - os << meta.str(); - return os; -} - - -namespace { - -template -inline bool -writeAsType(std::ostream& os, const boost::any& val) -{ - if (val.type() == typeid(T)) { - os << boost::any_cast(val); - return true; - } - return false; -} - -} // unnamed namespace - -std::ostream& -operator<<(std::ostream& os, const StreamMetadata::AuxDataMap& auxData) -{ - for (StreamMetadata::AuxDataMap::const_iterator it = auxData.begin(), end = auxData.end(); - it != end; ++it) - { - os << it->first << ": "; - // Note: boost::any doesn't support serialization. - const boost::any& val = it->second; - if (!writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val) - && !writeAsType(os, val)) - { - os << val.type().name() << "(...)"; - } - os << "\n"; - } - return os; -} - - -//////////////////////////////////////// - - -// Memory-mapping a VDB file permits threaded input (and output, potentially, -// though that might not be practical for compressed files or files containing -// multiple grids). In particular, a memory-mapped file can be loaded lazily, -// meaning that the voxel buffers of the leaf nodes of a grid's tree are not allocated -// until they are actually accessed. When access to its buffer is requested, -// a leaf node allocates memory for the buffer and then streams in (and decompresses) -// its contents from the memory map, starting from a stream offset that was recorded -// at the time the node was constructed. The memory map must persist as long as -// there are unloaded leaf nodes; this is ensured by storing a shared pointer -// to the map in each unloaded node. - -class MappedFile::Impl -{ -public: - Impl(const std::string& filename, bool autoDelete) - : mMap(filename.c_str(), boost::interprocess::read_only) - , mRegion(mMap, boost::interprocess::read_only) - , mAutoDelete(autoDelete) - { - mLastWriteTime = this->getLastWriteTime(); - - if (mAutoDelete) { -#ifndef _MSC_VER - // On Unix systems, unlink the file so that it gets deleted once it is closed. - ::unlink(mMap.get_name()); -#endif - } - } - - ~Impl() - { - std::string filename; - if (const char* s = mMap.get_name()) filename = s; - OPENVDB_LOG_DEBUG_RUNTIME("closing memory-mapped file " << filename); - if (mNotifier) mNotifier(filename); - if (mAutoDelete) { - if (!boost::interprocess::file_mapping::remove(filename.c_str())) { - if (errno != ENOENT) { - // Warn if the file exists but couldn't be removed. - std::string mesg = getErrorString(); - if (!mesg.empty()) mesg = " (" + mesg + ")"; - OPENVDB_LOG_WARN("failed to remove temporary file " << filename << mesg); - } - } - } - } - - Index64 getLastWriteTime() const - { - Index64 result = 0; - const char* filename = mMap.get_name(); - -#ifdef _MSC_VER - // boost::interprocess::detail was renamed to boost::interprocess::ipcdetail in Boost 1.48. - using namespace boost::interprocess::detail; - using namespace boost::interprocess::ipcdetail; - - if (void* fh = open_existing_file(filename, boost::interprocess::read_only)) { - struct { unsigned long lo, hi; } mtime; // Windows FILETIME struct - if (GetFileTime(fh, NULL, NULL, &mtime)) { - result = (Index64(mtime.hi) << 32) | mtime.lo; - } - close_file(fh); - } -#else - struct stat info; - if (0 == ::stat(filename, &info)) { - result = Index64(info.st_mtime); - } -#endif - return result; - } - - boost::interprocess::file_mapping mMap; - boost::interprocess::mapped_region mRegion; - bool mAutoDelete; - Notifier mNotifier; - mutable tbb::atomic mLastWriteTime; - -private: - Impl(const Impl&); // not copyable - Impl& operator=(const Impl&); // not copyable -}; - - -MappedFile::MappedFile(const std::string& filename, bool autoDelete): - mImpl(new Impl(filename, autoDelete)) -{ -} - - -MappedFile::~MappedFile() -{ -} - - -std::string -MappedFile::filename() const -{ - std::string result; - if (const char* s = mImpl->mMap.get_name()) result = s; - return result; -} - - -boost::shared_ptr -MappedFile::createBuffer() const -{ - if (!mImpl->mAutoDelete && mImpl->mLastWriteTime > 0) { - // Warn if the file has been modified since it was opened - // (but don't bother checking if it is a private, temporary file). - if (mImpl->getLastWriteTime() > mImpl->mLastWriteTime) { - OPENVDB_LOG_WARN("file " << this->filename() << " might have changed on disk" - << " since it was opened"); - mImpl->mLastWriteTime = 0; // suppress further warnings - } - } - - return boost::shared_ptr( - new boost::iostreams::stream_buffer( - static_cast(mImpl->mRegion.get_address()), mImpl->mRegion.get_size())); -} - - -void -MappedFile::setNotifier(const Notifier& notifier) -{ - mImpl->mNotifier = notifier; -} - - -void -MappedFile::clearNotifier() -{ - mImpl->mNotifier.clear(); -} - - -//////////////////////////////////////// - - -std::string -getErrorString(int errorNum) -{ - return boost::system::error_code(errorNum, boost::system::generic_category()).message(); -} - - -std::string -getErrorString() -{ - return getErrorString(errno); -} - - -//////////////////////////////////////// - - -Archive::Archive() - : mFileVersion(OPENVDB_FILE_VERSION) - , mLibraryVersion(OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION) - , mUuid(boost::uuids::nil_uuid()) - , mInputHasGridOffsets(false) - , mEnableInstancing(true) - , mCompression(DEFAULT_COMPRESSION_FLAGS) - , mEnableGridStats(true) -{ -} - - -Archive::~Archive() -{ -} - - -Archive::Ptr -Archive::copy() const -{ - return Archive::Ptr(new Archive(*this)); -} - - -//////////////////////////////////////// - - -std::string -Archive::getUniqueTag() const -{ - /// @todo Once versions of Boost < 1.44.0 are no longer in use, - /// this can be replaced with "return boost::uuids::to_string(mUuid);". - std::ostringstream ostr; - ostr << mUuid; - return ostr.str(); -} - - -bool -Archive::isIdentical(const std::string& uuidStr) const -{ - return uuidStr == getUniqueTag(); -} - - -//////////////////////////////////////// - - -uint32_t -getFormatVersion(std::ios_base& is) -{ - /// @todo get from StreamMetadata - return static_cast(is.iword(sStreamState.fileVersion)); -} - - -void -Archive::setFormatVersion(std::istream& is) -{ - is.iword(sStreamState.fileVersion) = mFileVersion; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) { - meta->setFileVersion(mFileVersion); - } -} - - -VersionId -getLibraryVersion(std::ios_base& is) -{ - /// @todo get from StreamMetadata - VersionId version; - version.first = static_cast(is.iword(sStreamState.libraryMajorVersion)); - version.second = static_cast(is.iword(sStreamState.libraryMinorVersion)); - return version; -} - - -void -Archive::setLibraryVersion(std::istream& is) -{ - is.iword(sStreamState.libraryMajorVersion) = mLibraryVersion.first; ///< @todo remove - is.iword(sStreamState.libraryMinorVersion) = mLibraryVersion.second; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) { - meta->setLibraryVersion(mLibraryVersion); - } -} - - -std::string -getVersion(std::ios_base& is) -{ - VersionId version = getLibraryVersion(is); - std::ostringstream ostr; - ostr << version.first << "." << version.second << "/" << getFormatVersion(is); - return ostr.str(); -} - - -void -setCurrentVersion(std::istream& is) -{ - is.iword(sStreamState.fileVersion) = OPENVDB_FILE_VERSION; ///< @todo remove - is.iword(sStreamState.libraryMajorVersion) = OPENVDB_LIBRARY_MAJOR_VERSION; ///< @todo remove - is.iword(sStreamState.libraryMinorVersion) = OPENVDB_LIBRARY_MINOR_VERSION; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) { - meta->setFileVersion(OPENVDB_FILE_VERSION); - meta->setLibraryVersion(VersionId( - OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION)); - } -} - - -void -setVersion(std::ios_base& strm, const VersionId& libraryVersion, uint32_t fileVersion) -{ - strm.iword(sStreamState.fileVersion) = fileVersion; ///< @todo remove - strm.iword(sStreamState.libraryMajorVersion) = libraryVersion.first; ///< @todo remove - strm.iword(sStreamState.libraryMinorVersion) = libraryVersion.second; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setFileVersion(fileVersion); - meta->setLibraryVersion(libraryVersion); - } -} - - -std::string -Archive::version() const -{ - std::ostringstream ostr; - ostr << mLibraryVersion.first << "." << mLibraryVersion.second << "/" << mFileVersion; - return ostr.str(); -} - - -//////////////////////////////////////// - - -uint32_t -getDataCompression(std::ios_base& strm) -{ - /// @todo get from StreamMetadata - return uint32_t(strm.iword(sStreamState.dataCompression)); -} - - -void -setDataCompression(std::ios_base& strm, uint32_t c) -{ - strm.iword(sStreamState.dataCompression) = c; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setCompression(c); - } -} - - -void -Archive::setDataCompression(std::istream& is) -{ - io::setDataCompression(is, mCompression); ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(is)) { - meta->setCompression(mCompression); - } -} - - -//static -bool -Archive::hasBloscCompression() -{ -#ifdef OPENVDB_USE_BLOSC - return true; -#else - return false; -#endif -} - - -void -Archive::setGridCompression(std::ostream& os, const GridBase& grid) const -{ - // Start with the options that are enabled globally for this archive. - uint32_t c = compression(); - - // Disable options that are inappropriate for the given grid. - switch (grid.getGridClass()) { - case GRID_LEVEL_SET: - case GRID_FOG_VOLUME: - // ZLIB compression is not used on level sets or fog volumes. - c = c & ~COMPRESS_ZIP; - break; - default: - break; - } - io::setDataCompression(os, c); - - os.write(reinterpret_cast(&c), sizeof(uint32_t)); -} - - -void -Archive::readGridCompression(std::istream& is) -{ - if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) { - uint32_t c = COMPRESS_NONE; - is.read(reinterpret_cast(&c), sizeof(uint32_t)); - io::setDataCompression(is, c); - } -} - - -//////////////////////////////////////// - - -bool -getWriteGridStatsMetadata(std::ios_base& strm) -{ - /// @todo get from StreamMetadata - return strm.iword(sStreamState.writeGridStatsMetadata) != 0; -} - - -void -setWriteGridStatsMetadata(std::ios_base& strm, bool writeGridStats) -{ - strm.iword(sStreamState.writeGridStatsMetadata) = writeGridStats; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setWriteGridStats(writeGridStats); - } -} - - -//////////////////////////////////////// - - -uint32_t -getGridClass(std::ios_base& strm) -{ - /// @todo get from StreamMetadata - const uint32_t val = static_cast(strm.iword(sStreamState.gridClass)); - if (val >= NUM_GRID_CLASSES) return GRID_UNKNOWN; - return val; -} - - -void -setGridClass(std::ios_base& strm, uint32_t cls) -{ - strm.iword(sStreamState.gridClass) = long(cls); ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setGridClass(cls); - } -} - - -bool -getHalfFloat(std::ios_base& strm) -{ - /// @todo get from StreamMetadata - return strm.iword(sStreamState.halfFloat) != 0; -} - - -void -setHalfFloat(std::ios_base& strm, bool halfFloat) -{ - strm.iword(sStreamState.halfFloat) = halfFloat; ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setHalfFloat(halfFloat); - } -} - - -const void* -getGridBackgroundValuePtr(std::ios_base& strm) -{ - /// @todo get from StreamMetadata - return strm.pword(sStreamState.gridBackground); -} - - -void -setGridBackgroundValuePtr(std::ios_base& strm, const void* background) -{ - strm.pword(sStreamState.gridBackground) = const_cast(background); ///< @todo remove - if (StreamMetadata::Ptr meta = getStreamMetadataPtr(strm)) { - meta->setBackgroundPtr(background); - } -} - - -MappedFile::Ptr -getMappedFilePtr(std::ios_base& strm) -{ - if (const void* ptr = strm.pword(sStreamState.mappedFile)) { - return *static_cast(ptr); - } - return MappedFile::Ptr(); -} - - -void -setMappedFilePtr(std::ios_base& strm, io::MappedFile::Ptr& mappedFile) -{ - strm.pword(sStreamState.mappedFile) = &mappedFile; -} - - -StreamMetadata::Ptr -getStreamMetadataPtr(std::ios_base& strm) -{ - if (const void* ptr = strm.pword(sStreamState.metadata)) { - return *static_cast(ptr); - } - return StreamMetadata::Ptr(); -} - - -void -setStreamMetadataPtr(std::ios_base& strm, StreamMetadata::Ptr& meta, bool transfer) -{ - strm.pword(sStreamState.metadata) = &meta; - if (transfer && meta) meta->transferTo(strm); -} - - -StreamMetadata::Ptr -clearStreamMetadataPtr(std::ios_base& strm) -{ - StreamMetadata::Ptr result = getStreamMetadataPtr(strm); - strm.pword(sStreamState.metadata) = NULL; - return result; -} - - -//////////////////////////////////////// - - -bool -Archive::readHeader(std::istream& is) -{ - // 1) Read the magic number for VDB. - int64_t magic; - is.read(reinterpret_cast(&magic), sizeof(int64_t)); - - if (magic != OPENVDB_MAGIC) { - OPENVDB_THROW(IoError, "not a VDB file"); - } - - // 2) Read the file format version number. - is.read(reinterpret_cast(&mFileVersion), sizeof(uint32_t)); - if (mFileVersion > OPENVDB_FILE_VERSION) { - OPENVDB_LOG_WARN("unsupported VDB file format (expected version " - << OPENVDB_FILE_VERSION << " or earlier, got version " << mFileVersion << ")"); - } else if (mFileVersion < 211) { - // Versions prior to 211 stored separate major, minor and patch numbers. - uint32_t version; - is.read(reinterpret_cast(&version), sizeof(uint32_t)); - mFileVersion = 100 * mFileVersion + 10 * version; - is.read(reinterpret_cast(&version), sizeof(uint32_t)); - mFileVersion += version; - } - - // 3) Read the library version numbers (not stored prior to file format version 211). - mLibraryVersion.first = mLibraryVersion.second = 0; - if (mFileVersion >= 211) { - uint32_t version; - is.read(reinterpret_cast(&version), sizeof(uint32_t)); - mLibraryVersion.first = version; // major version - is.read(reinterpret_cast(&version), sizeof(uint32_t)); - mLibraryVersion.second = version; // minor version - } - - // 4) Read the flag indicating whether the stream supports partial reading. - // (Versions prior to 212 have no flag because they always supported partial reading.) - mInputHasGridOffsets = true; - if (mFileVersion >= 212) { - char hasGridOffsets; - is.read(&hasGridOffsets, sizeof(char)); - mInputHasGridOffsets = hasGridOffsets; - } - - // 5) Read the flag that indicates whether data is compressed. - // (From version 222 on, compression information is stored per grid.) - mCompression = DEFAULT_COMPRESSION_FLAGS; - if (mFileVersion < OPENVDB_FILE_VERSION_BLOSC_COMPRESSION) { - // Prior to the introduction of Blosc, ZLIB was the default compression scheme. - mCompression = (COMPRESS_ZIP | COMPRESS_ACTIVE_MASK); - } - if (mFileVersion >= OPENVDB_FILE_VERSION_SELECTIVE_COMPRESSION && - mFileVersion < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) - { - char isCompressed; - is.read(&isCompressed, sizeof(char)); - mCompression = (isCompressed != 0 ? COMPRESS_ZIP : COMPRESS_NONE); - } - - // 6) Read the 16-byte (128-bit) uuid. - boost::uuids::uuid oldUuid = mUuid; - if (mFileVersion >= OPENVDB_FILE_VERSION_BOOST_UUID) { - // UUID is stored as an ASCII string. - is >> mUuid; - } else { - // Older versions stored the UUID as a byte string. - char uuidBytes[16]; - is.read(uuidBytes, 16); - std::memcpy(&mUuid.data[0], uuidBytes, std::min(16, mUuid.size())); - } - return oldUuid != mUuid; // true if UUID in input stream differs from old UUID -} - - -void -Archive::writeHeader(std::ostream& os, bool seekable) const -{ - using boost::uint32_t; - using boost::int64_t; - - // 1) Write the magic number for VDB. - int64_t magic = OPENVDB_MAGIC; - os.write(reinterpret_cast(&magic), sizeof(int64_t)); - - // 2) Write the file format version number. - uint32_t version = OPENVDB_FILE_VERSION; - os.write(reinterpret_cast(&version), sizeof(uint32_t)); - - // 3) Write the library version numbers. - version = OPENVDB_LIBRARY_MAJOR_VERSION; - os.write(reinterpret_cast(&version), sizeof(uint32_t)); - version = OPENVDB_LIBRARY_MINOR_VERSION; - os.write(reinterpret_cast(&version), sizeof(uint32_t)); - - // 4) Write a flag indicating that this stream contains no grid offsets. - char hasGridOffsets = seekable; - os.write(&hasGridOffsets, sizeof(char)); - - // 5) Write a flag indicating that this stream contains compressed leaf data. - // (Omitted as of version 222) - - // 6) Generate a new random 16-byte (128-bit) uuid and write it to the stream. - boost::mt19937 ran; - ran.seed(static_cast(time(NULL))); - boost::uuids::basic_random_generator gen(&ran); - mUuid = gen(); // mUuid is mutable - os << mUuid; -} - - -//////////////////////////////////////// - - -int32_t -Archive::readGridCount(std::istream& is) -{ - int32_t gridCount = 0; - is.read(reinterpret_cast(&gridCount), sizeof(int32_t)); - return gridCount; -} - - -//////////////////////////////////////// - - -void -Archive::connectInstance(const GridDescriptor& gd, const NamedGridMap& grids) const -{ - if (!gd.isInstance() || grids.empty()) return; - - NamedGridMap::const_iterator it = grids.find(gd.uniqueName()); - if (it == grids.end()) return; - GridBase::Ptr grid = it->second; - if (!grid) return; - - it = grids.find(gd.instanceParentName()); - if (it != grids.end()) { - GridBase::Ptr parent = it->second; - if (mEnableInstancing) { - // Share the instance parent's tree. - grid->setTree(parent->baseTreePtr()); - } else { - // Copy the instance parent's tree. - grid->setTree(parent->baseTree().copy()); - } - } else { - OPENVDB_THROW(KeyError, "missing instance parent \"" - << GridDescriptor::nameAsString(gd.instanceParentName()) - << "\" for grid " << GridDescriptor::nameAsString(gd.uniqueName())); - } -} - - -//////////////////////////////////////// - - -//static -bool -Archive::isDelayedLoadingEnabled() -{ -#ifdef OPENVDB_2_ABI_COMPATIBLE - return false; -#else - return (NULL == std::getenv("OPENVDB_DISABLE_DELAYED_LOAD")); -#endif -} - - -namespace { - -struct NoBBox {}; - -template -void -doReadGrid(GridBase::Ptr grid, const GridDescriptor& gd, std::istream& is, const BoxType& bbox) -{ - struct Local { - static void readBuffers(GridBase& g, std::istream& istrm, NoBBox) { g.readBuffers(istrm); } -#ifndef OPENVDB_2_ABI_COMPATIBLE - static void readBuffers(GridBase& g, std::istream& istrm, const CoordBBox& indexBBox) { - g.readBuffers(istrm, indexBBox); - } - static void readBuffers(GridBase& g, std::istream& istrm, const BBoxd& worldBBox) { - g.readBuffers(istrm, g.constTransform().worldToIndexNodeCentered(worldBBox)); - } -#endif - }; - - // Restore the file-level stream metadata on exit. - struct OnExit { - OnExit(std::ios_base& strm_): strm(&strm_), ptr(strm_.pword(sStreamState.metadata)) {} - ~OnExit() { strm->pword(sStreamState.metadata) = ptr; } - std::ios_base* strm; - void* ptr; - }; - OnExit restore(is); - - // Stream metadata varies per grid, and it needs to persist - // in case delayed load is in effect. - io::StreamMetadata::Ptr streamMetadata; - if (io::StreamMetadata::Ptr meta = io::getStreamMetadataPtr(is)) { - // Make a grid-level copy of the file-level stream metadata. - streamMetadata.reset(new StreamMetadata(*meta)); - } else { - streamMetadata.reset(new StreamMetadata); - } - streamMetadata->setHalfFloat(grid->saveFloatAsHalf()); - io::setStreamMetadataPtr(is, streamMetadata, /*transfer=*/false); - - io::setGridClass(is, GRID_UNKNOWN); - io::setGridBackgroundValuePtr(is, NULL); - - grid->readMeta(is); - - // Add a description of the compression settings to the grid as metadata. - /// @todo Would this be useful? - //const uint32_t c = getDataCompression(is); - //grid->insertMeta(GridBase::META_FILE_COMPRESSION, - // StringMetadata(compressionToString(c))); - - streamMetadata->gridMetadata() = static_cast(*grid); - const GridClass gridClass = grid->getGridClass(); - io::setGridClass(is, gridClass); - - if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_GRID_INSTANCING) { - grid->readTransform(is); - if (!gd.isInstance()) { - grid->readTopology(is); - Local::readBuffers(*grid, is, bbox); - } - } else { - // Older versions of the library stored the transform after the topology. - grid->readTopology(is); - grid->readTransform(is); - Local::readBuffers(*grid, is, bbox); - } - if (getFormatVersion(is) < OPENVDB_FILE_VERSION_NO_GRIDMAP) { - // Older versions of the library didn't store grid names as metadata, - // so when reading older files, copy the grid name from the descriptor - // to the grid's metadata. - if (grid->getName().empty()) { - grid->setName(gd.gridName()); - } - } -} - -} // unnamed namespace - - -void -Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd, std::istream& is) -{ - // Read the compression settings for this grid and tag the stream with them - // so that downstream functions can reference them. - readGridCompression(is); - - doReadGrid(grid, gd, is, NoBBox()); -} - -#ifndef OPENVDB_2_ABI_COMPATIBLE -void -Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd, - std::istream& is, const BBoxd& worldBBox) -{ - readGridCompression(is); - doReadGrid(grid, gd, is, worldBBox); -} - -void -Archive::readGrid(GridBase::Ptr grid, const GridDescriptor& gd, - std::istream& is, const CoordBBox& indexBBox) -{ - readGridCompression(is); - doReadGrid(grid, gd, is, indexBBox); -} -#endif - - -//////////////////////////////////////// - - -void -Archive::write(std::ostream& os, const GridPtrVec& grids, bool seekable, - const MetaMap& metadata) const -{ - this->write(os, GridCPtrVec(grids.begin(), grids.end()), seekable, metadata); -} - - -void -Archive::write(std::ostream& os, const GridCPtrVec& grids, bool seekable, - const MetaMap& metadata) const -{ - // Set stream flags so that downstream functions can reference them. - io::StreamMetadata::Ptr streamMetadata = io::getStreamMetadataPtr(os); - if (!streamMetadata) { - streamMetadata.reset(new StreamMetadata); - io::setStreamMetadataPtr(os, streamMetadata, /*transfer=*/false); - } - io::setDataCompression(os, compression()); - io::setWriteGridStatsMetadata(os, isGridStatsMetadataEnabled()); - - this->writeHeader(os, seekable); - - metadata.writeMeta(os); - - // Write the number of non-null grids. - int32_t gridCount = 0; - for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) { - if (*i) ++gridCount; - } - os.write(reinterpret_cast(&gridCount), sizeof(int32_t)); - - typedef std::map TreeMap; - typedef TreeMap::iterator TreeMapIter; - TreeMap treeMap; - - // Determine which grid names are unique and which are not. - typedef std::map NameHistogram; - NameHistogram nameCount; - for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) { - if (const GridBase::ConstPtr& grid = *i) { - const std::string name = grid->getName(); - NameHistogram::iterator it = nameCount.find(name); - if (it != nameCount.end()) it->second++; - else nameCount[name] = 1; - } - } - - std::set uniqueNames; - - // Write out the non-null grids. - for (GridCPtrVecCIter i = grids.begin(), e = grids.end(); i != e; ++i) { - if (const GridBase::ConstPtr& grid = *i) { - - // Ensure that the grid's descriptor has a unique grid name, by appending - // a number to it if a grid with the same name was already written. - // Always add a number if the grid name is empty, so that the grid can be - // properly identified as an instance parent, if necessary. - std::string name = grid->getName(); - if (name.empty() || nameCount[name] > 1) { - name = GridDescriptor::addSuffix(name, 0); - } - for (int n = 1; uniqueNames.find(name) != uniqueNames.end(); ++n) { - name = GridDescriptor::addSuffix(grid->getName(), n); - } - uniqueNames.insert(name); - - // Create a grid descriptor. - GridDescriptor gd(name, grid->type(), grid->saveFloatAsHalf()); - - // Check if this grid's tree is shared with a grid that has already been written. - const TreeBase* treePtr = &(grid->baseTree()); - TreeMapIter mapIter = treeMap.find(treePtr); - - bool isInstance = ((mapIter != treeMap.end()) - && (mapIter->second.saveFloatAsHalf() == gd.saveFloatAsHalf())); - - if (mEnableInstancing && isInstance) { - // This grid's tree is shared with another grid that has already been written. - // Get the name of the other grid. - gd.setInstanceParentName(mapIter->second.uniqueName()); - // Write out this grid's descriptor and metadata, but not its tree. - writeGridInstance(gd, grid, os, seekable); - - OPENVDB_LOG_DEBUG_RUNTIME("io::Archive::write(): " - << GridDescriptor::nameAsString(gd.uniqueName()) - << " (" << std::hex << treePtr << std::dec << ")" - << " is an instance of " - << GridDescriptor::nameAsString(gd.instanceParentName())); - } else { - // Write out the grid descriptor and its associated grid. - writeGrid(gd, grid, os, seekable); - // Record the grid's tree pointer so that the tree doesn't get written - // more than once. - treeMap[treePtr] = gd; - } - } - - // Some compression options (e.g., mask compression) are set per grid. - // Restore the original settings before writing the next grid. - io::setDataCompression(os, compression()); - } -} - - -void -Archive::writeGrid(GridDescriptor& gd, GridBase::ConstPtr grid, - std::ostream& os, bool seekable) const -{ - // Restore file-level stream metadata on exit. - struct OnExit { - OnExit(std::ios_base& strm_): strm(&strm_), ptr(strm_.pword(sStreamState.metadata)) {} - ~OnExit() { strm->pword(sStreamState.metadata) = ptr; } - std::ios_base* strm; - void* ptr; - }; - OnExit restore(os); - - // Stream metadata varies per grid, so make a copy of the file-level stream metadata. - io::StreamMetadata::Ptr streamMetadata; - if (io::StreamMetadata::Ptr meta = io::getStreamMetadataPtr(os)) { - streamMetadata.reset(new StreamMetadata(*meta)); - } else { - streamMetadata.reset(new StreamMetadata); - } - streamMetadata->setHalfFloat(grid->saveFloatAsHalf()); - streamMetadata->gridMetadata() = static_cast(*grid); - io::setStreamMetadataPtr(os, streamMetadata, /*transfer=*/false); - - // Write out the Descriptor's header information (grid name and type) - gd.writeHeader(os); - - // Save the curent stream position as postion to where the offsets for - // this GridDescriptor will be written to. - int64_t offsetPos = (seekable ? int64_t(os.tellp()) : 0); - - // Write out the offset information. At this point it will be incorrect. - // But we need to write it out to move the stream head forward. - gd.writeStreamPos(os); - - // Now we know the starting grid storage position. - if (seekable) gd.setGridPos(os.tellp()); - - // Save the compression settings for this grid. - setGridCompression(os, *grid); - - // Save the grid's metadata and transform. - if (!getWriteGridStatsMetadata(os)) { - grid->writeMeta(os); - } else { - // Compute and add grid statistics metadata. - GridBase::Ptr copyOfGrid = grid->copyGrid(); // shallow copy - copyOfGrid->addStatsMetadata(); - copyOfGrid->insertMeta(GridBase::META_FILE_COMPRESSION, - StringMetadata(compressionToString(getDataCompression(os)))); - copyOfGrid->writeMeta(os); - } - grid->writeTransform(os); - - // Save the grid's structure. - grid->writeTopology(os); - - // Now we know the grid block storage position. - if (seekable) gd.setBlockPos(os.tellp()); - - // Save out the data blocks of the grid. - grid->writeBuffers(os); - - // Now we know the end position of this grid. - if (seekable) gd.setEndPos(os.tellp()); - - if (seekable) { - // Now, go back to where the Descriptor's offset information is written - // and write the offsets again. - os.seekp(offsetPos, std::ios_base::beg); - gd.writeStreamPos(os); - - // Now seek back to the end. - gd.seekToEnd(os); - } -} - - -void -Archive::writeGridInstance(GridDescriptor& gd, GridBase::ConstPtr grid, - std::ostream& os, bool seekable) const -{ - // Write out the Descriptor's header information (grid name, type - // and instance parent name). - gd.writeHeader(os); - - // Save the curent stream position as postion to where the offsets for - // this GridDescriptor will be written to. - int64_t offsetPos = (seekable ? int64_t(os.tellp()) : 0); - - // Write out the offset information. At this point it will be incorrect. - // But we need to write it out to move the stream head forward. - gd.writeStreamPos(os); - - // Now we know the starting grid storage position. - if (seekable) gd.setGridPos(os.tellp()); - - // Save the compression settings for this grid. - setGridCompression(os, *grid); - - // Save the grid's metadata and transform. - grid->writeMeta(os); - grid->writeTransform(os); - - // Now we know the end position of this grid. - if (seekable) gd.setEndPos(os.tellp()); - - if (seekable) { - // Now, go back to where the Descriptor's offset information is written - // and write the offsets again. - os.seekp(offsetPos, std::ios_base::beg); - gd.writeStreamPos(os); - - // Now seek back to the end. - gd.seekToEnd(os); - } -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Archive.h b/openvdb_3_0_0_library/io/Archive.h deleted file mode 100755 index d1b973c..0000000 --- a/openvdb_3_0_0_library/io/Archive.h +++ /dev/null @@ -1,228 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_IO_ARCHIVE_HAS_BEEN_INCLUDED -#define OPENVDB_IO_ARCHIVE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for VersionId -#include "Compression.h" // for COMPRESS_ZIP, etc. - - -class TestFile; - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -class GridDescriptor; - - -/// Grid serializer/unserializer -class OPENVDB_API Archive -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - static const uint32_t DEFAULT_COMPRESSION_FLAGS; - - Archive(); - virtual ~Archive(); - - /// @brief Return a copy of this archive. - virtual Ptr copy() const; - - /// @brief Return the UUID that was most recently written (or read, - /// if no UUID has been written yet). - std::string getUniqueTag() const; - /// @brief Return @c true if the given UUID matches this archive's UUID. - bool isIdentical(const std::string& uuidStr) const; - - /// @brief Return the file format version number of the input stream. - uint32_t fileVersion() const { return mFileVersion; } - /// @brief Return the (major, minor) version number of the library that was - /// used to write the input stream. - VersionId libraryVersion() const { return mLibraryVersion; } - /// @brief Return a string of the form "./", giving the - /// library and file format version numbers associated with the input stream. - std::string version() const; - - /// @brief Return @c true if trees shared by multiple grids are written out - /// only once, @c false if they are written out once per grid. - bool isInstancingEnabled() const { return mEnableInstancing; } - /// @brief Specify whether trees shared by multiple grids should be - /// written out only once (@c true) or once per grid (@c false). - /// @note Instancing is enabled by default. - void setInstancingEnabled(bool b) { mEnableInstancing = b; } - - /// Return @c true if the OpenVDB library includes support for the Blosc compressor. - static bool hasBloscCompression(); - - /// Return a bit mask specifying compression options for the data stream. - uint32_t compression() const { return mCompression; } - /// @brief Specify whether and how the data stream should be compressed. - /// @param c bitwise OR (e.g., COMPRESS_ZIP | COMPRESS_ACTIVE_MASK) of - /// compression option flags (see Compression.h for the available flags) - /// @note Not all combinations of compression options are supported. - void setCompression(uint32_t c) { mCompression = c; } - - /// @brief Return @c true if grid statistics (active voxel count and - /// bounding box, etc.) are computed and written as grid metadata. - bool isGridStatsMetadataEnabled() const { return mEnableGridStats; } - /// @brief Specify whether grid statistics (active voxel count and - /// bounding box, etc.) should be computed and written as grid metadata. - void setGridStatsMetadataEnabled(bool b) { mEnableGridStats = b; } - - /// @brief Write the grids in the given container to this archive's output stream. - virtual void write(const GridCPtrVec&, const MetaMap& = MetaMap()) const {} - - /// @brief Return @c true if delayed loading is enabled. - /// @details If enabled, delayed loading can be disabled for individual files, - /// but not vice-versa. - /// @note Define the environment variable @c OPENVDB_DISABLE_DELAYED_LOAD - /// to disable delayed loading unconditionally. - static bool isDelayedLoadingEnabled(); - -protected: - /// @brief Return @c true if the input stream contains grid offsets - /// that allow for random access or partial reading. - bool inputHasGridOffsets() const { return mInputHasGridOffsets; } - void setInputHasGridOffsets(bool b) { mInputHasGridOffsets = b; } - - /// @brief Tag the given input stream with the input file format version number. - /// - /// The tag can be retrieved with getFormatVersion(). - /// @sa getFormatVersion() - void setFormatVersion(std::istream&); - - /// @brief Tag the given input stream with the version number of - /// the library with which the input stream was created. - /// - /// The tag can be retrieved with getLibraryVersion(). - /// @sa getLibraryVersion() - void setLibraryVersion(std::istream&); - - /// @brief Tag the given input stream with flags indicating whether - /// the input stream contains compressed data and how it is compressed. - void setDataCompression(std::istream&); - - /// @brief Tag an output stream with flags specifying only those - /// compression options that are applicable to the given grid. - void setGridCompression(std::ostream&, const GridBase&) const; - /// @brief Read in the compression flags for a grid and - /// tag the given input stream with those flags. - static void readGridCompression(std::istream&); - - /// Read in and return the number of grids on the input stream. - static int32_t readGridCount(std::istream&); - - /// Populate the given grid from the input stream. - static void readGrid(GridBase::Ptr, const GridDescriptor&, std::istream&); -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Populate the given grid from the input stream, but only where it - /// intersects the given world-space bounding box. - static void readGrid(GridBase::Ptr, const GridDescriptor&, std::istream&, const BBoxd&); - /// @brief Populate the given grid from the input stream, but only where it - /// intersects the given index-space bounding box. - static void readGrid(GridBase::Ptr, const GridDescriptor&, std::istream&, const CoordBBox&); -#endif - - typedef std::map NamedGridMap; - - /// @brief If the grid represented by the given grid descriptor - /// is an instance, connect it with its instance parent. - void connectInstance(const GridDescriptor&, const NamedGridMap&) const; - - /// Write the given grid descriptor and grid to an output stream - /// and update the GridDescriptor offsets. - /// @param seekable if true, the output stream supports seek operations - void writeGrid(GridDescriptor&, GridBase::ConstPtr, std::ostream&, bool seekable) const; - /// Write the given grid descriptor and grid metadata to an output stream - /// and update the GridDescriptor offsets, but don't write the grid's tree, - /// since it is shared with another grid. - /// @param seekable if true, the output stream supports seek operations - void writeGridInstance(GridDescriptor&, GridBase::ConstPtr, - std::ostream&, bool seekable) const; - - /// @brief Read the magic number, version numbers, UUID, etc. from the given input stream. - /// @return @c true if the input UUID differs from the previously-read UUID. - bool readHeader(std::istream&); - /// @brief Write the magic number, version numbers, UUID, etc. to the given output stream. - /// @param seekable if true, the output stream supports seek operations - /// @todo This method should not be const since it actually redefines the UUID! - void writeHeader(std::ostream&, bool seekable) const; - - //@{ - /// Write the given grids to an output stream. - void write(std::ostream&, const GridPtrVec&, bool seekable, const MetaMap& = MetaMap()) const; - void write(std::ostream&, const GridCPtrVec&, bool seekable, const MetaMap& = MetaMap()) const; - //@} - -private: - friend class ::TestFile; - - /// The version of the file that was read - uint32_t mFileVersion; - /// The version of the library that was used to create the file that was read - VersionId mLibraryVersion; - /// 16-byte (128-bit) UUID - mutable boost::uuids::uuid mUuid;// needs to be mutable since writeHeader is const! - /// Flag indicating whether the input stream contains grid offsets - /// and therefore supports partial reading - bool mInputHasGridOffsets; - /// Flag indicating whether a tree shared by multiple grids should be - /// written out only once (true) or once per grid (false) - bool mEnableInstancing; - /// Flags indicating whether and how the data stream is compressed - uint32_t mCompression; - /// Flag indicating whether grid statistics metadata should be written - bool mEnableGridStats; -}; // class Archive - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_ARCHIVE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Compression.cc b/openvdb_3_0_0_library/io/Compression.cc deleted file mode 100755 index 8cbb97c..0000000 --- a/openvdb_3_0_0_library/io/Compression.cc +++ /dev/null @@ -1,236 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Compression.h" - -#include -#include -#include -#include -#include -#ifdef OPENVDB_USE_BLOSC -#include -#endif - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -std::string -compressionToString(uint32_t flags) -{ - if (flags == COMPRESS_NONE) return "none"; - - std::vector words; - if (flags & COMPRESS_ZIP) words.push_back("zip"); - if (flags & COMPRESS_BLOSC) words.push_back("blosc"); - if (flags & COMPRESS_ACTIVE_MASK) words.push_back("active values"); - return boost::join(words, " + "); -} - - -//////////////////////////////////////// - - -namespace { -const int ZIP_COMPRESSION_LEVEL = Z_DEFAULT_COMPRESSION; ///< @todo use Z_BEST_SPEED? -} - -void -zipToStream(std::ostream& os, const char* data, size_t numBytes) -{ - // Get an upper bound on the size of the compressed data. - uLongf numZippedBytes = compressBound(numBytes); - // Compress the data. - boost::shared_array zippedData(new Bytef[numZippedBytes]); - int status = compress2( - /*dest=*/zippedData.get(), &numZippedBytes, - /*src=*/reinterpret_cast(data), numBytes, - /*level=*/ZIP_COMPRESSION_LEVEL); - if (status != Z_OK) { - std::string errDescr; - if (const char* s = zError(status)) errDescr = s; - if (!errDescr.empty()) errDescr = " (" + errDescr + ")"; - OPENVDB_LOG_DEBUG("zlib compress2() returned error code " << status << errDescr); - } - if (status == Z_OK && numZippedBytes < numBytes) { - // Write the size of the compressed data. - Int64 outZippedBytes = numZippedBytes; - os.write(reinterpret_cast(&outZippedBytes), 8); - // Write the compressed data. - os.write(reinterpret_cast(zippedData.get()), outZippedBytes); - } else { - // Write the size of the uncompressed data. - Int64 negBytes = -numBytes; - os.write(reinterpret_cast(&negBytes), 8); - // Write the uncompressed data. - os.write(reinterpret_cast(data), numBytes); - } -} - - -void -unzipFromStream(std::istream& is, char* data, size_t numBytes) -{ - // Read the size of the compressed data. - // A negative size indicates uncompressed data. - Int64 numZippedBytes; - is.read(reinterpret_cast(&numZippedBytes), 8); - - if (numZippedBytes <= 0) { - // Read the uncompressed data. - is.read(data, -numZippedBytes); - if (size_t(-numZippedBytes) != numBytes) { - OPENVDB_THROW(RuntimeError, "Expected to read a " << numBytes - << "-byte chunk, got a " << -numZippedBytes << "-byte chunk"); - } - } else { - // Read the compressed data. - boost::shared_array zippedData(new Bytef[numZippedBytes]); - is.read(reinterpret_cast(zippedData.get()), numZippedBytes); - // Uncompress the data. - uLongf numUnzippedBytes = numBytes; - int status = uncompress( - /*dest=*/reinterpret_cast(data), &numUnzippedBytes, - /*src=*/zippedData.get(), static_cast(numZippedBytes)); - if (status != Z_OK) { - std::string errDescr; - if (const char* s = zError(status)) errDescr = s; - if (!errDescr.empty()) errDescr = " (" + errDescr + ")"; - OPENVDB_LOG_DEBUG("zlib uncompress() returned error code " << status << errDescr); - } - if (numUnzippedBytes != numBytes) { - OPENVDB_THROW(RuntimeError, "Expected to decompress " << numBytes - << " byte" << (numBytes == 1 ? "" : "s") << ", got " - << numZippedBytes << " byte" << (numZippedBytes == 1 ? "" : "s")); - } - } -} - - -#ifndef OPENVDB_USE_BLOSC -void -bloscToStream(std::ostream&, const char*, size_t, size_t) -{ - OPENVDB_THROW(IoError, "Blosc encoding is not supported"); -} -#else -void -bloscToStream(std::ostream& os, const char* data, size_t valSize, size_t numVals) -{ - const size_t inBytes = valSize * numVals; - - int outBytes = int(inBytes) + BLOSC_MAX_OVERHEAD; - boost::shared_array compressedData(new char[outBytes]); - - outBytes = blosc_compress_ctx( - /*clevel=*/9, // 0 (no compression) to 9 (maximum compression) - /*doshuffle=*/true, - /*typesize=*/valSize, ///< @todo use size that gives best compression? - /*srcsize=*/inBytes, - /*src=*/data, - /*dest=*/compressedData.get(), - /*destsize=*/outBytes, - BLOSC_LZ4_COMPNAME, - /*blocksize=*/256, - /*numthreads=*/1); - - if (outBytes <= 0) { - std::ostringstream ostr; - ostr << "Blosc failed to compress " << inBytes << " byte" << (inBytes == 1 ? "" : "s"); - if (outBytes < 0) ostr << " (internal error " << outBytes << ")"; - OPENVDB_LOG_DEBUG(ostr.str()); - - // Write the size of the uncompressed data. - Int64 negBytes = -inBytes; - os.write(reinterpret_cast(&negBytes), 8); - // Write the uncompressed data. - os.write(reinterpret_cast(data), inBytes); - } else { - // Write the size of the compressed data. - Int64 numBytes = outBytes; - os.write(reinterpret_cast(&numBytes), 8); - // Write the compressed data. - os.write(reinterpret_cast(compressedData.get()), outBytes); - } -} -#endif - - -#ifndef OPENVDB_USE_BLOSC -void -bloscFromStream(std::istream&, char*, size_t) -{ - OPENVDB_THROW(IoError, "Blosc decoding is not supported"); -} -#else -void -bloscFromStream(std::istream& is, char* data, size_t numBytes) -{ - // Read the size of the compressed data. - // A negative size indicates uncompressed data. - Int64 numCompressedBytes; - is.read(reinterpret_cast(&numCompressedBytes), 8); - - if (numCompressedBytes <= 0) { - // Read the uncompressed data. - is.read(data, -numCompressedBytes); - if (size_t(-numCompressedBytes) != numBytes) { - OPENVDB_THROW(RuntimeError, "Expected to read a " << numBytes - << "-byte uncompressed chunk, got a " << -numCompressedBytes << "-byte chunk"); - } - } else { - // Read the compressed data. - boost::shared_array compressedData(new char[numCompressedBytes]); - is.read(reinterpret_cast(compressedData.get()), numCompressedBytes); - // Uncompress the data. - const int numUncompressedBytes = blosc_decompress_ctx( - /*src=*/compressedData.get(), /*dest=*/data, numBytes, /*numthreads=*/1); - if (numUncompressedBytes < 1) { - OPENVDB_LOG_DEBUG("blosc_decompress() returned error code " << numUncompressedBytes); - } - if (numUncompressedBytes != Int64(numBytes)) { - OPENVDB_THROW(RuntimeError, "Expected to decompress " << numBytes - << " byte" << (numBytes == 1 ? "" : "s") << ", got " - << numUncompressedBytes << " byte" << (numUncompressedBytes == 1 ? "" : "s")); - } - } -} -#endif - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Compression.h b/openvdb_3_0_0_library/io/Compression.h deleted file mode 100755 index 22c19d3..0000000 --- a/openvdb_3_0_0_library/io/Compression.h +++ /dev/null @@ -1,599 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_IO_COMPRESSION_HAS_BEEN_INCLUDED -#define OPENVDB_IO_COMPRESSION_HAS_BEEN_INCLUDED - -#include -#include // for negative() -#include "io.h" // for getDataCompression(), etc. -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -/// @brief OR-able bit flags for compression options on input and output streams -/// @details -///
-///
COMPRESS_NONE -///
On write, don't compress data.
-/// On read, the input stream contains uncompressed data. -/// -///
COMPRESS_ZIP -///
When writing grids other than level sets or fog volumes, apply -/// ZLIB compression to internal and leaf node value buffers.
-/// When reading grids other than level sets or fog volumes, indicate that -/// the value buffers of internal and leaf nodes are ZLIB-compressed.
-/// ZLIB compresses well but is slow. -/// -///
COMPRESS_ACTIVE_MASK -///
When writing a grid of any class, don't output a node's inactive values -/// if it has two or fewer distinct values. Instead, output minimal information -/// to permit the lossless reconstruction of inactive values.
-/// On read, nodes might have been stored without inactive values. -/// Where necessary, reconstruct inactive values from available information. -/// -///
COMPRESS_BLOSC -///
When writing grids other than level sets or fog volumes, apply -/// Blosc compression to internal and leaf node value buffers.
-/// When reading grids other than level sets or fog volumes, indicate that -/// the value buffers of internal and leaf nodes are Blosc-compressed.
-/// Blosc is much faster than ZLIB and produces comparable file sizes. -///
-enum { - COMPRESS_NONE = 0, - COMPRESS_ZIP = 0x1, - COMPRESS_ACTIVE_MASK = 0x2, - COMPRESS_BLOSC = 0x4 -}; - -/// Return a string describing the given compression flags. -OPENVDB_API std::string compressionToString(uint32_t flags); - - -//////////////////////////////////////// - - -/// @internal Per-node indicator byte that specifies what additional metadata -/// is stored to permit reconstruction of inactive values -enum { - /*0*/ NO_MASK_OR_INACTIVE_VALS, // no inactive vals, or all inactive vals are +background - /*1*/ NO_MASK_AND_MINUS_BG, // all inactive vals are -background - /*2*/ NO_MASK_AND_ONE_INACTIVE_VAL, // all inactive vals have the same non-background val - /*3*/ MASK_AND_NO_INACTIVE_VALS, // mask selects between -background and +background - /*4*/ MASK_AND_ONE_INACTIVE_VAL, // mask selects between backgd and one other inactive val - /*5*/ MASK_AND_TWO_INACTIVE_VALS, // mask selects between two non-background inactive vals - /*6*/ NO_MASK_AND_ALL_VALS // > 2 inactive vals, so no mask compression at all -}; - - -//////////////////////////////////////// - - -/// @brief RealToHalf and its specializations define a mapping from -/// floating-point data types to analogous half float types. -template -struct RealToHalf { - enum { isReal = false }; // unless otherwise specified, type T is not a floating-point type - typedef T HalfT; // type T's half float analogue is T itself -}; -template<> struct RealToHalf { enum { isReal = true }; typedef half HalfT; }; -template<> struct RealToHalf { enum { isReal = true }; typedef half HalfT; }; -template<> struct RealToHalf { enum { isReal = true }; typedef Vec2H HalfT; }; -template<> struct RealToHalf { enum { isReal = true }; typedef Vec2H HalfT; }; -template<> struct RealToHalf { enum { isReal = true }; typedef Vec3H HalfT; }; -template<> struct RealToHalf { enum { isReal = true }; typedef Vec3H HalfT; }; - - -/// Return the given value truncated to 16-bit float precision. -template -inline T -truncateRealToHalf(const T& val) -{ - return T(typename RealToHalf::HalfT(val)); -} - - -//////////////////////////////////////// - - -OPENVDB_API void zipToStream(std::ostream&, const char* data, size_t numBytes); -OPENVDB_API void unzipFromStream(std::istream&, char* data, size_t numBytes); -OPENVDB_API void bloscToStream(std::ostream&, const char* data, size_t valSize, size_t numVals); -OPENVDB_API void bloscFromStream(std::istream&, char* data, size_t numBytes); - -/// @brief Read data from a stream. -/// @param is the input stream -/// @param data the contiguous array of data to read in -/// @param count the number of elements to read in -/// @param compression whether and how the data is compressed (either COMPRESS_NONE, -/// COMPRESS_ZIP, COMPRESS_ACTIVE_MASK or COMPRESS_BLOSC) -/// @throw IoError if @a compression is COMPRESS_BLOSC but OpenVDB was compiled -/// without Blosc support. -/// @details This default implementation is instantiated only for types -/// whose size can be determined by the sizeof() operator. -template -inline void -readData(std::istream& is, T* data, Index count, uint32_t compression) -{ - if (compression & COMPRESS_BLOSC) { -#ifdef OPENVDB_USE_BLOSC - bloscFromStream(is, reinterpret_cast(data), sizeof(T) * count); -#else - OPENVDB_THROW(IoError, "Blosc decoding is not supported"); -#endif - } else if (compression & COMPRESS_ZIP) { - unzipFromStream(is, reinterpret_cast(data), sizeof(T) * count); - } else { - is.read(reinterpret_cast(data), sizeof(T) * count); - } -} - -/// Specialization for std::string input -template<> -inline void -readData(std::istream& is, std::string* data, Index count, uint32_t /*compression*/) -{ - for (Index i = 0; i < count; ++i) { - size_t len = 0; - is >> len; - //data[i].resize(len); - //is.read(&(data[i][0]), len); - - std::string buffer(len+1, ' '); - is.read(&buffer[0], len+1 ); - data[i].assign(buffer, 0, len); - } -} - -/// HalfReader wraps a static function, read(), that is analogous to readData(), above, -/// except that it is partially specialized for floating-point types in order to promote -/// 16-bit half float values to full float. A wrapper class is required because -/// only classes, not functions, can be partially specialized. -template struct HalfReader; -/// Partial specialization for non-floating-point types (no half to float promotion) -template -struct HalfReader { - static inline void read(std::istream& is, T* data, Index count, uint32_t compression) { - readData(is, data, count, compression); - } -}; -/// Partial specialization for floating-point types -template -struct HalfReader { - typedef typename RealToHalf::HalfT HalfT; - static inline void read(std::istream& is, T* data, Index count, uint32_t compression) { - if (count < 1) return; - std::vector halfData(count); // temp buffer into which to read half float values - readData(is, reinterpret_cast(&halfData[0]), count, compression); - // Copy half float values from the temporary buffer to the full float output array. - std::copy(halfData.begin(), halfData.end(), data); - } -}; - - -/// Write data to a stream. -/// @param os the output stream -/// @param data the contiguous array of data to write -/// @param count the number of elements to write out -/// @param compression whether and how to compress the data (either COMPRESS_NONE, -/// COMPRESS_ZIP, COMPRESS_ACTIVE_MASK or COMPRESS_BLOSC) -/// @throw IoError if @a compression is COMPRESS_BLOSC but OpenVDB was compiled -/// without Blosc support. -/// @details This default implementation is instantiated only for types -/// whose size can be determined by the sizeof() operator. -template -inline void -writeData(std::ostream &os, const T *data, Index count, uint32_t compression) -{ - if (compression & COMPRESS_BLOSC) { -#ifdef OPENVDB_USE_BLOSC - bloscToStream(os, reinterpret_cast(data), sizeof(T), count); -#else - OPENVDB_THROW(IoError, "Blosc encoding is not supported"); -#endif - } else if (compression & COMPRESS_ZIP) { - zipToStream(os, reinterpret_cast(data), sizeof(T) * count); - } else { - os.write(reinterpret_cast(data), sizeof(T) * count); - } -} - -/// Specialization for std::string output -template<> -inline void -writeData(std::ostream& os, const std::string* data, Index count, - uint32_t /*compression*/) ///< @todo add compression -{ - for (Index i = 0; i < count; ++i) { - const size_t len = data[i].size(); - os << len; - os.write(data[i].c_str(), len+1); - //os.write(&(data[i][0]), len ); - } -} - -/// HalfWriter wraps a static function, write(), that is analogous to writeData(), above, -/// except that it is partially specialized for floating-point types in order to quantize -/// floating-point values to 16-bit half float. A wrapper class is required because -/// only classes, not functions, can be partially specialized. -template struct HalfWriter; -/// Partial specialization for non-floating-point types (no float to half quantization) -template -struct HalfWriter { - static inline void write(std::ostream& os, const T* data, Index count, uint32_t compression) { - writeData(os, data, count, compression); - } -}; -/// Partial specialization for floating-point types -template -struct HalfWriter { - typedef typename RealToHalf::HalfT HalfT; - static inline void write(std::ostream& os, const T* data, Index count, uint32_t compression) { - if (count < 1) return; - // Convert full float values to half float, then output the half float array. - std::vector halfData(count); - for (Index i = 0; i < count; ++i) halfData[i] = static_cast(data[i]); - writeData(os, reinterpret_cast(&halfData[0]), count, compression); - } -}; -#ifdef _MSC_VER -/// Specialization to avoid double to float warnings in MSVC -template<> -struct HalfWriter { - typedef RealToHalf::HalfT HalfT; - static inline void write(std::ostream& os, const double* data, Index count, - uint32_t compression) - { - if (count < 1) return; - // Convert full float values to half float, then output the half float array. - std::vector halfData(count); - for (Index i = 0; i < count; ++i) halfData[i] = float(data[i]); - writeData(os, reinterpret_cast(&halfData[0]), count, compression); - } -}; -#endif // _MSC_VER - - -//////////////////////////////////////// - - -/// Populate the given buffer with @a destCount values of type @c ValueT -/// read from the given stream, taking into account that the stream might -/// have been compressed via one of several supported schemes. -/// [Mainly for internal use] -/// @param is a stream from which to read data (possibly compressed, -/// depending on the stream's compression settings) -/// @param destBuf a buffer into which to read values of type @c ValueT -/// @param destCount the number of values to be stored in the buffer -/// @param valueMask a bitmask (typically, a node's value mask) indicating -/// which positions in the buffer correspond to active values -/// @param fromHalf if true, read 16-bit half floats from the input stream -/// and convert them to full floats -template -inline void -readCompressedValues(std::istream& is, ValueT* destBuf, Index destCount, - const MaskT& valueMask, bool fromHalf) -{ - // Get the stream's compression settings. - const uint32_t compression = getDataCompression(is); - const bool maskCompressed = compression & COMPRESS_ACTIVE_MASK; - - int8_t metadata = NO_MASK_AND_ALL_VALS; - if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) { - // Read the flag that specifies what, if any, additional metadata - // (selection mask and/or inactive value(s)) is saved. - is.read(reinterpret_cast(&metadata), /*bytes=*/1); - } - - ValueT background = zeroVal(); - if (const void* bgPtr = getGridBackgroundValuePtr(is)) { - background = *static_cast(bgPtr); - } - ValueT inactiveVal1 = background; - ValueT inactiveVal0 = - ((metadata == NO_MASK_OR_INACTIVE_VALS) ? background : math::negative(background)); - - if (metadata == NO_MASK_AND_ONE_INACTIVE_VAL || - metadata == MASK_AND_ONE_INACTIVE_VAL || - metadata == MASK_AND_TWO_INACTIVE_VALS) - { - // Read one of at most two distinct inactive values. - is.read(reinterpret_cast(&inactiveVal0), sizeof(ValueT)); - if (metadata == MASK_AND_TWO_INACTIVE_VALS) { - // Read the second of two distinct inactive values. - is.read(reinterpret_cast(&inactiveVal1), sizeof(ValueT)); - } - } - - MaskT selectionMask; - if (metadata == MASK_AND_NO_INACTIVE_VALS || - metadata == MASK_AND_ONE_INACTIVE_VAL || - metadata == MASK_AND_TWO_INACTIVE_VALS) - { - // For use in mask compression (only), read the bitmask that selects - // between two distinct inactive values. - selectionMask.load(is); - } - - ValueT* tempBuf = destBuf; - boost::scoped_array scopedTempBuf; - - Index tempCount = destCount; - if (maskCompressed && metadata != NO_MASK_AND_ALL_VALS - && getFormatVersion(is) >= OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) - { - tempCount = valueMask.countOn(); - if (tempCount != destCount) { - // If this node has inactive voxels, allocate a temporary buffer - // into which to read just the active values. - scopedTempBuf.reset(new ValueT[tempCount]); - tempBuf = scopedTempBuf.get(); - } - } - - // Read in the buffer. - if (fromHalf) { - HalfReader::isReal, ValueT>::read(is, tempBuf, tempCount, compression); - } else { - readData(is, tempBuf, tempCount, compression); - } - - // If mask compression is enabled and the number of active values read into - // the temp buffer is smaller than the size of the destination buffer, - // then there are missing (inactive) values. - if (maskCompressed && tempCount != destCount) { - // Restore inactive values, using the background value and, if available, - // the inside/outside mask. (For fog volumes, the destination buffer is assumed - // to be initialized to background value zero, so inactive values can be ignored.) - for (Index destIdx = 0, tempIdx = 0; destIdx < MaskT::SIZE; ++destIdx) { - if (valueMask.isOn(destIdx)) { - // Copy a saved active value into this node's buffer. - destBuf[destIdx] = tempBuf[tempIdx]; - ++tempIdx; - } else { - // Reconstruct an unsaved inactive value and copy it into this node's buffer. - destBuf[destIdx] = (selectionMask.isOn(destIdx) ? inactiveVal1 : inactiveVal0); - } - } - } -} - - -/// Write @a srcCount values of type @c ValueT to the given stream, optionally -/// after compressing the values via one of several supported schemes. -/// [Mainly for internal use] -/// @param os a stream to which to write data (possibly compressed, depending -/// on the stream's compression settings) -/// @param srcBuf a buffer containing values of type @c ValueT to be written -/// @param srcCount the number of values stored in the buffer -/// @param valueMask a bitmask (typically, a node's value mask) indicating -/// which positions in the buffer correspond to active values -/// @param childMask a bitmask (typically, a node's child mask) indicating -/// which positions in the buffer correspond to child node pointers -/// @param toHalf if true, convert floating-point values to 16-bit half floats -template -inline void -writeCompressedValues(std::ostream& os, ValueT* srcBuf, Index srcCount, - const MaskT& valueMask, const MaskT& childMask, bool toHalf) -{ - struct Local { - // Comparison function for values - static inline bool eq(const ValueT& a, const ValueT& b) { - return math::isExactlyEqual(a, b); - } - }; - - // Get the stream's compression settings. - const uint32_t compress = getDataCompression(os); - const bool maskCompress = compress & COMPRESS_ACTIVE_MASK; - - Index tempCount = srcCount; - ValueT* tempBuf = srcBuf; - boost::scoped_array scopedTempBuf; - - int8_t metadata = NO_MASK_AND_ALL_VALS; - - if (!maskCompress) { - os.write(reinterpret_cast(&metadata), /*bytes=*/1); - } else { - // A valid level set's inactive values are either +background (outside) - // or -background (inside), and a fog volume's inactive values are all zero. - // Rather than write out all of these values, we can store just the active values - // (given that the value mask specifies their positions) and, if necessary, - // an inside/outside bitmask. - - const ValueT zero = zeroVal(); - ValueT background = zero; - if (const void* bgPtr = getGridBackgroundValuePtr(os)) { - background = *static_cast(bgPtr); - } - - /// @todo Consider all values, not just inactive values? - ValueT inactiveVal[2] = { background, background }; - int numUniqueInactiveVals = 0; - for (typename MaskT::OffIterator it = valueMask.beginOff(); - numUniqueInactiveVals < 3 && it; ++it) - { - const Index32 idx = it.pos(); - - // Skip inactive values that are actually child node pointers. - if (childMask.isOn(idx)) continue; - - const ValueT& val = srcBuf[idx]; - const bool unique = !( - (numUniqueInactiveVals > 0 && Local::eq(val, inactiveVal[0])) || - (numUniqueInactiveVals > 1 && Local::eq(val, inactiveVal[1])) - ); - if (unique) { - if (numUniqueInactiveVals < 2) inactiveVal[numUniqueInactiveVals] = val; - ++numUniqueInactiveVals; - } - } - - metadata = NO_MASK_OR_INACTIVE_VALS; - - if (numUniqueInactiveVals == 1) { - if (!Local::eq(inactiveVal[0], background)) { - if (Local::eq(inactiveVal[0], math::negative(background))) { - metadata = NO_MASK_AND_MINUS_BG; - } else { - metadata = NO_MASK_AND_ONE_INACTIVE_VAL; - } - } - } else if (numUniqueInactiveVals == 2) { - metadata = NO_MASK_OR_INACTIVE_VALS; - if (!Local::eq(inactiveVal[0], background) && !Local::eq(inactiveVal[1], background)) { - // If neither inactive value is equal to the background, both values - // need to be saved, along with a mask that selects between them. - metadata = MASK_AND_TWO_INACTIVE_VALS; - - } else if (Local::eq(inactiveVal[1], background)) { - if (Local::eq(inactiveVal[0], math::negative(background))) { - // If the second inactive value is equal to the background and - // the first is equal to -background, neither value needs to be saved, - // but save a mask that selects between -background and +background. - metadata = MASK_AND_NO_INACTIVE_VALS; - } else { - // If the second inactive value is equal to the background, only - // the first value needs to be saved, along with a mask that selects - // between it and the background. - metadata = MASK_AND_ONE_INACTIVE_VAL; - } - } else if (Local::eq(inactiveVal[0], background)) { - if (Local::eq(inactiveVal[1], math::negative(background))) { - // If the first inactive value is equal to the background and - // the second is equal to -background, neither value needs to be saved, - // but save a mask that selects between -background and +background. - metadata = MASK_AND_NO_INACTIVE_VALS; - std::swap(inactiveVal[0], inactiveVal[1]); - } else { - // If the first inactive value is equal to the background, swap it - // with the second value and save only that value, along with a mask - // that selects between it and the background. - std::swap(inactiveVal[0], inactiveVal[1]); - metadata = MASK_AND_ONE_INACTIVE_VAL; - } - } - } else if (numUniqueInactiveVals > 2) { - metadata = NO_MASK_AND_ALL_VALS; - } - - os.write(reinterpret_cast(&metadata), /*bytes=*/1); - - if (metadata == NO_MASK_AND_ONE_INACTIVE_VAL || - metadata == MASK_AND_ONE_INACTIVE_VAL || - metadata == MASK_AND_TWO_INACTIVE_VALS) - { - if (!toHalf) { - // Write one of at most two distinct inactive values. - os.write(reinterpret_cast(&inactiveVal[0]), sizeof(ValueT)); - if (metadata == MASK_AND_TWO_INACTIVE_VALS) { - // Write the second of two distinct inactive values. - os.write(reinterpret_cast(&inactiveVal[1]), sizeof(ValueT)); - } - } else { - // Write one of at most two distinct inactive values. - ValueT truncatedVal = static_cast(truncateRealToHalf(inactiveVal[0])); - os.write(reinterpret_cast(&truncatedVal), sizeof(ValueT)); - if (metadata == MASK_AND_TWO_INACTIVE_VALS) { - // Write the second of two distinct inactive values. - truncatedVal = truncateRealToHalf(inactiveVal[1]); - os.write(reinterpret_cast(&truncatedVal), sizeof(ValueT)); - } - } - } - - if (metadata == NO_MASK_AND_ALL_VALS) { - // If there are more than two unique inactive values, the entire input buffer - // needs to be saved (both active and inactive values). - /// @todo Save the selection mask as long as most of the inactive values - /// are one of two values? - } else { - // Create a new array to hold just the active values. - scopedTempBuf.reset(new ValueT[srcCount]); - tempBuf = scopedTempBuf.get(); - - if (metadata == NO_MASK_OR_INACTIVE_VALS || - metadata == NO_MASK_AND_MINUS_BG || - metadata == NO_MASK_AND_ONE_INACTIVE_VAL) - { - // Copy active values to the contiguous array. - tempCount = 0; - for (typename MaskT::OnIterator it = valueMask.beginOn(); it; ++it, ++tempCount) { - tempBuf[tempCount] = srcBuf[it.pos()]; - } - } else { - // Copy active values to a new, contiguous array and populate a bitmask - // that selects between two distinct inactive values. - MaskT selectionMask; - tempCount = 0; - for (Index srcIdx = 0; srcIdx < srcCount; ++srcIdx) { - if (valueMask.isOn(srcIdx)) { // active value - tempBuf[tempCount] = srcBuf[srcIdx]; - ++tempCount; - } else { // inactive value - if (Local::eq(srcBuf[srcIdx], inactiveVal[1])) { - selectionMask.setOn(srcIdx); // inactive value 1 - } // else inactive value 0 - } - } - assert(tempCount == valueMask.countOn()); - - // Write out the mask that selects between two inactive values. - selectionMask.save(os); - } - } - } - - // Write out the buffer. - if (toHalf) { - HalfWriter::isReal, ValueT>::write(os, tempBuf, tempCount, compress); - } else { - writeData(os, tempBuf, tempCount, compress); - } -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_COMPRESSION_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/File.cc b/openvdb_3_0_0_library/io/File.cc deleted file mode 100755 index fac20b1..0000000 --- a/openvdb_3_0_0_library/io/File.cc +++ /dev/null @@ -1,928 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file File.cc - -#include "File.h" - -#include "TempFile.h" -#include -#include -#include -#include -#ifndef _MSC_VER -#include -#include -#include -#endif -#include -#include // for getenv(), strtoul() -#include // for strerror_r() -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -// Implementation details of the File class -struct File::Impl -{ - enum { DEFAULT_COPY_MAX_BYTES = 500000000 }; // 500 MB - - struct NoBBox {}; - - // Common implementation of the various File::readGrid() overloads, - // with and without bounding box clipping - template - static GridBase::Ptr readGrid(const File& file, const GridDescriptor& gd, const BoxType& bbox) - { - // This method should not be called for files that don't contain grid offsets. - assert(file.inputHasGridOffsets()); - - GridBase::Ptr grid = file.createGrid(gd); - gd.seekToGrid(file.inputStream()); - unarchive(file, grid, gd, bbox); - return grid; - } - - static void unarchive(const File& file, GridBase::Ptr& grid, - const GridDescriptor& gd, NoBBox) - { - file.Archive::readGrid(grid, gd, file.inputStream()); - } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - static void unarchive(const File& file, GridBase::Ptr& grid, - const GridDescriptor& gd, const CoordBBox& indexBBox) - { - file.Archive::readGrid(grid, gd, file.inputStream(), indexBBox); - } - - static void unarchive(const File& file, GridBase::Ptr& grid, - const GridDescriptor& gd, const BBoxd& worldBBox) - { - file.Archive::readGrid(grid, gd, file.inputStream(), worldBBox); - } -#endif - - static Index64 getDefaultCopyMaxBytes() - { - Index64 result = DEFAULT_COPY_MAX_BYTES; - if (const char* s = std::getenv("OPENVDB_DELAYED_LOAD_COPY_MAX_BYTES")) { - char* endptr = NULL; - result = std::strtoul(s, &endptr, /*base=*/10); - } - return result; - } - - std::string mFilename; - // The file-level metadata - MetaMap::Ptr mMeta; - // The memory-mapped file - MappedFile::Ptr mFileMapping; - // The buffer for the input stream, if it is a memory-mapped file - boost::shared_ptr mStreamBuf; - // The file stream that is open for reading - boost::scoped_ptr mInStream; - // File-level stream metadata (file format, compression, etc.) - StreamMetadata::Ptr mStreamMetadata; - // Flag indicating if we have read in the global information (header, - // metadata, and grid descriptors) for this VDB file - bool mIsOpen; - // File size limit for copying during delayed loading - Index64 mCopyMaxBytes; - // Grid descriptors for all grids stored in the file, indexed by grid name - NameMap mGridDescriptors; - // All grids, indexed by unique name (used only when mHasGridOffsets is false) - Archive::NamedGridMap mNamedGrids; - // All grids stored in the file (used only when mHasGridOffsets is false) - GridPtrVecPtr mGrids; -}; // class File::Impl - - -//////////////////////////////////////// - - -File::File(const std::string& filename): mImpl(new Impl) -{ - mImpl->mFilename = filename; - mImpl->mIsOpen = false; - mImpl->mCopyMaxBytes = Impl::getDefaultCopyMaxBytes(); - setInputHasGridOffsets(true); -} - - -File::~File() -{ -} - - -File::File(const File& other) - : Archive(other) - , mImpl(new Impl) -{ - *this = other; -} - - -File& -File::operator=(const File& other) -{ - if (&other != this) { - Archive::operator=(other); - const Impl& otherImpl = *other.mImpl; - mImpl->mFilename = otherImpl.mFilename; - mImpl->mMeta = otherImpl.mMeta; - mImpl->mIsOpen = false; // don't want two file objects reading from the same stream - mImpl->mCopyMaxBytes = otherImpl.mCopyMaxBytes; - mImpl->mGridDescriptors = otherImpl.mGridDescriptors; - mImpl->mNamedGrids = otherImpl.mNamedGrids; - mImpl->mGrids = otherImpl.mGrids; - } - return *this; -} - - -boost::shared_ptr -File::copy() const -{ - return boost::shared_ptr(new File(*this)); -} - - -//////////////////////////////////////// - - -const std::string& -File::filename() const -{ - return mImpl->mFilename; -} - - -MetaMap::Ptr -File::fileMetadata() -{ - return mImpl->mMeta; -} - -MetaMap::ConstPtr -File::fileMetadata() const -{ - return mImpl->mMeta; -} - - -const File::NameMap& -File::gridDescriptors() const -{ - return mImpl->mGridDescriptors; -} - -File::NameMap& -File::gridDescriptors() -{ - return mImpl->mGridDescriptors; -} - - -std::istream& -File::inputStream() const -{ - if (!mImpl->mInStream) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - return *mImpl->mInStream; -} - - -//////////////////////////////////////// - - -Index64 -File::getSize() const -{ - /// @internal boost::filesystem::file_size() would be a more portable alternative, - /// but as of 9/2014, Houdini ships without the Boost.Filesystem library, - /// which makes it much less convenient to use that library. - - Index64 result = std::numeric_limits::max(); - - std::string mesg = "could not get size of file " + filename(); - -#ifdef _MSC_VER - // Get the file size by seeking to the end of the file. - std::ifstream fstrm(filename()); - if (fstrm) { - fstrm.seekg(0, fstrm.end); - result = static_cast(fstrm.tellg()); - } else { - OPENVDB_THROW(IoError, mesg); - } -#else - // Get the file size using the stat() system call. - struct stat info; - if (0 != ::stat(filename().c_str(), &info)) { - std::string s = getErrorString(); - if (!s.empty()) mesg += " (" + s + ")"; - OPENVDB_THROW(IoError, mesg); - } - if (!S_ISREG(info.st_mode)) { - mesg += " (not a regular file)"; - OPENVDB_THROW(IoError, mesg); - } - result = static_cast(info.st_size); -#endif - - return result; -} - - -Index64 -File::copyMaxBytes() const -{ - return mImpl->mCopyMaxBytes; -} - - -void -File::setCopyMaxBytes(Index64 bytes) -{ - mImpl->mCopyMaxBytes = bytes; -} - - -//////////////////////////////////////// - - -bool -File::isOpen() const -{ - return mImpl->mIsOpen; -} - - -bool -File::open(bool delayLoad, const MappedFile::Notifier& notifier) -{ - if (isOpen()) { - OPENVDB_THROW(IoError, filename() << " is already open"); - } - mImpl->mInStream.reset(); - - // Open the file. - boost::scoped_ptr newStream; - boost::shared_ptr newStreamBuf; - MappedFile::Ptr newFileMapping; - if (!delayLoad || !Archive::isDelayedLoadingEnabled()) { - newStream.reset(new std::ifstream( - filename().c_str(), std::ios_base::in | std::ios_base::binary)); - } else { - bool isTempFile = false; - std::string fname = filename(); - if (getSize() < copyMaxBytes()) { - // If the file is not too large, make a temporary private copy of it - // and open the copy instead. The original file can then be modified - // or removed without affecting delayed load. - try { - TempFile tempFile; - std::ifstream fstrm(filename().c_str(), - std::ios_base::in | std::ios_base::binary); - boost::iostreams::copy(fstrm, tempFile); - fname = tempFile.filename(); - isTempFile = true; - } catch (std::exception& e) { - std::string mesg; - if (e.what()) mesg = std::string(" (") + e.what() + ")"; - OPENVDB_LOG_WARN("failed to create a temporary copy of " << filename() - << " for delayed loading" << mesg - << "; will read directly from " << filename() << " instead"); - } - } - - // While the file is open, its mapping, stream buffer and stream - // must all be maintained. Once the file is closed, the buffer and - // the stream can be discarded, but the mapping needs to persist - // if any grids were lazily loaded. - try { - newFileMapping.reset(new MappedFile(fname, /*autoDelete=*/isTempFile)); - newStreamBuf = newFileMapping->createBuffer(); - newStream.reset(new std::istream(newStreamBuf.get())); - } catch (std::exception& e) { - std::ostringstream ostr; - ostr << "could not open file " << filename(); - if (e.what() != NULL) ostr << " (" << e.what() << ")"; - OPENVDB_THROW(IoError, ostr.str()); - } - } - - if (newStream->fail()) { - OPENVDB_THROW(IoError, "could not open file " << filename()); - } - - // Read in the file header. - bool newFile = false; - try { - newFile = Archive::readHeader(*newStream); - } catch (IoError& e) { - if (e.what() && std::string("not a VDB file") == e.what()) { - // Rethrow, adding the filename. - OPENVDB_THROW(IoError, filename() << " is not a VDB file"); - } - throw; - } - - mImpl->mFileMapping = newFileMapping; - if (mImpl->mFileMapping) mImpl->mFileMapping->setNotifier(notifier); - mImpl->mStreamBuf = newStreamBuf; - mImpl->mInStream.swap(newStream); - - // Tag the input stream with the file format and library version numbers - // and other metadata. - mImpl->mStreamMetadata.reset(new StreamMetadata); - io::setStreamMetadataPtr(inputStream(), mImpl->mStreamMetadata, /*transfer=*/false); - Archive::setFormatVersion(inputStream()); - Archive::setLibraryVersion(inputStream()); - Archive::setDataCompression(inputStream()); - io::setMappedFilePtr(inputStream(), mImpl->mFileMapping); - - // Read in the VDB metadata. - mImpl->mMeta = MetaMap::Ptr(new MetaMap); - mImpl->mMeta->readMeta(inputStream()); - - if (!inputHasGridOffsets()) { - OPENVDB_LOG_DEBUG_RUNTIME("file " << filename() << " does not support partial reading"); - - mImpl->mGrids.reset(new GridPtrVec); - mImpl->mNamedGrids.clear(); - - // Stream in the entire contents of the file and append all grids to mGrids. - const boost::int32_t gridCount = readGridCount(inputStream()); - for (boost::int32_t i = 0; i < gridCount; ++i) { - GridDescriptor gd; - gd.read(inputStream()); - - GridBase::Ptr grid = createGrid(gd); - Archive::readGrid(grid, gd, inputStream()); - - gridDescriptors().insert(std::make_pair(gd.gridName(), gd)); - mImpl->mGrids->push_back(grid); - mImpl->mNamedGrids[gd.uniqueName()] = grid; - } - // Connect instances (grids that share trees with other grids). - for (NameMapCIter it = gridDescriptors().begin(); it != gridDescriptors().end(); ++it) { - Archive::connectInstance(it->second, mImpl->mNamedGrids); - } - } else { - // Read in just the grid descriptors. - readGridDescriptors(inputStream()); - } - - mImpl->mIsOpen = true; - return newFile; // true if file is not identical to opened file -} - - -void -File::close() -{ - // Reset all data. - mImpl->mMeta.reset(); - mImpl->mGridDescriptors.clear(); - mImpl->mGrids.reset(); - mImpl->mNamedGrids.clear(); - mImpl->mInStream.reset(); - mImpl->mStreamBuf.reset(); - mImpl->mStreamMetadata.reset(); - mImpl->mFileMapping.reset(); - - mImpl->mIsOpen = false; - setInputHasGridOffsets(true); -} - - -//////////////////////////////////////// - - -bool -File::hasGrid(const Name& name) const -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - return (findDescriptor(name) != gridDescriptors().end()); -} - - -MetaMap::Ptr -File::getMetadata() const -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - // Return a deep copy of the file-level metadata, which was read - // when the file was opened. - return MetaMap::Ptr(new MetaMap(*mImpl->mMeta)); -} - - -GridPtrVecPtr -File::getGrids() const -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - - GridPtrVecPtr ret; - if (!inputHasGridOffsets()) { - // If the input file doesn't have grid offsets, then all of the grids - // have already been streamed in and stored in mGrids. - ret = mImpl->mGrids; - } else { - ret.reset(new GridPtrVec); - - Archive::NamedGridMap namedGrids; - - // Read all grids represented by the GridDescriptors. - for (NameMapCIter i = gridDescriptors().begin(), e = gridDescriptors().end(); i != e; ++i) { - const GridDescriptor& gd = i->second; - GridBase::Ptr grid = readGrid(gd); - ret->push_back(grid); - namedGrids[gd.uniqueName()] = grid; - } - - // Connect instances (grids that share trees with other grids). - for (NameMapCIter i = gridDescriptors().begin(), e = gridDescriptors().end(); i != e; ++i) { - Archive::connectInstance(i->second, namedGrids); - } - } - return ret; -} - - -GridBase::Ptr -File::retrieveCachedGrid(const Name& name) const -{ - // If the file has grid offsets, grids are read on demand - // and not cached in mNamedGrids. - if (inputHasGridOffsets()) return GridBase::Ptr(); - - // If the file does not have grid offsets, mNamedGrids should already - // contain the entire contents of the file. - - // Search by unique name. - Archive::NamedGridMap::const_iterator it = - mImpl->mNamedGrids.find(GridDescriptor::stringAsUniqueName(name)); - // If not found, search by grid name. - if (it == mImpl->mNamedGrids.end()) it = mImpl->mNamedGrids.find(name); - if (it == mImpl->mNamedGrids.end()) { - OPENVDB_THROW(KeyError, filename() << " has no grid named \"" << name << "\""); - } - return it->second; -} - - -//////////////////////////////////////// - - -GridPtrVecPtr -File::readAllGridMetadata() -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - - GridPtrVecPtr ret(new GridPtrVec); - - if (!inputHasGridOffsets()) { - // If the input file doesn't have grid offsets, then all of the grids - // have already been streamed in and stored in mGrids. - for (size_t i = 0, N = mImpl->mGrids->size(); i < N; ++i) { - // Return copies of the grids, but with empty trees. - ret->push_back((*mImpl->mGrids)[i]->copyGrid(/*treePolicy=*/CP_NEW)); - } - } else { - // Read just the metadata and transforms for all grids. - for (NameMapCIter i = gridDescriptors().begin(), e = gridDescriptors().end(); i != e; ++i) { - const GridDescriptor& gd = i->second; - GridBase::ConstPtr grid = readGridPartial(gd, /*readTopology=*/false); - // Return copies of the grids, but with empty trees. - // (As of 0.98.0, at least, it would suffice to just const cast - // the grid pointers returned by readGridPartial(), but shallow - // copying the grids helps to ensure future compatibility.) - ret->push_back(grid->copyGrid(/*treePolicy=*/CP_NEW)); - } - } - return ret; -} - - -GridBase::Ptr -File::readGridMetadata(const Name& name) -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading."); - } - - GridBase::ConstPtr ret; - if (!inputHasGridOffsets()) { - // Retrieve the grid from mGrids, which should already contain - // the entire contents of the file. - ret = readGrid(name); - } else { - NameMapCIter it = findDescriptor(name); - if (it == gridDescriptors().end()) { - OPENVDB_THROW(KeyError, filename() << " has no grid named \"" << name << "\""); - } - - // Seek to and read in the grid from the file. - const GridDescriptor& gd = it->second; - ret = readGridPartial(gd, /*readTopology=*/false); - } - return ret->copyGrid(/*treePolicy=*/CP_NEW); -} - - -//////////////////////////////////////// - - -GridBase::ConstPtr -File::readGridPartial(const Name& name) -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading."); - } - - GridBase::ConstPtr ret; - if (!inputHasGridOffsets()) { - // Retrieve the grid from mGrids, which should already contain - // the entire contents of the file. - if (GridBase::Ptr grid = readGrid(name)) { - ret = boost::const_pointer_cast(grid); - } - } else { - NameMapCIter it = findDescriptor(name); - if (it == gridDescriptors().end()) { - OPENVDB_THROW(KeyError, filename() << " has no grid named \"" << name << "\""); - } - - // Seek to and read in the grid from the file. - const GridDescriptor& gd = it->second; - ret = readGridPartial(gd, /*readTopology=*/true); - - if (gd.isInstance()) { - NameMapCIter parentIt = - findDescriptor(GridDescriptor::nameAsString(gd.instanceParentName())); - if (parentIt == gridDescriptors().end()) { - OPENVDB_THROW(KeyError, "missing instance parent \"" - << GridDescriptor::nameAsString(gd.instanceParentName()) - << "\" for grid " << GridDescriptor::nameAsString(gd.uniqueName()) - << " in file " << filename()); - } - if (GridBase::ConstPtr parent = - readGridPartial(parentIt->second, /*readTopology=*/true)) - { - boost::const_pointer_cast(ret)->setTree( - boost::const_pointer_cast(parent)->baseTreePtr()); - } - } - } - return ret; -} - - -//////////////////////////////////////// - - -GridBase::Ptr -File::readGrid(const Name& name) -{ - return readGridByName(name, BBoxd()); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -GridBase::Ptr -File::readGrid(const Name& name, const BBoxd& bbox) -{ - return readGridByName(name, bbox); -} -#endif - - -#ifdef OPENVDB_2_ABI_COMPATIBLE -GridBase::Ptr -File::readGridByName(const Name& name, const BBoxd&) -#else -GridBase::Ptr -File::readGridByName(const Name& name, const BBoxd& bbox) -#endif -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading."); - } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - const bool clip = bbox.isSorted(); -#endif - - // If a grid with the given name was already read and cached - // (along with the entire contents of the file, because the file - // doesn't support random access), retrieve and return it. - GridBase::Ptr grid = retrieveCachedGrid(name); - if (grid) { -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (clip) { - grid = grid->deepCopyGrid(); - grid->clipGrid(bbox); - } -#endif - return grid; - } - - NameMapCIter it = findDescriptor(name); - if (it == gridDescriptors().end()) { - OPENVDB_THROW(KeyError, filename() << " has no grid named \"" << name << "\""); - } - - // Seek to and read in the grid from the file. - const GridDescriptor& gd = it->second; -#ifdef OPENVDB_2_ABI_COMPATIBLE - grid = readGrid(gd); -#else - grid = (clip ? readGrid(gd, bbox) : readGrid(gd)); -#endif - - if (gd.isInstance()) { - /// @todo Refactor to share code with Archive::connectInstance()? - NameMapCIter parentIt = - findDescriptor(GridDescriptor::nameAsString(gd.instanceParentName())); - if (parentIt == gridDescriptors().end()) { - OPENVDB_THROW(KeyError, "missing instance parent \"" - << GridDescriptor::nameAsString(gd.instanceParentName()) - << "\" for grid " << GridDescriptor::nameAsString(gd.uniqueName()) - << " in file " << filename()); - } - - GridBase::Ptr parent; -#ifdef OPENVDB_2_ABI_COMPATIBLE - parent = readGrid(parentIt->second); -#else - if (clip) { - const CoordBBox indexBBox = grid->constTransform().worldToIndexNodeCentered(bbox); - parent = readGrid(parentIt->second, indexBBox); - } else { - parent = readGrid(parentIt->second); - } -#endif - if (parent) grid->setTree(parent->baseTreePtr()); - } - return grid; -} - - -//////////////////////////////////////// - - -void -File::writeGrids(const GridCPtrVec& grids, const MetaMap& meta) const -{ - if (isOpen()) { - OPENVDB_THROW(IoError, - filename() << " cannot be written because it is open for reading"); - } - - // Create a file stream and write it out. - std::ofstream file; - file.open(filename().c_str(), - std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); - - if (file.fail()) { - OPENVDB_THROW(IoError, "could not open " << filename() << " for writing"); - } - - // Write out the vdb. - Archive::write(file, grids, /*seekable=*/true, meta); - - file.close(); -} - - -//////////////////////////////////////// - - -void -File::readGridDescriptors(std::istream& is) -{ - // This method should not be called for files that don't contain grid offsets. - assert(inputHasGridOffsets()); - - gridDescriptors().clear(); - - for (boost::int32_t i = 0, N = readGridCount(is); i < N; ++i) { - // Read the grid descriptor. - GridDescriptor gd; - gd.read(is); - - // Add the descriptor to the dictionary. - gridDescriptors().insert(std::make_pair(gd.gridName(), gd)); - - // Skip forward to the next descriptor. - gd.seekToEnd(is); - } -} - - -//////////////////////////////////////// - - -File::NameMapCIter -File::findDescriptor(const Name& name) const -{ - const Name uniqueName = GridDescriptor::stringAsUniqueName(name); - - // Find all descriptors with the given grid name. - std::pair range = gridDescriptors().equal_range(name); - - if (range.first == range.second) { - // If no descriptors were found with the given grid name, the name might have - // a suffix ("name[N]"). In that case, remove the "[N]" suffix and search again. - range = gridDescriptors().equal_range(GridDescriptor::stripSuffix(uniqueName)); - } - - const size_t count = size_t(std::distance(range.first, range.second)); - if (count > 1 && name == uniqueName) { - OPENVDB_LOG_WARN(filename() << " has more than one grid named \"" << name << "\""); - } - - NameMapCIter ret = gridDescriptors().end(); - - if (count > 0) { - if (name == uniqueName) { - // If the given grid name is unique or if no "[N]" index was given, - // use the first matching descriptor. - ret = range.first; - } else { - // If the given grid name has a "[N]" index, find the descriptor - // with a matching unique name. - for (NameMapCIter it = range.first; it != range.second; ++it) { - const Name candidateName = it->second.uniqueName(); - if (candidateName == uniqueName || candidateName == name) { - ret = it; - break; - } - } - } - } - return ret; -} - - -//////////////////////////////////////// - - -GridBase::Ptr -File::createGrid(const GridDescriptor& gd) const -{ - // Create the grid. - if (!GridBase::isRegistered(gd.gridType())) { - OPENVDB_THROW(KeyError, "Cannot read grid " - << GridDescriptor::nameAsString(gd.uniqueName()) - << " from " << filename() << ": grid type " - << gd.gridType() << " is not registered"); - } - - GridBase::Ptr grid = GridBase::createGrid(gd.gridType()); - if (grid) grid->setSaveFloatAsHalf(gd.saveFloatAsHalf()); - - return grid; -} - - -GridBase::ConstPtr -File::readGridPartial(const GridDescriptor& gd, bool readTopology) const -{ - // This method should not be called for files that don't contain grid offsets. - assert(inputHasGridOffsets()); - - GridBase::Ptr grid = createGrid(gd); - - // Seek to grid. - gd.seekToGrid(inputStream()); - - // Read the grid partially. - readGridPartial(grid, inputStream(), gd.isInstance(), readTopology); - - // Promote to a const grid. - GridBase::ConstPtr constGrid = grid; - - return constGrid; -} - - -GridBase::Ptr -File::readGrid(const GridDescriptor& gd) const -{ - return Impl::readGrid(*this, gd, Impl::NoBBox()); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -GridBase::Ptr -File::readGrid(const GridDescriptor& gd, const BBoxd& bbox) const -{ - return Impl::readGrid(*this, gd, bbox); -} - - -GridBase::Ptr -File::readGrid(const GridDescriptor& gd, const CoordBBox& bbox) const -{ - return Impl::readGrid(*this, gd, bbox); -} -#endif - - -void -File::readGridPartial(GridBase::Ptr grid, std::istream& is, - bool isInstance, bool readTopology) const -{ - // This method should not be called for files that don't contain grid offsets. - assert(inputHasGridOffsets()); - - // This code needs to stay in sync with io::Archive::readGrid(), in terms of - // the order of operations. - readGridCompression(is); - grid->readMeta(is); - if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_GRID_INSTANCING) { - grid->readTransform(is); - if (!isInstance && readTopology) { - grid->readTopology(is); - } - } else { - if (readTopology) { - grid->readTopology(is); - grid->readTransform(is); - } - } -} - - -//////////////////////////////////////// - - -File::NameIterator -File::beginName() const -{ - if (!isOpen()) { - OPENVDB_THROW(IoError, filename() << " is not open for reading"); - } - return File::NameIterator(gridDescriptors().begin()); -} - - -File::NameIterator -File::endName() const -{ - return File::NameIterator(gridDescriptors().end()); -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/File.h b/openvdb_3_0_0_library/io/File.h deleted file mode 100755 index 972d390..0000000 --- a/openvdb_3_0_0_library/io/File.h +++ /dev/null @@ -1,276 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file File.h - -#ifndef OPENVDB_IO_FILE_HAS_BEEN_INCLUDED -#define OPENVDB_IO_FILE_HAS_BEEN_INCLUDED - -#include "io.h" // for MappedFile::Notifier -#include "Archive.h" -#include "GridDescriptor.h" -#include -#include -#include -#include - - -class TestFile; -class TestStream; - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -/// Grid archive associated with a file on disk -class OPENVDB_API File: public Archive -{ -public: - typedef std::multimap NameMap; - typedef NameMap::const_iterator NameMapCIter; - - explicit File(const std::string& filename); - virtual ~File(); - - /// @brief Copy constructor - /// @details The copy will be closed and will not reference the same - /// file descriptor as the original. - File(const File& other); - /// @brief Assignment - /// @details After assignment, this File will be closed and will not - /// reference the same file descriptor as the source File. - File& operator=(const File& other); - - /// @brief Return a copy of this archive. - /// @details The copy will be closed and will not reference the same - /// file descriptor as the original. - virtual boost::shared_ptr copy() const; - - /// @brief Return the name of the file with which this archive is associated. - /// @details The file does not necessarily exist on disk yet. - const std::string& filename() const; - - /// @brief Open the file, read the file header and the file-level metadata, - /// and populate the grid descriptors, but do not load any grids into memory. - /// @details If @a delayLoad is true, map the file into memory and enable delayed loading - /// of grids, and if a notifier is provided, call it when the file gets unmapped. - /// @note Define the environment variable @c OPENVDB_DISABLE_DELAYED_LOAD to disable - /// delayed loading unconditionally. - /// @throw IoError if the file is not a valid VDB file. - /// @return @c true if the file's UUID has changed since it was last read. - /// @see setCopyMaxBytes - bool open(bool delayLoad = true, const MappedFile::Notifier& = MappedFile::Notifier()); - - /// Return @c true if the file has been opened for reading. - bool isOpen() const; - - /// Close the file once we are done reading from it. - void close(); - - /// @brief Return this file's current size on disk in bytes. - /// @throw IoError if the file size cannot be determined. - Index64 getSize() const; - - /// @brief Return the size in bytes above which this file will not be - /// automatically copied during delayed loading. - Index64 copyMaxBytes() const; - /// @brief If this file is opened with delayed loading enabled, make a private copy - /// of the file if its size in bytes is less than the specified value. - /// @details Making a private copy ensures that the file can't change on disk - /// before it has been fully read. - /// @warning If the file is larger than this size, it is the user's responsibility - /// to ensure that it does not change on disk before it has been fully read. - /// Undefined behavior and/or a crash might result otherwise. - /// @note Copying is enabled by default, but it can be disabled for individual files - /// by setting the maximum size to zero bytes. A default size limit can be specified - /// by setting the environment variable @c OPENVDB_DELAYED_LOAD_COPY_MAX_BYTES - /// to the desired number of bytes. - void setCopyMaxBytes(Index64 bytes); - - /// Return @c true if a grid of the given name exists in this file. - bool hasGrid(const Name&) const; - - /// Return (in a newly created MetaMap) the file-level metadata. - MetaMap::Ptr getMetadata() const; - - /// Read the entire contents of the file and return a list of grid pointers. - GridPtrVecPtr getGrids() const; - - /// @brief Read just the grid metadata and transforms from the file and return a list - /// of pointers to grids that are empty except for their metadata and transforms. - /// @throw IoError if this file is not open for reading. - GridPtrVecPtr readAllGridMetadata(); - - /// @brief Read a grid's metadata and transform only. - /// @return A pointer to a grid that is empty except for its metadata and transform. - /// @throw IoError if this file is not open for reading. - /// @throw KeyError if no grid with the given name exists in this file. - GridBase::Ptr readGridMetadata(const Name&); - - /// @brief Read a grid's metadata, topology, transform, etc., but not - /// any of its leaf node data blocks. - /// @return the grid pointer to the partially loaded grid. - /// @note This returns a @c const pointer, so that the grid can't be - /// changed before its data blocks have been loaded. A non-const - /// pointer is only returned when readGrid() is called. - GridBase::ConstPtr readGridPartial(const Name&); - - /// Read an entire grid, including all of its data blocks. - GridBase::Ptr readGrid(const Name&); -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Read a grid, including its data blocks, but only where it - /// intersects the given world-space bounding box. - GridBase::Ptr readGrid(const Name&, const BBoxd&); -#endif - - /// @todo GridPtrVec readAllGridsPartial(const Name&) - /// @todo GridPtrVec readAllGrids(const Name&) - - /// @brief Write the grids in the given container to the file whose name - /// was given in the constructor. - virtual void write(const GridCPtrVec&, const MetaMap& = MetaMap()) const; - - /// @brief Write the grids in the given container to the file whose name - /// was given in the constructor. - template - void write(const GridPtrContainerT&, const MetaMap& = MetaMap()) const; - - /// A const iterator that iterates over all names in the file. This is only - /// valid once the file has been opened. - class NameIterator - { - public: - NameIterator(const NameMapCIter& iter): mIter(iter) {} - ~NameIterator() {} - - NameIterator& operator++() { mIter++; return *this; } - - bool operator==(const NameIterator& iter) const { return mIter == iter.mIter; } - bool operator!=(const NameIterator& iter) const { return mIter != iter.mIter; } - - Name operator*() const { return this->gridName(); } - - Name gridName() const { return GridDescriptor::nameAsString(mIter->second.uniqueName()); } - - private: - NameMapCIter mIter; - }; - - /// @return a NameIterator to iterate over all grid names in the file. - NameIterator beginName() const; - - /// @return the ending iterator for all grid names in the file. - NameIterator endName() const; - -private: - /// Read in all grid descriptors that are stored in the given stream. - void readGridDescriptors(std::istream&); - - /// @brief Return an iterator to the descriptor for the grid with the given name. - /// If the name is non-unique, return an iterator to the first matching descriptor. - NameMapCIter findDescriptor(const Name&) const; - - /// Return a newly created, empty grid of the type specified by the given grid descriptor. - GridBase::Ptr createGrid(const GridDescriptor&) const; - - /// @brief Read a grid, including its data blocks, but only where it - /// intersects the given world-space bounding box. - GridBase::Ptr readGridByName(const Name&, const BBoxd&); - - /// Read in and return the partially-populated grid specified by the given grid descriptor. - GridBase::ConstPtr readGridPartial(const GridDescriptor&, bool readTopology) const; - - /// Read in and return the grid specified by the given grid descriptor. - GridBase::Ptr readGrid(const GridDescriptor&) const; -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Read in and return the region of the grid specified by the given grid descriptor - /// that intersects the given world-space bounding box. - GridBase::Ptr readGrid(const GridDescriptor&, const BBoxd&) const; - /// Read in and return the region of the grid specified by the given grid descriptor - /// that intersects the given index-space bounding box. - GridBase::Ptr readGrid(const GridDescriptor&, const CoordBBox&) const; -#endif - - /// @brief Partially populate the given grid by reading its metadata and transform and, - /// if the grid is not an instance, its tree structure, but not the tree's leaf nodes. - void readGridPartial(GridBase::Ptr, std::istream&, bool isInstance, bool readTopology) const; - - /// @brief Retrieve a grid from @c mNamedGrids. Return a null pointer - /// if @c mNamedGrids was not populated (because this file is random-access). - /// @throw KeyError if no grid with the given name exists in this file. - GridBase::Ptr retrieveCachedGrid(const Name&) const; - - void writeGrids(const GridCPtrVec&, const MetaMap&) const; - - MetaMap::Ptr fileMetadata(); - MetaMap::ConstPtr fileMetadata() const; - - const NameMap& gridDescriptors() const; - NameMap& gridDescriptors(); - - std::istream& inputStream() const; - - friend class ::TestFile; - friend class ::TestStream; - - struct Impl; - boost::scoped_ptr mImpl; -}; - - -//////////////////////////////////////// - - -inline void -File::write(const GridCPtrVec& grids, const MetaMap& meta) const -{ - this->writeGrids(grids, meta); -} - - -template -inline void -File::write(const GridPtrContainerT& container, const MetaMap& meta) const -{ - GridCPtrVec grids; - std::copy(container.begin(), container.end(), std::back_inserter(grids)); - this->writeGrids(grids, meta); -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_FILE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/GridDescriptor.cc b/openvdb_3_0_0_library/io/GridDescriptor.cc deleted file mode 100755 index ee79a89..0000000 --- a/openvdb_3_0_0_library/io/GridDescriptor.cc +++ /dev/null @@ -1,227 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "GridDescriptor.h" - -#include -#include // for boost::ends_with() -#include // for boost::erase_last() -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -namespace { - -// In order not to break backward compatibility with existing VDB files, -// grids stored using 16-bit half floats are flagged by adding the following -// suffix to the grid's type name on output. The suffix is removed on input -// and the grid's "save float as half" flag set accordingly. -const char* HALF_FLOAT_TYPENAME_SUFFIX = "_HalfFloat"; - -const char* SEP = "\x1e"; // ASCII "record separator" - -} - - -GridDescriptor::GridDescriptor(): - mSaveFloatAsHalf(false), - mGridPos(0), - mBlockPos(0), - mEndPos(0) -{ -} - -GridDescriptor::GridDescriptor(const Name &name, const Name &type, bool half): - mGridName(stripSuffix(name)), - mUniqueName(name), - mGridType(type), - mSaveFloatAsHalf(half), - mGridPos(0), - mBlockPos(0), - mEndPos(0) -{ -} - -GridDescriptor::~GridDescriptor() -{ -} - -void -GridDescriptor::writeHeader(std::ostream &os) const -{ - writeString(os, mUniqueName); - - Name gridType = mGridType; - if (mSaveFloatAsHalf) gridType += HALF_FLOAT_TYPENAME_SUFFIX; - writeString(os, gridType); - - writeString(os, mInstanceParentName); -} - -void -GridDescriptor::writeStreamPos(std::ostream &os) const -{ - os.write(reinterpret_cast(&mGridPos), sizeof(boost::int64_t)); - os.write(reinterpret_cast(&mBlockPos), sizeof(boost::int64_t)); - os.write(reinterpret_cast(&mEndPos), sizeof(boost::int64_t)); -} - -GridBase::Ptr -GridDescriptor::read(std::istream &is) -{ - // Read in the name. - mUniqueName = readString(is); - mGridName = stripSuffix(mUniqueName); - - // Read in the grid type. - mGridType = readString(is); - if (boost::ends_with(mGridType, HALF_FLOAT_TYPENAME_SUFFIX)) { - mSaveFloatAsHalf = true; - boost::erase_last(mGridType, HALF_FLOAT_TYPENAME_SUFFIX); - } - - if (getFormatVersion(is) >= OPENVDB_FILE_VERSION_GRID_INSTANCING) { - mInstanceParentName = readString(is); - } - - // Create the grid of the type if it has been registered. - if (!GridBase::isRegistered(mGridType)) { - OPENVDB_THROW(LookupError, "Cannot read grid." << - " Grid type " << mGridType << " is not registered."); - } - // else - GridBase::Ptr grid = GridBase::createGrid(mGridType); - if (grid) grid->setSaveFloatAsHalf(mSaveFloatAsHalf); - - // Read in the offsets. - is.read(reinterpret_cast(&mGridPos), sizeof(boost::int64_t)); - is.read(reinterpret_cast(&mBlockPos), sizeof(boost::int64_t)); - is.read(reinterpret_cast(&mEndPos), sizeof(boost::int64_t)); - - return grid; -} - -void -GridDescriptor::seekToGrid(std::istream &is) const -{ - is.seekg(mGridPos, std::ios_base::beg); -} - -void -GridDescriptor::seekToBlocks(std::istream &is) const -{ - is.seekg(mBlockPos, std::ios_base::beg); -} - -void -GridDescriptor::seekToEnd(std::istream &is) const -{ - is.seekg(mEndPos, std::ios_base::beg); -} - - -void -GridDescriptor::seekToGrid(std::ostream &os) const -{ - os.seekp(mGridPos, std::ios_base::beg); -} - -void -GridDescriptor::seekToBlocks(std::ostream &os) const -{ - os.seekp(mBlockPos, std::ios_base::beg); -} - -void -GridDescriptor::seekToEnd(std::ostream &os) const -{ - os.seekp(mEndPos, std::ios_base::beg); -} - - -//////////////////////////////////////// - - -// static -Name -GridDescriptor::addSuffix(const Name& name, int n) -{ - std::ostringstream ostr; - ostr << name << SEP << n; - return ostr.str(); -} - - -// static -Name -GridDescriptor::stripSuffix(const Name& name) -{ - return name.substr(0, name.find(SEP)); -} - - -// static -std::string -GridDescriptor::nameAsString(const Name& name) -{ - std::string::size_type pos = name.find(SEP); - if (pos == std::string::npos) return name; - - return name.substr(0, pos) + "[" + name.substr(pos + 1) + "]"; -} - - -//static -Name -GridDescriptor::stringAsUniqueName(const std::string& s) -{ - Name ret = s; - if (!ret.empty() && *ret.rbegin() == ']') { // found trailing ']' - std::string::size_type pos = ret.find("["); - // Replace "[N]" with SEP "N". - if (pos != std::string::npos) { - ret.resize(ret.size() - 1); // drop trailing ']' - ret.replace(ret.find("["), 1, SEP); - } - } - return ret; -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/GridDescriptor.h b/openvdb_3_0_0_library/io/GridDescriptor.h deleted file mode 100755 index 040bbf9..0000000 --- a/openvdb_3_0_0_library/io/GridDescriptor.h +++ /dev/null @@ -1,135 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_IO_GRIDDESCRIPTOR_HAS_BEEN_INCLUDED -#define OPENVDB_IO_GRIDDESCRIPTOR_HAS_BEEN_INCLUDED - -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -/// This structure stores useful information that describes a grid on disk. -/// It can be used to retrieve I/O information about the grid such as -/// offsets into the file where the grid is located, its type, etc. -class OPENVDB_API GridDescriptor -{ -public: - GridDescriptor(); - GridDescriptor(const Name& name, const Name& gridType, bool saveFloatAsHalf = false); - - ~GridDescriptor(); - - const Name& gridType() const { return mGridType; } - const Name& gridName() const { return mGridName; } - const Name& uniqueName() const { return mUniqueName; } - - const Name& instanceParentName() const { return mInstanceParentName; } - void setInstanceParentName(const Name& name) { mInstanceParentName = name; } - bool isInstance() const { return !mInstanceParentName.empty(); } - - bool saveFloatAsHalf() const { return mSaveFloatAsHalf; } - - void setGridPos(boost::int64_t pos) { mGridPos = pos; } - boost::int64_t getGridPos() const { return mGridPos; } - - void setBlockPos(boost::int64_t pos) { mBlockPos = pos; } - boost::int64_t getBlockPos() const { return mBlockPos; } - - void setEndPos(boost::int64_t pos) { mEndPos = pos; } - boost::int64_t getEndPos() const { return mEndPos; } - - // These methods seek to the right position in the given stream. - void seekToGrid(std::istream&) const; - void seekToBlocks(std::istream&) const; - void seekToEnd(std::istream&) const; - - void seekToGrid(std::ostream&) const; - void seekToBlocks(std::ostream&) const; - void seekToEnd(std::ostream&) const; - - /// @brief Write out this descriptor's header information (all data except for - /// stream offsets). - void writeHeader(std::ostream&) const; - - /// @brief Since positions into the stream are known at a later time, they are - /// written out separately. - void writeStreamPos(std::ostream&) const; - - /// @brief Read a grid descriptor from the given stream. - /// @return an empty grid of the type specified by the grid descriptor. - GridBase::Ptr read(std::istream&); - - /// @brief Append the number @a n to the given name (separated by an ASCII - /// "record separator" character) and return the resulting name. - static Name addSuffix(const Name&, int n); - /// @brief Strip from the given name any suffix that is separated by an ASCII - /// "record separator" character and return the resulting name. - static Name stripSuffix(const Name&); - /// @brief Given a name with suffix N, return "name[N]", otherwise just return "name". - /// Use this to produce a human-readable string from a descriptor's unique name. - static std::string nameAsString(const Name&); - /// @brief Given a string of the form "name[N]", return "name" with the suffix N - /// separated by an ASCII "record separator" character). Otherwise just return - /// the string as is. - static Name stringAsUniqueName(const std::string&); - -private: - /// Name of the grid - Name mGridName; - /// Unique name for this descriptor - Name mUniqueName; - /// If nonempty, the name of another grid that shares this grid's tree - Name mInstanceParentName; - /// The type of the grid - Name mGridType; - /// Are floats quantized to 16 bits on disk? - bool mSaveFloatAsHalf; - /// Location in the stream where the grid data is stored - boost::int64_t mGridPos; - /// Location in the stream where the grid blocks are stored - boost::int64_t mBlockPos; - /// Location in the stream where the next grid descriptor begins - boost::int64_t mEndPos; -}; - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_GRIDDESCRIPTOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Queue.cc b/openvdb_3_0_0_library/io/Queue.cc deleted file mode 100755 index cf17602..0000000 --- a/openvdb_3_0_0_library/io/Queue.cc +++ /dev/null @@ -1,343 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Queue.cc -/// @author Peter Cucka - -#include "Queue.h" - -#include "File.h" -#include "Stream.h" -#include -#include -#include -#include -#include -#include -#include -#include // for tbb::this_tbb_thread::sleep() -#include -#include // for std::max() -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -namespace { - -typedef tbb::mutex Mutex; -typedef Mutex::scoped_lock Lock; - - -// Abstract base class for queuable TBB tasks that adds a task completion callback -class Task: public tbb::task -{ -public: - Task(Queue::Id id): mId(id) {} - virtual ~Task() {} - - Queue::Id id() const { return mId; } - - void setNotifier(Queue::Notifier& notifier) { mNotify = notifier; } - -protected: - void notify(Queue::Status status) { if (mNotify) mNotify(this->id(), status); } - -private: - Queue::Id mId; - Queue::Notifier mNotify; -}; - - -// Queuable TBB task that writes one or more grids to a .vdb file or an output stream -class OutputTask: public Task -{ -public: - OutputTask(Queue::Id id, const GridCPtrVec& grids, const Archive& archive, - const MetaMap& metadata) - : Task(id) - , mGrids(grids) - , mArchive(archive.copy()) - , mMetadata(metadata) - {} - - virtual tbb::task* execute() - { - Queue::Status status = Queue::FAILED; - try { - mArchive->write(mGrids, mMetadata); - status = Queue::SUCCEEDED; - } catch (std::exception& e) { - if (const char* msg = e.what()) { - OPENVDB_LOG_ERROR(msg); - } - } catch (...) { - } - this->notify(status); - return NULL; // no successor to this task - } - -private: - GridCPtrVec mGrids; - boost::shared_ptr mArchive; - MetaMap mMetadata; -}; - -} // unnamed namespace - - -//////////////////////////////////////// - - -// Private implementation details of a Queue -struct Queue::Impl -{ - typedef std::map NotifierMap; - /// @todo Provide more information than just "succeeded" or "failed"? - typedef tbb::concurrent_hash_map StatusMap; - - - Impl() - : mTimeout(Queue::DEFAULT_TIMEOUT) - , mCapacity(Queue::DEFAULT_CAPACITY) - , mNextId(1) - , mNextNotifierId(1) - { - mNumTasks = 0; // note: must explicitly zero-initialize atomics - } - ~Impl() {} - - // Disallow copying of instances of this class. - Impl(const Impl&); - Impl& operator=(const Impl&); - - // This method might be called from multiple threads. - void setStatus(Queue::Id id, Queue::Status status) - { - StatusMap::accessor acc; - mStatus.insert(acc, id); - acc->second = status; - } - - // This method might be called from multiple threads. - void setStatusWithNotification(Queue::Id id, Queue::Status status) - { - const bool completed = (status == SUCCEEDED || status == FAILED); - - // Update the task's entry in the status map with the new status. - this->setStatus(id, status); - - // If the client registered any callbacks, call them now. - bool didNotify = false; - { - // tbb::concurrent_hash_map does not support concurrent iteration - // (i.e., iteration concurrent with insertion or deletion), - // so we use a mutex-protected STL map instead. But if a callback - // invokes a notifier method such as removeNotifier() on this queue, - // the result will be a deadlock. - /// @todo Is it worth trying to avoid such deadlocks? - Lock lock(mNotifierMutex); - if (!mNotifiers.empty()) { - didNotify = true; - for (NotifierMap::const_iterator it = mNotifiers.begin(); - it != mNotifiers.end(); ++it) - { - it->second(id, status); - } - } - } - // If the task completed and callbacks were called, remove - // the task's entry from the status map. - if (completed) { - if (didNotify) { - StatusMap::accessor acc; - if (mStatus.find(acc, id)) { - mStatus.erase(acc); - } - } - --mNumTasks; - } - } - - bool canEnqueue() const { return mNumTasks < Int64(mCapacity); } - - void enqueue(Task& task) - { - tbb::tick_count start = tbb::tick_count::now(); - while (!canEnqueue()) { - tbb::this_tbb_thread::sleep(tbb::tick_count::interval_t(0.5/*sec*/)); - if ((tbb::tick_count::now() - start).seconds() > double(mTimeout)) { - OPENVDB_THROW(RuntimeError, - "unable to queue I/O task; " << mTimeout << "-second time limit expired"); - } - } - Queue::Notifier notify = boost::bind(&Impl::setStatusWithNotification, this, _1, _2); - task.setNotifier(notify); - this->setStatus(task.id(), Queue::PENDING); - tbb::task::enqueue(task); - ++mNumTasks; - } - - Index32 mTimeout; - Index32 mCapacity; - tbb::atomic mNumTasks; - Index32 mNextId; - StatusMap mStatus; - NotifierMap mNotifiers; - Index32 mNextNotifierId; - Mutex mNotifierMutex; -}; - - -//////////////////////////////////////// - - -Queue::Queue(Index32 capacity): mImpl(new Impl) -{ - mImpl->mCapacity = capacity; -} - - -Queue::~Queue() -{ - // Wait for all queued tasks to complete (successfully or unsuccessfully). - /// @todo Allow the queue to be destroyed while there are uncompleted tasks - /// (e.g., by keeping a static registry of queues that also dispatches - /// or blocks notifications)? - while (mImpl->mNumTasks > 0) { - tbb::this_tbb_thread::sleep(tbb::tick_count::interval_t(0.5/*sec*/)); - } -} - - -//////////////////////////////////////// - - -bool Queue::empty() const { return (mImpl->mNumTasks == 0); } -Index32 Queue::size() const { return Index32(std::max(0, mImpl->mNumTasks)); } -Index32 Queue::capacity() const { return mImpl->mCapacity; } -void Queue::setCapacity(Index32 n) { mImpl->mCapacity = std::max(1, n); } - -/// @todo void Queue::setCapacity(Index64 bytes); - -/// @todo Provide a way to limit the number of tasks in flight -/// (e.g., by enqueueing tbb::tasks that pop Tasks off a concurrent_queue)? - -/// @todo Remove any tasks from the queue that are not currently executing. -//void clear() const; - -Index32 Queue::timeout() const { return mImpl->mTimeout; } -void Queue::setTimeout(Index32 sec) { mImpl->mTimeout = sec; } - - -//////////////////////////////////////// - - -Queue::Status -Queue::status(Id id) const -{ - Impl::StatusMap::const_accessor acc; - if (mImpl->mStatus.find(acc, id)) { - const Status status = acc->second; - if (status == SUCCEEDED || status == FAILED) { - mImpl->mStatus.erase(acc); - } - return status; - } - return UNKNOWN; -} - - -Queue::Id -Queue::addNotifier(Notifier notify) -{ - Lock lock(mImpl->mNotifierMutex); - Queue::Id id = mImpl->mNextNotifierId++; - mImpl->mNotifiers[id] = notify; - return id; -} - - -void -Queue::removeNotifier(Id id) -{ - Lock lock(mImpl->mNotifierMutex); - Impl::NotifierMap::iterator it = mImpl->mNotifiers.find(id); - if (it != mImpl->mNotifiers.end()) { - mImpl->mNotifiers.erase(it); - } -} - - -void -Queue::clearNotifiers() -{ - Lock lock(mImpl->mNotifierMutex); - mImpl->mNotifiers.clear(); -} - - -//////////////////////////////////////// - - -Queue::Id -Queue::writeGrid(GridBase::ConstPtr grid, const Archive& archive, const MetaMap& metadata) -{ - return writeGridVec(GridCPtrVec(1, grid), archive, metadata); -} - - -Queue::Id -Queue::writeGridVec(const GridCPtrVec& grids, const Archive& archive, const MetaMap& metadata) -{ - // From the "GUI Thread" chapter in the TBB Design Patterns guide - OutputTask* task = - new(tbb::task::allocate_root()) OutputTask(mImpl->mNextId++, grids, archive, metadata); - try { - mImpl->enqueue(*task); - } catch (openvdb::RuntimeError&) { - // Destroy the task if it could not be enqueued, then rethrow the exception. - tbb::task::destroy(*task); - throw; - } - return task->id(); -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Queue.h b/openvdb_3_0_0_library/io/Queue.h deleted file mode 100755 index b40542c..0000000 --- a/openvdb_3_0_0_library/io/Queue.h +++ /dev/null @@ -1,277 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Queue.h -/// @author Peter Cucka - -#ifndef OPENVDB_IO_QUEUE_HAS_BEEN_INCLUDED -#define OPENVDB_IO_QUEUE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include // for std::copy -#include // for std::back_inserter - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -class Archive; - -/// @brief Queue for asynchronous output of grids to files or streams -/// -/// @warning The queue holds shared pointers to grids. It is not safe -/// to modify a grid that has been placed in the queue. Instead, -/// make a deep copy of the grid (Grid::deepCopy()). -/// -/// @par Example: -/// @code -/// #include -/// #include -/// #include -/// #include -/// -/// using openvdb::io::Queue; -/// -/// struct MyNotifier -/// { -/// // Use a concurrent container, because queue callback functions -/// // must be thread-safe. -/// typedef tbb::concurrent_hash_map FilenameMap; -/// FilenameMap filenames; -/// -/// // Callback function that prints the status of a completed task. -/// void callback(Queue::Id id, Queue::Status status) -/// { -/// const bool ok = (status == Queue::SUCCEEDED); -/// FilenameMap::accessor acc; -/// if (filenames.find(acc, id)) { -/// std::cout << (ok ? "wrote " : "failed to write ") -/// << acc->second << std::endl; -/// filenames.erase(acc); -/// } -/// } -/// }; -/// -/// int main() -/// { -/// // Construct an object to receive notifications from the queue. -/// // The object's lifetime must exceed the queue's. -/// MyNotifier notifier; -/// -/// Queue queue; -/// -/// // Register the callback() method of the MyNotifier object -/// // to receive notifications of completed tasks. -/// queue.addNotifier(boost::bind(&MyNotifier::callback, ¬ifier, _1, _2)); -/// -/// // Queue grids for output (e.g., for each step of a simulation). -/// for (int step = 1; step <= 10; ++step) { -/// openvdb::FloatGrid::Ptr grid = ...; -/// -/// std::ostringstream os; -/// os << "mygrid." << step << ".vdb"; -/// const std::string filename = os.str(); -/// -/// Queue::Id id = queue.writeGrid(grid, openvdb::io::File(filename)); -/// -/// // Associate the filename with the ID of the queued task. -/// MyNotifier::FilenameMap::accessor acc; -/// notifier.filenames.insert(acc, id); -/// acc->second = filename; -/// } -/// } -/// @endcode -/// Output: -/// @code -/// wrote mygrid.1.vdb -/// wrote mygrid.2.vdb -/// wrote mygrid.4.vdb -/// wrote mygrid.3.vdb -/// ... -/// wrote mygrid.10.vdb -/// @endcode -/// Note that tasks do not necessarily complete in the order in which they were queued. -class OPENVDB_API Queue -{ -public: - /// Default maximum queue length (see setCapacity()) - static const Index32 DEFAULT_CAPACITY = 100; - /// @brief Default maximum time in seconds to wait to queue a task - /// when the queue is full (see setTimeout()) - static const Index32 DEFAULT_TIMEOUT = 120; // seconds - - /// ID number of a queued task or of a registered notification callback - typedef Index32 Id; - - /// Status of a queued task - enum Status { UNKNOWN, PENDING, SUCCEEDED, FAILED }; - - - /// Construct a queue with the given capacity. - explicit Queue(Index32 capacity = DEFAULT_CAPACITY); - /// Block until all queued tasks complete (successfully or unsuccessfully). - ~Queue(); - - /// @brief Return @c true if the queue is empty. - bool empty() const; - /// @brief Return the number of tasks currently in the queue. - Index32 size() const; - - /// @brief Return the maximum number of tasks allowed in the queue. - /// @details Once the queue has reached its maximum size, adding - /// a new task will block until an existing task has executed. - Index32 capacity() const; - /// Set the maximum number of tasks allowed in the queue. - void setCapacity(Index32); - - /// Return the maximum number of seconds to wait to queue a task when the queue is full. - Index32 timeout() const; - /// Set the maximum number of seconds to wait to queue a task when the queue is full. - void setTimeout(Index32 seconds = DEFAULT_TIMEOUT); - - /// @brief Return the status of the task with the given ID. - /// @note Querying the status of a task that has already completed - /// (whether successfully or not) removes the task from the status registry. - /// Subsequent queries of its status will return UNKNOWN. - Status status(Id) const; - - typedef boost::function Notifier; - /// @brief Register a function that will be called with a task's ID - /// and status when that task completes, whether successfully or not. - /// @return an ID that can be passed to removeNotifier() to deregister the function - /// @details When multiple notifiers are registered, they are called - /// in the order in which they were registered. - /// @warning Notifiers are called from worker threads, so they must be thread-safe - /// and their lifetimes must exceed that of the queue. They must also not call, - /// directly or indirectly, addNotifier(), removeNotifier() or clearNotifiers(), - /// as that can result in a deadlock. - Id addNotifier(Notifier); - /// Deregister the notifier with the given ID. - void removeNotifier(Id); - /// Deregister all notifiers. - void clearNotifiers(); - - /// @brief Queue a single grid for output to a file or stream. - /// @param grid the grid to be serialized - /// @param archive the io::File or io::Stream to which to output the grid - /// @param fileMetadata optional file-level metadata - /// @return an ID with which the status of the queued task can be queried - /// @throw RuntimeError if the task cannot be queued within the time limit - /// (see setTimeout()) because the queue is full - /// @par Example: - /// @code - /// openvdb::FloatGrid::Ptr grid = ...; - /// - /// openvdb::io::Queue queue; - /// - /// // Write the grid to the file mygrid.vdb. - /// queue.writeGrid(grid, openvdb::io::File("mygrid.vdb")); - /// - /// // Stream the grid to a binary string. - /// std::ostringstream ostr(std::ios_base::binary); - /// queue.writeGrid(grid, openvdb::io::Stream(ostr)); - /// @endcode - Id writeGrid(GridBase::ConstPtr grid, const Archive& archive, - const MetaMap& fileMetadata = MetaMap()); - - /// @brief Queue a container of grids for output to a file. - /// @param grids any iterable container of grid pointers - /// (e.g., a GridPtrVec or GridPtrSet) - /// @param archive the io::File or io::Stream to which to output the grids - /// @param fileMetadata optional file-level metadata - /// @return an ID with which the status of the queued task can be queried - /// @throw RuntimeError if the task cannot be queued within the time limit - /// (see setTimeout()) because the queue is full - /// @par Example: - /// @code - /// openvdb::FloatGrid::Ptr floatGrid = ...; - /// openvdb::BoolGrid::Ptr boolGrid = ...; - /// openvdb::GridPtrVec grids; - /// grids.push_back(floatGrid); - /// grids.push_back(boolGrid); - /// - /// openvdb::io::Queue queue; - /// - /// // Write the grids to the file mygrid.vdb. - /// queue.write(grids, openvdb::io::File("mygrid.vdb")); - /// - /// // Stream the grids to a (binary) string. - /// std::ostringstream ostr(std::ios_base::binary); - /// queue.write(grids, openvdb::io::Stream(ostr)); - /// @endcode - template - Id write(const GridPtrContainer& grids, const Archive& archive, - const MetaMap& fileMetadata = MetaMap()); - -private: - // Disallow copying of instances of this class. - Queue(const Queue&); - Queue& operator=(const Queue&); - - Id writeGridVec(const GridCPtrVec&, const Archive&, const MetaMap&); - - struct Impl; - boost::shared_ptr mImpl; -}; // class Queue - - -template -inline Queue::Id -Queue::write(const GridPtrContainer& container, - const Archive& archive, const MetaMap& metadata) -{ - GridCPtrVec grids; - std::copy(container.begin(), container.end(), std::back_inserter(grids)); - return this->writeGridVec(grids, archive, metadata); -} - -// Specialization for vectors of const Grid pointers; no copying necessary -template<> -inline Queue::Id -Queue::write(const GridCPtrVec& grids, - const Archive& archive, const MetaMap& metadata) -{ - return this->writeGridVec(grids, archive, metadata); -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_QUEUE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Stream.cc b/openvdb_3_0_0_library/io/Stream.cc deleted file mode 100755 index 065b5de..0000000 --- a/openvdb_3_0_0_library/io/Stream.cc +++ /dev/null @@ -1,268 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Stream.h" - -#include "File.h" ///< @todo refactor -#include "GridDescriptor.h" -#include "TempFile.h" -#include -#include -#include -#include -#include // for remove() -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -struct Stream::Impl -{ - Impl(): mOutputStream(NULL) {} - Impl(const Impl& other) { *this = other; } - Impl& operator=(const Impl& other) - { - if (&other != this) { - mMeta = other.mMeta; ///< @todo deep copy? - mGrids = other.mGrids; ///< @todo deep copy? - mOutputStream = other.mOutputStream; - mFile.reset(); - } - return *this; - } - - MetaMap::Ptr mMeta; - GridPtrVecPtr mGrids; - std::ostream* mOutputStream; - boost::scoped_ptr mFile; -}; - - -//////////////////////////////////////// - - -namespace { - -/// @todo Use MappedFile auto-deletion instead. -void -removeTempFile(const std::string expectedFilename, const std::string& filename) -{ - if (filename == expectedFilename) { - if (0 != std::remove(filename.c_str())) { - std::string mesg = getErrorString(); - if (!mesg.empty()) mesg = " (" + mesg + ")"; - OPENVDB_LOG_WARN("failed to remove temporary file " << filename << mesg); - } - } -} - -} - - -Stream::Stream(std::istream& is, bool delayLoad): mImpl(new Impl) -{ - if (!is) return; - - if (delayLoad && Archive::isDelayedLoadingEnabled()) { - // Copy the contents of the stream to a temporary private file - // and open the file instead. - boost::scoped_ptr tempFile; - try { - tempFile.reset(new TempFile); - } catch (std::exception& e) { - std::string mesg; - if (e.what()) mesg = std::string(" (") + e.what() + ")"; - OPENVDB_LOG_WARN("failed to create a temporary file for delayed loading" << mesg - << "; will read directly from the input stream instead"); - } - if (tempFile) { - boost::iostreams::copy(is, *tempFile); - const std::string& filename = tempFile->filename(); - mImpl->mFile.reset(new File(filename)); - mImpl->mFile->setCopyMaxBytes(0); // don't make a copy of the temporary file - /// @todo Need to pass auto-deletion flag to MappedFile. - mImpl->mFile->open(delayLoad, boost::bind(&removeTempFile, filename, _1)); - } - } - - if (!mImpl->mFile) { - readHeader(is); - - // Tag the input stream with the library and file format version numbers - // and the compression options specified in the header. - StreamMetadata::Ptr streamMetadata(new StreamMetadata); - io::setStreamMetadataPtr(is, streamMetadata, /*transfer=*/false); - io::setVersion(is, libraryVersion(), fileVersion()); - io::setDataCompression(is, compression()); - - // Read in the VDB metadata. - mImpl->mMeta.reset(new MetaMap); - mImpl->mMeta->readMeta(is); - - // Read in the number of grids. - const boost::int32_t gridCount = readGridCount(is); - - // Read in all grids and insert them into mGrids. - mImpl->mGrids.reset(new GridPtrVec); - std::vector descriptors; - descriptors.reserve(gridCount); - Archive::NamedGridMap namedGrids; - for (boost::int32_t i = 0; i < gridCount; ++i) { - GridDescriptor gd; - gd.read(is); - descriptors.push_back(gd); - GridBase::Ptr grid = readGrid(gd, is); - mImpl->mGrids->push_back(grid); - namedGrids[gd.uniqueName()] = grid; - } - - // Connect instances (grids that share trees with other grids). - for (size_t i = 0, N = descriptors.size(); i < N; ++i) { - Archive::connectInstance(descriptors[i], namedGrids); - } - } -} - - -Stream::Stream(): mImpl(new Impl) -{ -} - - -Stream::Stream(std::ostream& os): mImpl(new Impl) -{ - mImpl->mOutputStream = &os; -} - - -Stream::~Stream() -{ -} - - -Stream::Stream(const Stream& other): Archive(other), mImpl(new Impl(*other.mImpl)) -{ -} - - -Stream& -Stream::operator=(const Stream& other) -{ - if (&other != this) { - mImpl.reset(new Impl(*other.mImpl)); - } - return *this; -} - - -boost::shared_ptr -Stream::copy() const -{ - return boost::shared_ptr(new Stream(*this)); -} - - -//////////////////////////////////////// - - -GridBase::Ptr -Stream::readGrid(const GridDescriptor& gd, std::istream& is) const -{ - GridBase::Ptr grid; - - if (!GridBase::isRegistered(gd.gridType())) { - OPENVDB_THROW(TypeError, "can't read grid \"" - << GridDescriptor::nameAsString(gd.uniqueName()) << - "\" from input stream because grid type " << gd.gridType() << " is unknown"); - } else { - grid = GridBase::createGrid(gd.gridType()); - if (grid) grid->setSaveFloatAsHalf(gd.saveFloatAsHalf()); - - Archive::readGrid(grid, gd, is); - } - return grid; -} - - -void -Stream::write(const GridCPtrVec& grids, const MetaMap& metadata) const -{ - if (mImpl->mOutputStream == NULL) { - OPENVDB_THROW(ValueError, "no output stream was specified"); - } - this->writeGrids(*mImpl->mOutputStream, grids, metadata); -} - - -void -Stream::writeGrids(std::ostream& os, const GridCPtrVec& grids, const MetaMap& metadata) const -{ - Archive::write(os, grids, /*seekable=*/false, metadata); -} - - -//////////////////////////////////////// - - -MetaMap::Ptr -Stream::getMetadata() const -{ - MetaMap::Ptr result; - if (mImpl->mFile) { - result = mImpl->mFile->getMetadata(); - } else if (mImpl->mMeta) { - // Return a deep copy of the file-level metadata - // that was read when this object was constructed. - result.reset(new MetaMap(*mImpl->mMeta)); - } - return result; -} - - -GridPtrVecPtr -Stream::getGrids() -{ - if (mImpl->mFile) { - return mImpl->mFile->getGrids(); - } - return mImpl->mGrids; -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/Stream.h b/openvdb_3_0_0_library/io/Stream.h deleted file mode 100755 index cf1c76c..0000000 --- a/openvdb_3_0_0_library/io/Stream.h +++ /dev/null @@ -1,120 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_IO_STREAM_HAS_BEEN_INCLUDED -#define OPENVDB_IO_STREAM_HAS_BEEN_INCLUDED - -#include "Archive.h" -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -class GridDescriptor; - - -/// Grid archive associated with arbitrary input and output streams (not necessarily files) -class OPENVDB_API Stream: public Archive -{ -public: - /// @brief Read grids from an input stream. - /// @details If @a delayLoad is true, map the contents of the input stream - /// into memory and enable delayed loading of grids. - /// @note Define the environment variable @c OPENVDB_DISABLE_DELAYED_LOAD - /// to disable delayed loading unconditionally. - explicit Stream(std::istream&, bool delayLoad = true); - - /// Construct an archive for stream output. - Stream(); - /// Construct an archive for output to the given stream. - explicit Stream(std::ostream&); - - Stream(const Stream&); - Stream& operator=(const Stream&); - - virtual ~Stream(); - - /// @brief Return a copy of this archive. - virtual Archive::Ptr copy() const; - - /// Return the file-level metadata in a newly created MetaMap. - MetaMap::Ptr getMetadata() const; - - /// Return pointers to the grids that were read from the input stream. - GridPtrVecPtr getGrids(); - - /// @brief Write the grids in the given container to this archive's output stream. - /// @throw ValueError if this archive was constructed without specifying an output stream. - virtual void write(const GridCPtrVec&, const MetaMap& = MetaMap()) const; - - /// @brief Write the grids in the given container to this archive's output stream. - /// @throw ValueError if this archive was constructed without specifying an output stream. - template - void write(const GridPtrContainerT&, const MetaMap& = MetaMap()) const; - -private: - /// Create a new grid of the type specified by the given descriptor, - /// then populate the grid from the given input stream. - /// @return the newly created grid. - GridBase::Ptr readGrid(const GridDescriptor&, std::istream&) const; - - void writeGrids(std::ostream&, const GridCPtrVec&, const MetaMap&) const; - - - struct Impl; - boost::scoped_ptr mImpl; -}; - - -//////////////////////////////////////// - - -template -inline void -Stream::write(const GridPtrContainerT& container, const MetaMap& metadata) const -{ - GridCPtrVec grids; - std::copy(container.begin(), container.end(), std::back_inserter(grids)); - this->write(grids, metadata); -} - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_STREAM_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/TempFile.cc b/openvdb_3_0_0_library/io/TempFile.cc deleted file mode 100755 index c7ecd0e..0000000 --- a/openvdb_3_0_0_library/io/TempFile.cc +++ /dev/null @@ -1,167 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file TempFile.cc - -#include "TempFile.h" - -#include -#ifndef _MSC_VER -#include -#include -#include // for std::getenv(), mkstemp() -#include // for mode_t -#include // for mkdir(), umask() -#include // for access() -#else -#include // for std::filebuf -#endif -#include // for std::tmpnam(), L_tmpnam, P_tmpdir -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -struct TempFile::TempFileImpl -{ - const std::string& filename() const { return mPath; } - - bool is_open() const { return mBuffer.is_open(); } - - /// @internal boost::filesystem::unique_path(), etc. might be useful here, - /// but as of 9/2014, Houdini ships without the Boost.Filesystem library, - /// which makes it much less convenient to use that library. -#ifndef _MSC_VER - TempFileImpl(std::ostream& os): mFileDescr(-1) { this->init(os); } - - void init(std::ostream& os) - { - std::string fn = this->getTempDir() + "/openvdb_temp_XXXXXX"; - std::vector fnbuf(fn.begin(), fn.end()); - fnbuf.push_back(char(0)); - - //const mode_t savedMode = ::umask(~(S_IRUSR | S_IWUSR)); - mFileDescr = ::mkstemp(&fnbuf[0]); - //::umask(savedMode); - if (mFileDescr < 0) { - OPENVDB_THROW(IoError, "failed to generate temporary file"); - } - - mPath.assign(&fnbuf[0]); - - mDevice = DeviceType(mFileDescr, boost::iostreams::never_close_handle); - mBuffer.open(mDevice); - os.rdbuf(&mBuffer); - - if (!os.good()) { - OPENVDB_THROW(IoError, "failed to open temporary file " + mPath); - } - } - - void close() { mBuffer.close(); if (mFileDescr >= 0) ::close(mFileDescr); } - - static std::string getTempDir() - { - if (const char* dir = std::getenv("OPENVDB_TEMP_DIR")) { - if (0 != ::access(dir, F_OK)) { - ::mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR); - if (0 != ::access(dir, F_OK)) { - OPENVDB_THROW(IoError, - "failed to create OPENVDB_TEMP_DIR (" + std::string(dir) + ")"); - } - } - return dir; - } - if (const char* dir = std::getenv("TMPDIR")) return dir; - return P_tmpdir; - } - - typedef boost::iostreams::file_descriptor_sink DeviceType; - typedef boost::iostreams::stream_buffer BufferType; - - std::string mPath; - DeviceType mDevice; - BufferType mBuffer; - int mFileDescr; -#else // _MSC_VER - // Use only standard library routines; no POSIX. - - TempFileImpl(std::ostream& os) { this->init(os); } - - void init(std::ostream& os) - { - char fnbuf[L_tmpnam]; - const char* filename = std::tmpnam(fnbuf); - if (!filename) { - OPENVDB_THROW(IoError, "failed to generate name for temporary file"); - } - /// @todo This is not safe, since another process could open a file - /// with this name before we do. Unfortunately, there is no safe, - /// portable way to create a temporary file. - mPath = filename; - - const std::ios_base::openmode mode = (std::ios_base::out | std::ios_base::binary); - os.rdbuf(mBuffer.open(mPath.c_str(), mode)); - if (!os.good()) { - OPENVDB_THROW(IoError, "failed to open temporary file " + mPath); - } - } - - void close() { mBuffer.close(); } - - std::string mPath; - std::filebuf mBuffer; -#endif // _MSC_VER - -private: - TempFileImpl(const TempFileImpl&); // disable copying - TempFileImpl& operator=(const TempFileImpl&); // disable assignment -}; - - -TempFile::TempFile(): std::ostream(NULL), mImpl(new TempFileImpl(*this)) {} -TempFile::~TempFile() { this->close(); } -const std::string& TempFile::filename() const { return mImpl->filename(); } -bool TempFile::is_open() const { return mImpl->is_open(); } -void TempFile::close() { mImpl->close(); } - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/TempFile.h b/openvdb_3_0_0_library/io/TempFile.h deleted file mode 100755 index 99f2d1f..0000000 --- a/openvdb_3_0_0_library/io/TempFile.h +++ /dev/null @@ -1,81 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file TempFile.h - -#ifndef OPENVDB_IO_TEMPFILE_HAS_BEEN_INCLUDED -#define OPENVDB_IO_TEMPFILE_HAS_BEEN_INCLUDED - -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace io { - -/// Output stream to a unique temporary file -class OPENVDB_API TempFile: public std::ostream -{ -public: - /// @brief Create and open a unique file. - /// @details On UNIX systems, the file is created in the directory specified by - /// the environment variable @c OPENVDB_TEMP_DIR, if that variable is defined, - /// or else in the directory specified by @c TMPDIR, if that variable is defined. - /// Otherwise (and on non-UNIX systems), the file is created in the system default - /// temporary directory. - TempFile(); - ~TempFile(); - - /// Return the path to the temporary file. - const std::string& filename() const; - - /// Return @c true if the file is open for writing. - bool is_open() const; - - /// Close the file. - void close(); - -private: - struct TempFileImpl; - boost::scoped_ptr mImpl; -}; - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_TEMPFILE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/io/io.h b/openvdb_3_0_0_library/io/io.h deleted file mode 100755 index 5f19f8c..0000000 --- a/openvdb_3_0_0_library/io/io.h +++ /dev/null @@ -1,277 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_IO_IO_HAS_BEEN_INCLUDED -#define OPENVDB_IO_IO_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include // for std::ios_base -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -class MetaMap; - -namespace io { - -/// @brief Container for metadata describing how to unserialize grids from and/or -/// serialize grids to a stream (which file format, compression scheme, etc. to use) -/// @details This class is mainly for internal use. -class OPENVDB_API StreamMetadata -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - StreamMetadata(); - StreamMetadata(const StreamMetadata&); - explicit StreamMetadata(std::ios_base&); - ~StreamMetadata(); - - StreamMetadata& operator=(const StreamMetadata&); - - /// @brief Transfer metadata items directly to the given stream. - /// @todo Deprecate direct transfer; use StreamMetadata structs everywhere. - void transferTo(std::ios_base&) const; - - uint32_t fileVersion() const; - void setFileVersion(uint32_t); - - VersionId libraryVersion() const; - void setLibraryVersion(VersionId); - - uint32_t compression() const; - void setCompression(uint32_t); - - uint32_t gridClass() const; - void setGridClass(uint32_t); - - const void* backgroundPtr() const; - void setBackgroundPtr(const void*); - - bool halfFloat() const; - void setHalfFloat(bool); - - bool writeGridStats() const; - void setWriteGridStats(bool); - - //@{ - /// @brief Return a (reference to a) copy of the metadata of the grid currently - /// being read or written. - /// @details Some grid metadata might duplicate information returned by - /// gridClass(), backgroundPtr() and other accessors, but those values - /// are not guaranteed to be kept in sync. - MetaMap& gridMetadata(); - const MetaMap& gridMetadata() const; - //@} - - typedef std::map AuxDataMap; - //@{ - /// @brief Return a map that can be populated with arbitrary user data. - AuxDataMap& auxData(); - const AuxDataMap& auxData() const; - //@} - - /// Return a string describing this stream metadata. - std::string str() const; - -private: - struct Impl; - boost::scoped_ptr mImpl; -}; // class StreamMetadata - - -/// Write a description of the given metadata to an output stream. -std::ostream& operator<<(std::ostream&, const StreamMetadata&); - -std::ostream& operator<<(std::ostream&, const StreamMetadata::AuxDataMap&); - - -//////////////////////////////////////// - - -class File; - -/// @brief Handle to control the lifetime of a memory-mapped .vdb file -class OPENVDB_API MappedFile -{ -public: - typedef boost::shared_ptr Ptr; - - ~MappedFile(); - - /// Return the filename of the mapped file. - std::string filename() const; - - /// @brief Return a new stream buffer for the mapped file. - /// @details Typical usage is - /// @code - /// openvdb::io::MappedFile::Ptr mappedFile = ...; - /// boost::shared_ptr buf = mappedFile->createBuffer(); - /// std::istream istrm(buf.get()); - /// // Read from istrm... - /// @endcode - /// The buffer must persist as long as the stream is open. - boost::shared_ptr createBuffer() const; - - typedef boost::function Notifier; - /// @brief Register a function that will be called with this file's name - /// when the file is unmapped. - void setNotifier(const Notifier&); - /// Deregister the notifier. - void clearNotifier(); - -private: - friend class File; - - explicit MappedFile(const std::string& filename, bool autoDelete = false); - - MappedFile(const MappedFile&); // not copyable - MappedFile& operator=(const MappedFile&); // not copyable - - class Impl; - boost::scoped_ptr mImpl; -}; // class MappedFile - - -//////////////////////////////////////// - - -/// Return a string (possibly empty) describing the given system error code. -std::string getErrorString(int errorNum); - - -/// Return a string (possibly empty) describing the most recent system error. -std::string getErrorString(); - - -//////////////////////////////////////// - - -/// @brief Return the file format version number associated with the given input stream. -/// @sa File::setFormatVersion() -OPENVDB_API uint32_t getFormatVersion(std::ios_base&); - -/// @brief Return the (major, minor) library version number associated with the given input stream. -/// @sa File::setLibraryVersion() -OPENVDB_API VersionId getLibraryVersion(std::ios_base&); - -/// @brief Return a string of the form "./", giving the library -/// and file format version numbers associated with the given input stream. -OPENVDB_API std::string getVersion(std::ios_base&); - -/// Associate the current file format and library version numbers with the given input stream. -OPENVDB_API void setCurrentVersion(std::istream&); - -/// @brief Associate specific file format and library version numbers with the given stream. -/// @details This is typically called immediately after reading a header that contains -/// the version numbers. Data read subsequently can then be interpreted appropriately. -OPENVDB_API void setVersion(std::ios_base&, const VersionId& libraryVersion, uint32_t fileVersion); - -/// @brief Return a bitwise OR of compression option flags (COMPRESS_ZIP, -/// COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed -/// or output data should be compressed. -OPENVDB_API uint32_t getDataCompression(std::ios_base&); -/// @brief Associate with the given stream a bitwise OR of compression option flags -/// (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data -/// is compressed or output data should be compressed. -OPENVDB_API void setDataCompression(std::ios_base&, uint32_t compressionFlags); - -/// @brief Return the class (GRID_LEVEL_SET, GRID_UNKNOWN, etc.) of the grid -/// currently being read from or written to the given stream. -OPENVDB_API uint32_t getGridClass(std::ios_base&); -/// @brief Associate with the given stream the class (GRID_LEVEL_SET, GRID_UNKNOWN, etc.) -/// of the grid currently being read or written. -OPENVDB_API void setGridClass(std::ios_base&, uint32_t); - -/// @brief Return true if floating-point values should be quantized to 16 bits when writing -/// to the given stream or promoted back from 16-bit to full precision when reading from it. -OPENVDB_API bool getHalfFloat(std::ios_base&); -/// @brief Specify whether floating-point values should be quantized to 16 bits when writing -/// to the given stream or promoted back from 16-bit to full precision when reading from it. -OPENVDB_API void setHalfFloat(std::ios_base&, bool); - -/// @brief Return a pointer to the background value of the grid -/// currently being read from or written to the given stream. -OPENVDB_API const void* getGridBackgroundValuePtr(std::ios_base&); -/// @brief Specify (a pointer to) the background value of the grid -/// currently being read from or written to the given stream. -/// @note The pointer must remain valid until the entire grid has been read or written. -OPENVDB_API void setGridBackgroundValuePtr(std::ios_base&, const void* background); - -/// @brief Return @c true if grid statistics (active voxel count and bounding box, etc.) -/// should be computed and stored as grid metadata when writing to the given stream. -OPENVDB_API bool getWriteGridStatsMetadata(std::ios_base&); -/// @brief Specify whether to compute grid statistics (active voxel count and bounding box, etc.) -/// and store them as grid metadata when writing to the given stream. -OPENVDB_API void setWriteGridStatsMetadata(std::ios_base&, bool writeGridStats); - -/// @brief Return a shared pointer to the memory-mapped file with which the given stream -/// is associated, or a null pointer if the stream is not associated with a memory-mapped file. -OPENVDB_API boost::shared_ptr getMappedFilePtr(std::ios_base&); -/// @brief Associate the given stream with (a shared pointer to) a memory-mapped file. -/// @note The shared pointer object (not just the io::MappedFile object to which it points) -/// must remain valid until the file is closed. -OPENVDB_API void setMappedFilePtr(std::ios_base&, boost::shared_ptr&); - -/// @brief Return a shared pointer to an object that stores metadata (file format, -/// compression scheme, etc.) for use when reading from or writing to the given stream. -OPENVDB_API boost::shared_ptr getStreamMetadataPtr(std::ios_base&); -/// @brief Associate the given stream with (a shared pointer to) an object that stores -/// metadata (file format, compression scheme, etc.) for use when reading from -/// or writing to the stream. -/// @details If @a transfer is true, copy metadata from the object directly to the stream -/// (for backward compatibility with older versions of the library). -/// @note The shared pointer object (not just the io::StreamMetadata object to which it points) -/// must remain valid until the file is closed. -OPENVDB_API void setStreamMetadataPtr(std::ios_base&, - boost::shared_ptr&, bool transfer = true); -/// @brief Dissociate the given stream from its metadata object (if it has one) -/// and return a shared pointer to the object. -OPENVDB_API boost::shared_ptr clearStreamMetadataPtr(std::ios_base&); - -} // namespace io -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_IO_IO_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/BBox.h b/openvdb_3_0_0_library/math/BBox.h deleted file mode 100755 index f2a1135..0000000 --- a/openvdb_3_0_0_library/math/BBox.h +++ /dev/null @@ -1,467 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_BBOX_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_BBOX_HAS_BEEN_INCLUDED - -#include "Math.h" // for math::isApproxEqual() and math::Tolerance() -#include "Vec3.h" -#include -#include // for min/max -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @brief Axis-aligned bounding box -template -class BBox -{ -public: - typedef Vec3T Vec3Type; - typedef Vec3T ValueType; - typedef Vec3T VectorType; - typedef typename Vec3Type::ValueType ElementType; - - /// @brief Default constructor creates an invalid BBox - BBox(); - - /// @brief Constructor based on a minimum and maximum point. - BBox(const Vec3T& xyzMin, const Vec3T& xyzMax); - - /// @brief Constructor based on a minimum and maximum point. - /// If sorted is false the points will be sorted by x,y,z component. - BBox(const Vec3T& xyzMin, const Vec3T& xyzMax, bool sorted); - - /// @brief Contruct a cubical BBox from a minimum coordinate and a - /// single edge length. - /// @note inclusive for integral ElementTypes - BBox(const Vec3T& xyzMin, const ElementType& length); - - /// @brief Constructor based on a raw array of six points. If - /// sorted is false the points will be sorted by x,y,z component. - explicit BBox(const ElementType* xyz, bool sorted = true); - - /// @brief Copy constructor - BBox(const BBox& other); - - /// @brief Sort the min/max by x,y,z component. - void sort(); - - /// @brief Return a const reference to the minimum point of the BBox - const Vec3T& min() const { return mMin; } - - /// @brief Return a const reference to the maximum point of the BBox - const Vec3T& max() const { return mMax; } - - /// @brief Return a non-const reference to the minimum point of the BBox - Vec3T& min() { return mMin; } - - /// @brief Return a non-const reference to the maximum point of the BBox - Vec3T& max() { return mMax; } - - /// @brief Return true if the two BBox'es are identical - bool operator==(const BBox& rhs) const; - - /// @brief Return true if the two BBox'es are not identical - bool operator!=(const BBox& rhs) const { return !(*this == rhs); } - - /// @brief Return true if the BBox is empty, i.e. has no - /// (positive) volume. - bool empty() const; - - /// @brief Return true if the BBox has a (positive) volume. - bool hasVolume() const { return !this->empty(); } - - /// @brief Return true if the BBox is valid, i.e. as a (positive) volume. - operator bool() const { return !this->empty(); } - - /// @brief Return true if the all components of mMin <= mMax, - /// i.e. the volume is not negative. - /// @note For floating point values a tolerance is used for this test. - bool isSorted() const; - - /// @brief Return the center point of the BBox - Vec3d getCenter() const; - - /// @brief Returns the extents of the BBox, i.e. the length per axis - /// for floating points values or number of grids per axis points - /// integral values. - /// @note inclusive for integral ElementTypes - Vec3T extents() const; - - /// @brief Return the volume spanned by this BBox. - ElementType volume() const { Vec3T e = this->extents(); return e[0] * e[1] * e[2]; } - - /// Return the index (0, 1 or 2) of the longest axis. - size_t maxExtent() const { return MaxIndex(mMax - mMin); } - - /// Return the index (0, 1 or 2) of the shortest axis. - size_t minExtent() const { return MinIndex(mMax - mMin); } - - /// Return @c true if point (x, y, z) is inside this bounding box. - bool isInside(const Vec3T& xyz) const; - - /// Return @c true if the given bounding box is inside this bounding box. - bool isInside(const BBox&) const; - - /// Return @c true if the given bounding box overlaps with this bounding box. - bool hasOverlap(const BBox&) const; - - /// Pad this bounding box. - void expand(ElementType padding); - - /// Expand this bounding box to enclose point (x, y, z). - void expand(const Vec3T& xyz); - - /// Union this bounding box with the given bounding box. - void expand(const BBox&); - // @brief Union this bbox with the cubical bbox defined from xyzMin and - // length - /// @note inclusive for integral ElementTypes - void expand(const Vec3T& xyzMin, const ElementType& length); - - /// Translate this bounding box by \f$(t_x, t_y, t_z)\f$. - void translate(const Vec3T& t); - - /// Apply a map to this bounding box - template - BBox applyMap(const MapType& map) const; - - /// Apply the inverse of a map to this bounding box - template - BBox applyInverseMap(const MapType& map) const; - - /// Unserialize this bounding box from the given stream. - void read(std::istream& is) { mMin.read(is); mMax.read(is); } - - /// Serialize this bounding box to the given stream. - void write(std::ostream& os) const { mMin.write(os); mMax.write(os); } - -private: - Vec3T mMin, mMax; -}; // class BBox - - -//////////////////////////////////////// - - -template -inline -BBox::BBox(): - mMin( std::numeric_limits::max()), - mMax(-std::numeric_limits::max()) -{ -} - -template -inline -BBox::BBox(const Vec3T& xyzMin, const Vec3T& xyzMax): - mMin(xyzMin), mMax(xyzMax) -{ -} - -template -inline -BBox::BBox(const Vec3T& xyzMin, const Vec3T& xyzMax, bool sorted): - mMin(xyzMin), mMax(xyzMax) -{ - if (!sorted) this->sort(); -} - -template -inline -BBox::BBox(const Vec3T& xyzMin, const ElementType& length): - mMin(xyzMin), mMax(xyzMin) -{ - // min and max are inclusive for integral ElementType - const ElementType size = boost::is_integral::value ? length-1 : length; - mMax[0] += size; - mMax[1] += size; - mMax[2] += size; -} - -template -inline -BBox::BBox(const ElementType* xyz, bool sorted): - mMin(xyz[0], xyz[1], xyz[2]), - mMax(xyz[3], xyz[4], xyz[5]) -{ - if (!sorted) this->sort(); -} - - -template -inline -BBox::BBox(const BBox& other): - mMin(other.mMin), mMax(other.mMax) -{ -} - - -//////////////////////////////////////// - - -template -inline bool -BBox::empty() const -{ - if (boost::is_integral::value) { - // min and max are inclusive for integral ElementType - return (mMin[0] > mMax[0] || mMin[1] > mMax[1] || mMin[2] > mMax[2]); - } - return mMin[0] >= mMax[0] || mMin[1] >= mMax[1] || mMin[2] >= mMax[2]; -} - - -template -inline bool -BBox::operator==(const BBox& rhs) const -{ - if (boost::is_integral::value) { - return mMin == rhs.min() && mMax == rhs.max(); - } else { - return math::isApproxEqual(mMin, rhs.min()) && math::isApproxEqual(mMax, rhs.max()); - } -} - - -template -inline void -BBox::sort() -{ - Vec3T tMin(mMin), tMax(mMax); - for (int i = 0; i < 3; ++i) { - mMin[i] = std::min(tMin[i], tMax[i]); - mMax[i] = std::max(tMin[i], tMax[i]); - } -} - - -template -inline bool -BBox::isSorted() const -{ - if (boost::is_integral::value) { - return (mMin[0] <= mMax[0] && mMin[1] <= mMax[1] && mMin[2] <= mMax[2]); - } else { - ElementType t = math::Tolerance::value(); - return (mMin[0] < (mMax[0] + t) && mMin[1] < (mMax[1] + t) && mMin[2] < (mMax[2] + t)); - } -} - - -template -inline Vec3d -BBox::getCenter() const -{ - return (Vec3d(mMin.asPointer()) + Vec3d(mMax.asPointer())) * 0.5; -} - - -template -inline Vec3T -BBox::extents() const -{ - if (boost::is_integral::value) { - return (mMax - mMin) + Vec3T(1, 1, 1); - } else { - return (mMax - mMin); - } -} - -//////////////////////////////////////// - - -template -inline bool -BBox::isInside(const Vec3T& xyz) const -{ - if (boost::is_integral::value) { - return xyz[0] >= mMin[0] && xyz[0] <= mMax[0] && - xyz[1] >= mMin[1] && xyz[1] <= mMax[1] && - xyz[2] >= mMin[2] && xyz[2] <= mMax[2]; - } else { - ElementType t = math::Tolerance::value(); - return xyz[0] > (mMin[0]-t) && xyz[0] < (mMax[0]+t) && - xyz[1] > (mMin[1]-t) && xyz[1] < (mMax[1]+t) && - xyz[2] > (mMin[2]-t) && xyz[2] < (mMax[2]+t); - } -} - - -template -inline bool -BBox::isInside(const BBox& b) const -{ - if (boost::is_integral::value) { - return b.min()[0] >= mMin[0] && b.max()[0] <= mMax[0] && - b.min()[1] >= mMin[1] && b.max()[1] <= mMax[1] && - b.min()[2] >= mMin[2] && b.max()[2] <= mMax[2]; - } else { - ElementType t = math::Tolerance::value(); - return (b.min()[0]-t) > mMin[0] && (b.max()[0]+t) < mMax[0] && - (b.min()[1]-t) > mMin[1] && (b.max()[1]+t) < mMax[1] && - (b.min()[2]-t) > mMin[2] && (b.max()[2]+t) < mMax[2]; - } -} - - -template -inline bool -BBox::hasOverlap(const BBox& b) const -{ - if (boost::is_integral::value) { - return mMax[0] >= b.min()[0] && mMin[0] <= b.max()[0] && - mMax[1] >= b.min()[1] && mMin[1] <= b.max()[1] && - mMax[2] >= b.min()[2] && mMin[2] <= b.max()[2]; - } else { - ElementType t = math::Tolerance::value(); - return mMax[0] > (b.min()[0]-t) && mMin[0] < (b.max()[0]+t) && - mMax[1] > (b.min()[1]-t) && mMin[1] < (b.max()[1]+t) && - mMax[2] > (b.min()[2]-t) && mMin[2] < (b.max()[2]+t); - } -} - - -//////////////////////////////////////// - - -template -inline void -BBox::expand(ElementType dx) -{ - dx = std::abs(dx); - for (int i = 0; i < 3; ++i) { - mMin[i] -= dx; - mMax[i] += dx; - } -} - - -template -inline void -BBox::expand(const Vec3T& xyz) -{ - for (int i = 0; i < 3; ++i) { - mMin[i] = std::min(mMin[i], xyz[i]); - mMax[i] = std::max(mMax[i], xyz[i]); - } -} - - -template -inline void -BBox::expand(const BBox& b) -{ - for (int i = 0; i < 3; ++i) { - mMin[i] = std::min(mMin[i], b.min()[i]); - mMax[i] = std::max(mMax[i], b.max()[i]); - } -} - -template -inline void -BBox::expand(const Vec3T& xyzMin, const ElementType& length) -{ - const ElementType size = boost::is_integral::value ? length-1 : length; - for (int i = 0; i < 3; ++i) { - mMin[i] = std::min(mMin[i], xyzMin[i]); - mMax[i] = std::max(mMax[i], xyzMin[i] + size); - } -} - - -template -inline void -BBox::translate(const Vec3T& dx) -{ - mMin += dx; - mMax += dx; -} - -template -template -inline BBox -BBox::applyMap(const MapType& map) const -{ - typedef Vec3 Vec3R; - BBox bbox; - bbox.expand(map.applyMap(Vec3R(mMin[0], mMin[1], mMin[2]))); - bbox.expand(map.applyMap(Vec3R(mMin[0], mMin[1], mMax[2]))); - bbox.expand(map.applyMap(Vec3R(mMin[0], mMax[1], mMin[2]))); - bbox.expand(map.applyMap(Vec3R(mMax[0], mMin[1], mMin[2]))); - bbox.expand(map.applyMap(Vec3R(mMax[0], mMax[1], mMin[2]))); - bbox.expand(map.applyMap(Vec3R(mMax[0], mMin[1], mMax[2]))); - bbox.expand(map.applyMap(Vec3R(mMin[0], mMax[1], mMax[2]))); - bbox.expand(map.applyMap(Vec3R(mMax[0], mMax[1], mMax[2]))); - return bbox; -} - -template -template -inline BBox -BBox::applyInverseMap(const MapType& map) const -{ - typedef Vec3 Vec3R; - BBox bbox; - bbox.expand(map.applyInverseMap(Vec3R(mMin[0], mMin[1], mMin[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMin[0], mMin[1], mMax[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMin[0], mMax[1], mMin[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMax[0], mMin[1], mMin[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMax[0], mMax[1], mMin[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMax[0], mMin[1], mMax[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMin[0], mMax[1], mMax[2]))); - bbox.expand(map.applyInverseMap(Vec3R(mMax[0], mMax[1], mMax[2]))); - return bbox; -} - -//////////////////////////////////////// - - -template -inline std::ostream& -operator<<(std::ostream& os, const BBox& b) -{ - os << b.min() << " -> " << b.max(); - return os; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_BBOX_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Coord.h b/openvdb_3_0_0_library/math/Coord.h deleted file mode 100755 index 7e74e8e..0000000 --- a/openvdb_3_0_0_library/math/Coord.h +++ /dev/null @@ -1,444 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED - -#include -#include "Math.h" -#include "Vec3.h" - -namespace tbb { class split; } // forward declaration - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @brief Signed (x, y, z) 32-bit integer coordinates -class Coord -{ -public: - typedef int32_t Int32; - typedef uint32_t Index32; - typedef Vec3 Vec3i; - typedef Vec3 Vec3I; - - typedef Int32 ValueType; - typedef std::numeric_limits Limits; - - Coord() - { mVec[0] = mVec[1] = mVec[2] = 0; } - explicit Coord(Int32 xyz) - { mVec[0] = mVec[1] = mVec[2] = xyz; } - Coord(Int32 x, Int32 y, Int32 z) - { mVec[0] = x; mVec[1] = y; mVec[2] = z; } - explicit Coord(const Vec3i& v) - { mVec[0] = v[0]; mVec[1] = v[1]; mVec[2] = v[2]; } - explicit Coord(const Vec3I& v) - { mVec[0] = Int32(v[0]); mVec[1] = Int32(v[1]); mVec[2] = Int32(v[2]); } - explicit Coord(const Int32* v) - { mVec[0] = v[0]; mVec[1] = v[1]; mVec[2] = v[2]; } - - /// @brief Return the smallest possible coordinate - static Coord min() { return Coord(Limits::min()); } - - /// @brief Return the largest possible coordinate - static Coord max() { return Coord(Limits::max()); } - - /// @brief Return @a xyz rounded to the closest integer coordinates - /// (cell centered conversion). - template static Coord round(const Vec3& xyz) - { return Coord(Int32(Round(xyz[0])), Int32(Round(xyz[1])), Int32(Round(xyz[2]))); } - /// @brief Return the largest integer coordinates that are not greater - /// than @a xyz (node centered conversion). - template static Coord floor(const Vec3& xyz) - { return Coord(Int32(Floor(xyz[0])), Int32(Floor(xyz[1])), Int32(Floor(xyz[2]))); } - - /// @brief Return the largest integer coordinates that are not greater - /// than @a xyz+1 (node centered conversion). - template static Coord ceil(const Vec3& xyz) - { return Coord(Int32(Ceil(xyz[0])), Int32(Ceil(xyz[1])), Int32(Ceil(xyz[2]))); } - - Coord& reset(Int32 x, Int32 y, Int32 z) - { mVec[0] = x; mVec[1] = y; mVec[2] = z; this->dirty(); return *this; } - Coord& reset(Int32 xyz) { return this->reset(xyz, xyz, xyz); } - - Coord& setX(Int32 x) { mVec[0] = x; dirty(); return *this; } - Coord& setY(Int32 y) { mVec[1] = y; dirty(); return *this; } - Coord& setZ(Int32 z) { mVec[2] = z; dirty(); return *this; } - - Coord& offset(Int32 dx, Int32 dy, Int32 dz) - { mVec[0]+=dx; mVec[1]+=dy; mVec[2]+=dz; this->dirty(); return *this; } - Coord& offset(Int32 n) { return this->offset(n, n, n); } - Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const - { return Coord(mVec[0] + dx, mVec[1] + dy, mVec[2] + dz); } - Coord offsetBy(Int32 n) const { return offsetBy(n, n, n); } - - Coord& operator+=(const Coord& rhs) - { mVec[0] += rhs[0]; mVec[1] += rhs[1]; mVec[2] += rhs[2]; return *this; } - Coord& operator-=(const Coord& rhs) - { mVec[0] -= rhs[0]; mVec[1] -= rhs[1]; mVec[2] -= rhs[2]; return *this; } - Coord operator+(const Coord& rhs) const - { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); } - Coord operator-(const Coord& rhs) const - { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); } - Coord operator-() const { return Coord(-mVec[0], -mVec[1], -mVec[2]); } - - Coord operator>> (size_t n) const { return Coord(mVec[0]>>n, mVec[1]>>n, mVec[2]>>n); } - Coord operator<< (size_t n) const { return Coord(mVec[0]<>=(size_t n) { mVec[0]>>=n; mVec[1]>>=n; mVec[2]>>=n; dirty(); return *this; } - Coord operator& (Int32 n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); } - Coord operator| (Int32 n) const { return Coord(mVec[0] | n, mVec[1] | n, mVec[2] | n); } - Coord& operator&= (Int32 n) { mVec[0]&=n; mVec[1]&=n; mVec[2]&=n; dirty(); return *this; } - Coord& operator|= (Int32 n) { mVec[0]|=n; mVec[1]|=n; mVec[2]|=n; dirty(); return *this; } - - Int32 x() const { return mVec[0]; } - Int32 y() const { return mVec[1]; } - Int32 z() const { return mVec[2]; } - Int32 operator[](size_t i) const { assert(i < 3); return mVec[i]; } - Int32& x() { dirty(); return mVec[0]; } - Int32& y() { dirty(); return mVec[1]; } - Int32& z() { dirty(); return mVec[2]; } - Int32& operator[](size_t i) { assert(i < 3); dirty(); return mVec[i]; } - - const Int32* asPointer() const { return mVec; } - Int32* asPointer() { dirty(); return mVec; } - Vec3d asVec3d() const { return Vec3d(double(mVec[0]), double(mVec[1]), double(mVec[2])); } - Vec3s asVec3s() const { return Vec3s(float(mVec[0]), float(mVec[1]), float(mVec[2])); } - Vec3i asVec3i() const { return Vec3i(mVec); } - Vec3I asVec3I() const { return Vec3I(Index32(mVec[0]), Index32(mVec[1]), Index32(mVec[2])); } - void asXYZ(Int32& x, Int32& y, Int32& z) const { x = mVec[0]; y = mVec[1]; z = mVec[2]; } - - bool operator==(const Coord& rhs) const - { return (mVec[0] == rhs.mVec[0] && mVec[1] == rhs.mVec[1] && mVec[2] == rhs.mVec[2]); } - bool operator!=(const Coord& rhs) const { return !(*this == rhs); } - - /// Lexicographic less than - bool operator<(const Coord& rhs) const - { - return this->x() < rhs.x() ? true : this->x() > rhs.x() ? false - : this->y() < rhs.y() ? true : this->y() > rhs.y() ? false - : this->z() < rhs.z() ? true : false; - } - /// Lexicographic less than or equal to - bool operator<=(const Coord& rhs) const - { - return this->x() < rhs.x() ? true : this->x() > rhs.x() ? false - : this->y() < rhs.y() ? true : this->y() > rhs.y() ? false - : this->z() <=rhs.z() ? true : false; - } - /// Lexicographic greater than - bool operator>(const Coord& rhs) const { return !(*this <= rhs); } - /// Lexicographic greater than or equal to - bool operator>=(const Coord& rhs) const { return !(*this < rhs); } - - //HashType hash() { if (!mHash) { mHash = ...; } return mHash; } - - /// Perform a component-wise minimum with the other Coord. - void minComponent(const Coord& other) - { - mVec[0] = std::min(mVec[0], other.mVec[0]); - mVec[1] = std::min(mVec[1], other.mVec[1]); - mVec[2] = std::min(mVec[2], other.mVec[2]); - } - - /// Perform a component-wise maximum with the other Coord. - void maxComponent(const Coord& other) - { - mVec[0] = std::max(mVec[0], other.mVec[0]); - mVec[1] = std::max(mVec[1], other.mVec[1]); - mVec[2] = std::max(mVec[2], other.mVec[2]); - } - - /// Return the component-wise minimum of the two Coords. - static inline Coord minComponent(const Coord& lhs, const Coord& rhs) - { - return Coord(std::min(lhs.x(), rhs.x()), - std::min(lhs.y(), rhs.y()), - std::min(lhs.z(), rhs.z())); - } - - /// Return the component-wise maximum of the two Coords. - static inline Coord maxComponent(const Coord& lhs, const Coord& rhs) - { - return Coord(std::max(lhs.x(), rhs.x()), - std::max(lhs.y(), rhs.y()), - std::max(lhs.z(), rhs.z())); - } - static inline bool lessThan(const Coord& a, const Coord& b) - { - return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]); - } - - /// @brief Return the index (0, 1 or 2) with the smallest value. - size_t minIndex() const { return MinIndex(mVec); } - - /// @brief Return the index (0, 1 or 2) with the largest value. - size_t maxIndex() const { return MaxIndex(mVec); } - - void read(std::istream& is) { is.read(reinterpret_cast(mVec), sizeof(mVec)); } - void write(std::ostream& os) const - { os.write(reinterpret_cast(mVec), sizeof(mVec)); } - -private: - //no-op for now - void dirty() { /*mHash.clear();*/ } - - Int32 mVec[3]; - //HashType mHash; -}; // class Coord - - -//////////////////////////////////////// - - -/// @brief Axis-aligned bounding box of signed integer coordinates -/// @note The range of the integer coordinates, [min, max], is inclusive. -/// Thus, a bounding box with min = max is not empty but rather encloses -/// a single coordinate. -class CoordBBox -{ -public: - typedef uint64_t Index64; - typedef Coord::ValueType ValueType; - - /// @brief The default constructor produces an empty bounding box. - CoordBBox(): mMin(Coord::max()), mMax(Coord::min()) {} - /// @brief Construct a bounding box with the given @a min and @a max bounds. - CoordBBox(const Coord& min, const Coord& max): mMin(min), mMax(max) {} - /// @brief Splitting constructor for use in TBB ranges - /// @note The other bounding box is assumed to be divisible. - CoordBBox(CoordBBox& other, const tbb::split&): mMin(other.mMin), mMax(other.mMax) - { - assert(this->is_divisible()); - const size_t n = this->maxExtent(); - mMax[n] = (mMin[n] + mMax[n]) >> 1; - other.mMin[n] = mMax[n] + 1; - } - - static CoordBBox createCube(const Coord& min, ValueType dim) - { - return CoordBBox(min, min.offsetBy(dim - 1)); - } - - /// Return an "infinite" bounding box, as defined by the Coord value range. - static CoordBBox inf() { return CoordBBox(Coord::min(), Coord::max()); } - - const Coord& min() const { return mMin; } - const Coord& max() const { return mMax; } - - Coord& min() { return mMin; } - Coord& max() { return mMax; } - - void reset() { mMin = Coord::max(); mMax = Coord::min(); } - void reset(const Coord& min, const Coord& max) { mMin = min; mMax = max; } - void resetToCube(const Coord& min, ValueType dim) { mMin = min; mMax = min.offsetBy(dim - 1); } - - /// @note The start coordinate is inclusive. - Coord getStart() const { return mMin; } - /// @note The end coordinate is exclusive. - Coord getEnd() const { return mMax.offsetBy(1); } - - bool operator==(const CoordBBox& rhs) const { return mMin == rhs.mMin && mMax == rhs.mMax; } - bool operator!=(const CoordBBox& rhs) const { return !(*this == rhs); } - - bool empty() const { return (mMin[0] > mMax[0] || mMin[1] > mMax[1] || mMin[2] > mMax[2]); } - //@{ - /// Return @c true if this bounding box is nonempty - operator bool() const { return !this->empty(); } - bool hasVolume() const { return !this->empty(); } - //@} - - /// Return the floating-point position of the center of this bounding box. - Vec3d getCenter() const { return 0.5 * Vec3d((mMin + mMax).asPointer()); } - - /// @brief Return the dimensions of the coordinates spanned by this bounding box. - /// @note Since coordinates are inclusive, a bounding box with min = max - /// has dimensions of (1, 1, 1). - Coord dim() const { return mMax.offsetBy(1) - mMin; } - /// @todo deprecate - use dim instead - Coord extents() const { return this->dim(); } - /// @brief Return the integer volume of coordinates spanned by this bounding box. - /// @note Since coordinates are inclusive, a bounding box with min = max has volume one. - Index64 volume() const - { - const Coord d = this->dim(); - return Index64(d[0]) * Index64(d[1]) * Index64(d[2]); - } - /// Return @c true if this bounding box can be subdivided [mainly for use by TBB]. - bool is_divisible() const { return mMin[0]dim().minIndex(); } - - /// @brief Return the index (0, 1 or 2) of the longest axis. - size_t maxExtent() const { return this->dim().maxIndex(); } - - /// Return @c true if point (x, y, z) is inside this bounding box. - bool isInside(const Coord& xyz) const - { - return !(Coord::lessThan(xyz,mMin) || Coord::lessThan(mMax,xyz)); - } - - /// Return @c true if the given bounding box is inside this bounding box. - bool isInside(const CoordBBox& b) const - { - return !(Coord::lessThan(b.mMin,mMin) || Coord::lessThan(mMax,b.mMax)); - } - - /// Return @c true if the given bounding box overlaps with this bounding box. - bool hasOverlap(const CoordBBox& b) const - { - return !(Coord::lessThan(mMax,b.mMin) || Coord::lessThan(b.mMax,mMin)); - } - - /// Pad this bounding box with the specified padding. - void expand(ValueType padding) - { - mMin.offset(-padding); - mMax.offset( padding); - } - /// Expand this bounding box to enclose point (x, y, z). - void expand(const Coord& xyz) - { - mMin.minComponent(xyz); - mMax.maxComponent(xyz); - } - /// Union this bounding box with the given bounding box. - void expand(const CoordBBox& bbox) - { - mMin.minComponent(bbox.min()); - mMax.maxComponent(bbox.max()); - } - /// Intersect this bounding box with the given bounding box. - void intersect(const CoordBBox& bbox) - { - mMin.maxComponent(bbox.min()); - mMax.minComponent(bbox.max()); - } - /// @brief Union this bounding box with the cubical bounding box - /// of the given size and with the given minimum coordinates. - void expand(const Coord& min, Coord::ValueType dim) - { - mMin.minComponent(min); - mMax.maxComponent(min.offsetBy(dim-1)); - } - /// Translate this bounding box by @f$(t_x, t_y, t_z)@f$. - void translate(const Coord& t) { mMin += t; mMax += t; } - - /// Unserialize this bounding box from the given stream. - void read(std::istream& is) { mMin.read(is); mMax.read(is); } - /// Serialize this bounding box to the given stream. - void write(std::ostream& os) const { mMin.write(os); mMax.write(os); } - -private: - Coord mMin, mMax; -}; // class CoordBBox - - -//////////////////////////////////////// - - -inline std::ostream& operator<<(std::ostream& os, const Coord& xyz) -{ - os << xyz.asVec3i(); return os; -} - - -//@{ -/// Allow a Coord to be added to or subtracted from a Vec3. -template -inline Vec3::type> -operator+(const Vec3& v0, const Coord& v1) -{ - Vec3::type> result(v0); - result[0] += v1[0]; - result[1] += v1[1]; - result[2] += v1[2]; - return result; -} - -template -inline Vec3::type> -operator+(const Coord& v1, const Vec3& v0) -{ - Vec3::type> result(v0); - result[0] += v1[0]; - result[1] += v1[1]; - result[2] += v1[2]; - return result; -} -//@} - - -//@{ -/// Allow a Coord to be subtracted from a Vec3. -template -inline Vec3::type> -operator-(const Vec3& v0, const Coord& v1) -{ - Vec3::type> result(v0); - result[0] -= v1[0]; - result[1] -= v1[1]; - result[2] -= v1[2]; - return result; -} - -template -inline Vec3::type> -operator-(const Coord& v1, const Vec3& v0) -{ - Vec3::type> result(v0); - result[0] -= v1[0]; - result[1] -= v1[1]; - result[2] -= v1[2]; - return -result; -} -//@} - -inline std::ostream& -operator<<(std::ostream& os, const CoordBBox& b) -{ - os << b.min() << " -> " << b.max(); - return os; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_COORD_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/DDA.h b/openvdb_3_0_0_library/math/DDA.h deleted file mode 100755 index adfb032..0000000 --- a/openvdb_3_0_0_library/math/DDA.h +++ /dev/null @@ -1,371 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file DDA.h -/// -/// @author Ken Museth -/// -/// @brief Digital Differential Analyzers specialized for VDB. - -#ifndef OPENVDB_MATH_DDA_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_DDA_HAS_BEEN_INCLUDED - -#include "Coord.h" -#include "Math.h" -#include "Vec3.h" -#include // for std::ostream -#include // for std::numeric_limits::max() - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @brief A Digital Differential Analyzer specialized for OpenVDB grids -/// @note Conceptually similar to Bresenham's line algorithm applied -/// to a 3D Ray intersecting OpenVDB nodes or voxels. Log2Dim = 0 -/// corresponds to a voxel and Log2Dim a tree node of size 2^Log2Dim. -/// -/// @note The Ray template class is expected to have the following -/// methods: test(time), t0(), t1(), invDir(), and operator()(time). -/// See the example Ray class above for their definition. -template -class DDA -{ -public: - typedef typename RayT::RealType RealType; - typedef RealType RealT; - typedef typename RayT::Vec3Type Vec3Type; - typedef Vec3Type Vec3T; - - /// @brief uninitialized constructor - DDA() {} - - DDA(const RayT& ray) { this->init(ray); } - - DDA(const RayT& ray, RealT startTime) { this->init(ray, startTime); } - - DDA(const RayT& ray, RealT startTime, RealT maxTime) { this->init(ray, startTime, maxTime); } - - inline void init(const RayT& ray, RealT startTime, RealT maxTime) - { - assert(startTime <= maxTime); - static const int DIM = 1 << Log2Dim; - mT0 = startTime; - mT1 = maxTime; - const Vec3T &pos = ray(mT0), &dir = ray.dir(), &inv = ray.invDir(); - mVoxel = Coord::floor(pos) & (~(DIM-1)); - for (int axis = 0; axis < 3; ++axis) { - if (math::isZero(dir[axis])) {//handles dir = +/- 0 - mStep[axis] = 0;//dummy value - mNext[axis] = std::numeric_limits::max();//i.e. disabled! - mDelta[axis] = std::numeric_limits::max();//dummy value - } else if (inv[axis] > 0) { - mStep[axis] = DIM; - mNext[axis] = mT0 + (mVoxel[axis] + DIM - pos[axis]) * inv[axis]; - mDelta[axis] = mStep[axis] * inv[axis]; - } else { - mStep[axis] = -DIM; - mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis]; - mDelta[axis] = mStep[axis] * inv[axis]; - } - } - } - - inline void init(const RayT& ray) { this->init(ray, ray.t0(), ray.t1()); } - - inline void init(const RayT& ray, RealT startTime) { this->init(ray, startTime, ray.t1()); } - - /// @brief Increment the voxel index to next intersected voxel or node - /// and returns true if the step in time does not exceed maxTime. - inline bool step() - { - const int stepAxis = static_cast(math::MinIndex(mNext)); - mT0 = mNext[stepAxis]; - mNext[stepAxis] += mDelta[stepAxis]; - mVoxel[stepAxis] += mStep[stepAxis]; - return mT0 <= mT1; - } - - /// @brief Return the index coordinates of the next node or voxel - /// intersected by the ray. If Log2Dim = 0 the return value is the - /// actual signed coordinate of the voxel, else it is the origin - /// of the corresponding VDB tree node or tile. - /// @note Incurs no computational overhead. - inline const Coord& voxel() const { return mVoxel; } - - /// @brief Return the time (parameterized along the Ray) of the - /// first hit of a tree node of size 2^Log2Dim. - /// @details This value is initialized to startTime or ray.t0() - /// depending on the constructor used. - /// @note Incurs no computational overhead. - inline RealType time() const { return mT0; } - - /// @brief Return the maximum time (parameterized along the Ray). - inline RealType maxTime() const { return mT1; } - - /// @brief Return the time (parameterized along the Ray) of the - /// second (i.e. next) hit of a tree node of size 2^Log2Dim. - /// @note Incurs a (small) computational overhead. - inline RealType next() const { return math::Min(mT1, mNext[0], mNext[1], mNext[2]); } - - /// @brief Print information about this DDA for debugging. - /// @param os a stream to which to write textual information. - void print(std::ostream& os = std::cout) const - { - os << "Dim=" << (1< -#include "Math.h" -#include "Coord.h" -#include "Vec3.h" - -#include -#include - -#ifdef DWA_OPENVDB -#include -#endif - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - - -/// @brief Different discrete schemes used in the first derivatives. -// Add new items to the *end* of this list, and update NUM_DS_SCHEMES. -enum DScheme { - UNKNOWN_DS = -1, - CD_2NDT = 0, // center difference, 2nd order, but the result must be divided by 2 - CD_2ND, // center difference, 2nd order - CD_4TH, // center difference, 4th order - CD_6TH, // center difference, 6th order - FD_1ST, // forward difference, 1st order - FD_2ND, // forward difference, 2nd order - FD_3RD, // forward difference, 3rd order - BD_1ST, // backward difference, 1st order - BD_2ND, // backward difference, 2nd order - BD_3RD, // backward difference, 3rd order - FD_WENO5, // forward difference, weno5 - BD_WENO5, // backward difference, weno5 - FD_HJWENO5, // forward differene, HJ-weno5 - BD_HJWENO5 // backward difference, HJ-weno5 -}; - -enum { NUM_DS_SCHEMES = BD_HJWENO5 + 1 }; - - -inline std::string -dsSchemeToString(DScheme dss) -{ - std::string ret; - switch (dss) { - case UNKNOWN_DS: ret = "unknown_ds"; break; - case CD_2NDT: ret = "cd_2ndt"; break; - case CD_2ND: ret = "cd_2nd"; break; - case CD_4TH: ret = "cd_4th"; break; - case CD_6TH: ret = "cd_6th"; break; - case FD_1ST: ret = "fd_1st"; break; - case FD_2ND: ret = "fd_2nd"; break; - case FD_3RD: ret = "fd_3rd"; break; - case BD_1ST: ret = "bd_1st"; break; - case BD_2ND: ret = "bd_2nd"; break; - case BD_3RD: ret = "bd_3rd"; break; - case FD_WENO5: ret = "fd_weno5"; break; - case BD_WENO5: ret = "bd_weno5"; break; - case FD_HJWENO5: ret = "fd_hjweno5"; break; - case BD_HJWENO5: ret = "bd_hjweno5"; break; - } - return ret; -} - -inline DScheme -stringToDScheme(const std::string& s) -{ - DScheme ret = UNKNOWN_DS; - - std::string str = s; - boost::trim(str); - boost::to_lower(str); - - if (str == dsSchemeToString(CD_2NDT)) { - ret = CD_2NDT; - } else if (str == dsSchemeToString(CD_2ND)) { - ret = CD_2ND; - } else if (str == dsSchemeToString(CD_4TH)) { - ret = CD_4TH; - } else if (str == dsSchemeToString(CD_6TH)) { - ret = CD_6TH; - } else if (str == dsSchemeToString(FD_1ST)) { - ret = FD_1ST; - } else if (str == dsSchemeToString(FD_2ND)) { - ret = FD_2ND; - } else if (str == dsSchemeToString(FD_3RD)) { - ret = FD_3RD; - } else if (str == dsSchemeToString(BD_1ST)) { - ret = BD_1ST; - } else if (str == dsSchemeToString(BD_2ND)) { - ret = BD_2ND; - } else if (str == dsSchemeToString(BD_3RD)) { - ret = BD_3RD; - } else if (str == dsSchemeToString(FD_WENO5)) { - ret = FD_WENO5; - } else if (str == dsSchemeToString(BD_WENO5)) { - ret = BD_WENO5; - } else if (str == dsSchemeToString(FD_HJWENO5)) { - ret = FD_HJWENO5; - } else if (str == dsSchemeToString(BD_HJWENO5)) { - ret = BD_HJWENO5; - } - - return ret; -} - -inline std::string -dsSchemeToMenuName(DScheme dss) -{ - std::string ret; - switch (dss) { - case UNKNOWN_DS: ret = "Unknown DS scheme"; break; - case CD_2NDT: ret = "Twice 2nd-order center difference"; break; - case CD_2ND: ret = "2nd-order center difference"; break; - case CD_4TH: ret = "4th-order center difference"; break; - case CD_6TH: ret = "6th-order center difference"; break; - case FD_1ST: ret = "1st-order forward difference"; break; - case FD_2ND: ret = "2nd-order forward difference"; break; - case FD_3RD: ret = "3rd-order forward difference"; break; - case BD_1ST: ret = "1st-order backward difference"; break; - case BD_2ND: ret = "2nd-order backward difference"; break; - case BD_3RD: ret = "3rd-order backward difference"; break; - case FD_WENO5: ret = "5th-order WENO forward difference"; break; - case BD_WENO5: ret = "5th-order WENO backward difference"; break; - case FD_HJWENO5: ret = "5th-order HJ-WENO forward difference"; break; - case BD_HJWENO5: ret = "5th-order HJ-WENO backward difference"; break; - } - return ret; -} - - - -//////////////////////////////////////// - - -/// @brief Different discrete schemes used in the second derivatives. -// Add new items to the *end* of this list, and update NUM_DD_SCHEMES. -enum DDScheme { - UNKNOWN_DD = -1, - CD_SECOND = 0, // center difference, 2nd order - CD_FOURTH, // center difference, 4th order - CD_SIXTH // center difference, 6th order -}; - -enum { NUM_DD_SCHEMES = CD_SIXTH + 1 }; - - -//////////////////////////////////////// - - -/// @brief Biased Gradients are limited to non-centered differences -// Add new items to the *end* of this list, and update NUM_BIAS_SCHEMES. -enum BiasedGradientScheme { - UNKNOWN_BIAS = -1, - FIRST_BIAS = 0, // uses FD_1ST & BD_1ST - SECOND_BIAS, // uses FD_2ND & BD_2ND - THIRD_BIAS, // uses FD_3RD & BD_3RD - WENO5_BIAS, // uses WENO5 - HJWENO5_BIAS // uses HJWENO5 -}; - -enum { NUM_BIAS_SCHEMES = HJWENO5_BIAS + 1 }; - -inline std::string -biasedGradientSchemeToString(BiasedGradientScheme bgs) -{ - std::string ret; - switch (bgs) { - case UNKNOWN_BIAS: ret = "unknown_bias"; break; - case FIRST_BIAS: ret = "first_bias"; break; - case SECOND_BIAS: ret = "second_bias"; break; - case THIRD_BIAS: ret = "third_bias"; break; - case WENO5_BIAS: ret = "weno5_bias"; break; - case HJWENO5_BIAS: ret = "hjweno5_bias"; break; - } - return ret; -} - -inline BiasedGradientScheme -stringToBiasedGradientScheme(const std::string& s) -{ - BiasedGradientScheme ret = UNKNOWN_BIAS; - - std::string str = s; - boost::trim(str); - boost::to_lower(str); - - if (str == biasedGradientSchemeToString(FIRST_BIAS)) { - ret = FIRST_BIAS; - } else if (str == biasedGradientSchemeToString(SECOND_BIAS)) { - ret = SECOND_BIAS; - } else if (str == biasedGradientSchemeToString(THIRD_BIAS)) { - ret = THIRD_BIAS; - } else if (str == biasedGradientSchemeToString(WENO5_BIAS)) { - ret = WENO5_BIAS; - } else if (str == biasedGradientSchemeToString(HJWENO5_BIAS)) { - ret = HJWENO5_BIAS; - } - return ret; -} - -inline std::string -biasedGradientSchemeToMenuName(BiasedGradientScheme bgs) -{ - std::string ret; - switch (bgs) { - case UNKNOWN_BIAS: ret = "Unknown biased gradient"; break; - case FIRST_BIAS: ret = "1st-order biased gradient"; break; - case SECOND_BIAS: ret = "2nd-order biased gradient"; break; - case THIRD_BIAS: ret = "3rd-order biased gradient"; break; - case WENO5_BIAS: ret = "5th-order WENO biased gradient"; break; - case HJWENO5_BIAS: ret = "5th-order HJ-WENO biased gradient"; break; - } - return ret; -} - -//////////////////////////////////////// - - -/// @brief Temporal integration schemes -// Add new items to the *end* of this list, and update NUM_TEMPORAL_SCHEMES. -enum TemporalIntegrationScheme { - UNKNOWN_TIS = -1, - TVD_RK1,//same as explicit Euler integration - TVD_RK2, - TVD_RK3 -}; - -enum { NUM_TEMPORAL_SCHEMES = TVD_RK3 + 1 }; - -inline std::string -temporalIntegrationSchemeToString(TemporalIntegrationScheme tis) -{ - std::string ret; - switch (tis) { - case UNKNOWN_TIS: ret = "unknown_tis"; break; - case TVD_RK1: ret = "tvd_rk1"; break; - case TVD_RK2: ret = "tvd_rk2"; break; - case TVD_RK3: ret = "tvd_rk3"; break; - } - return ret; -} - -inline TemporalIntegrationScheme -stringToTemporalIntegrationScheme(const std::string& s) -{ - TemporalIntegrationScheme ret = UNKNOWN_TIS; - - std::string str = s; - boost::trim(str); - boost::to_lower(str); - - if (str == temporalIntegrationSchemeToString(TVD_RK1)) { - ret = TVD_RK1; - } else if (str == temporalIntegrationSchemeToString(TVD_RK2)) { - ret = TVD_RK2; - } else if (str == temporalIntegrationSchemeToString(TVD_RK3)) { - ret = TVD_RK3; - } - - return ret; -} - -inline std::string -temporalIntegrationSchemeToMenuName(TemporalIntegrationScheme tis) -{ - std::string ret; - switch (tis) { - case UNKNOWN_TIS: ret = "Unknown temporal integration"; break; - case TVD_RK1: ret = "Forward Euler"; break; - case TVD_RK2: ret = "2nd-order Runge-Kutta"; break; - case TVD_RK3: ret = "3rd-order Runge-Kutta"; break; - } - return ret; -} - - -//@} - - -/// @brief Implementation of nominally fifth-order finite-difference WENO -/// @details This function returns the numerical flux. See "High Order Finite Difference and -/// Finite Volume WENO Schemes and Discontinuous Galerkin Methods for CFD" - Chi-Wang Shu -/// ICASE Report No 2001-11 (page 6). Also see ICASE No 97-65 for a more complete reference -/// (Shu, 1997). -/// Given v1 = f(x-2dx), v2 = f(x-dx), v3 = f(x), v4 = f(x+dx) and v5 = f(x+2dx), -/// return an interpolated value f(x+dx/2) with the special property that -/// ( f(x+dx/2) - f(x-dx/2) ) / dx = df/dx (x) + error, -/// where the error is fifth-order in smooth regions: O(dx) <= error <=O(dx^5) -template -inline ValueType -WENO5(const ValueType& v1, const ValueType& v2, const ValueType& v3, - const ValueType& v4, const ValueType& v5, float scale2 = 0.01f) -{ - const double C = 13.0 / 12.0; - // WENO is formulated for non-dimensional equations, here the optional scale2 - // is a reference value (squared) for the function being interpolated. For - // example if 'v' is of order 1000, then scale2 = 10^6 is ok. But in practice - // leave scale2 = 1. - const double eps = 1e-6 * scale2; - // {\tilde \omega_k} = \gamma_k / ( \beta_k + \epsilon)^2 in Shu's ICASE report) - const double A1=0.1/math::Pow2(C*math::Pow2(v1-2*v2+v3)+0.25*math::Pow2(v1-4*v2+3.0*v3)+eps), - A2=0.6/math::Pow2(C*math::Pow2(v2-2*v3+v4)+0.25*math::Pow2(v2-v4)+eps), - A3=0.3/math::Pow2(C*math::Pow2(v3-2*v4+v5)+0.25*math::Pow2(3.0*v3-4*v4+v5)+eps); - - return static_cast(static_cast( - A1*(2.0*v1 - 7.0*v2 + 11.0*v3) + - A2*(5.0*v3 - v2 + 2.0*v4) + - A3*(2.0*v3 + 5.0*v4 - v5))/(6.0*(A1+A2+A3))); -} - - -template -inline Real GudonovsNormSqrd(bool isOutside, - Real dP_xm, Real dP_xp, - Real dP_ym, Real dP_yp, - Real dP_zm, Real dP_zp) -{ - using math::Max; - using math::Min; - using math::Pow2; - - const Real zero(0); - Real dPLen2; - if (isOutside) { // outside - dPLen2 = Max(Pow2(Max(dP_xm, zero)), Pow2(Min(dP_xp,zero))); // (dP/dx)2 - dPLen2 += Max(Pow2(Max(dP_ym, zero)), Pow2(Min(dP_yp,zero))); // (dP/dy)2 - dPLen2 += Max(Pow2(Max(dP_zm, zero)), Pow2(Min(dP_zp,zero))); // (dP/dz)2 - } else { // inside - dPLen2 = Max(Pow2(Min(dP_xm, zero)), Pow2(Max(dP_xp,zero))); // (dP/dx)2 - dPLen2 += Max(Pow2(Min(dP_ym, zero)), Pow2(Max(dP_yp,zero))); // (dP/dy)2 - dPLen2 += Max(Pow2(Min(dP_zm, zero)), Pow2(Max(dP_zp,zero))); // (dP/dz)2 - } - return dPLen2; // |\nabla\phi|^2 -} - - -template -inline Real -GudonovsNormSqrd(bool isOutside, const Vec3& gradient_m, const Vec3& gradient_p) -{ - return GudonovsNormSqrd(isOutside, - gradient_m[0], gradient_p[0], - gradient_m[1], gradient_p[1], - gradient_m[2], gradient_p[2]); -} - - -#ifdef DWA_OPENVDB -inline simd::Float4 simdMin(const simd::Float4& a, const simd::Float4& b) { - return simd::Float4(_mm_min_ps(a.base(), b.base())); -} -inline simd::Float4 simdMax(const simd::Float4& a, const simd::Float4& b) { - return simd::Float4(_mm_max_ps(a.base(), b.base())); -} - -inline float simdSum(const simd::Float4& v); - -inline simd::Float4 Pow2(const simd::Float4& v) { return v * v; } - -template<> -inline simd::Float4 -WENO5(const simd::Float4& v1, const simd::Float4& v2, const simd::Float4& v3, - const simd::Float4& v4, const simd::Float4& v5, float scale2) -{ - using math::Pow2; - typedef simd::Float4 F4; - const F4 - C(13.f / 12.f), - eps(1.0e-6f * scale2), - two(2.0), three(3.0), four(4.0), five(5.0), fourth(0.25), - A1 = F4(0.1f) / Pow2(C*Pow2(v1-two*v2+v3) + fourth*Pow2(v1-four*v2+three*v3) + eps), - A2 = F4(0.6f) / Pow2(C*Pow2(v2-two*v3+v4) + fourth*Pow2(v2-v4) + eps), - A3 = F4(0.3f) / Pow2(C*Pow2(v3-two*v4+v5) + fourth*Pow2(three*v3-four*v4+v5) + eps); - return (A1 * (two * v1 - F4(7.0) * v2 + F4(11.0) * v3) + - A2 * (five * v3 - v2 + two * v4) + - A3 * (two * v3 + five * v4 - v5)) / (F4(6.0) * (A1 + A2 + A3)); -} - - -inline float -simdSum(const simd::Float4& v) -{ - // temp = { v3+v3, v2+v2, v1+v3, v0+v2 } - __m128 temp = _mm_add_ps(v.base(), _mm_movehl_ps(v.base(), v.base())); - // temp = { v3+v3, v2+v2, v1+v3, (v0+v2)+(v1+v3) } - temp = _mm_add_ss(temp, _mm_shuffle_ps(temp, temp, 1)); - return _mm_cvtss_f32(temp); -} - -inline float -GudonovsNormSqrd(bool isOutside, const simd::Float4& dP_m, const simd::Float4& dP_p) -{ - const simd::Float4 zero(0.0); - simd::Float4 v = isOutside - ? simdMax(math::Pow2(simdMax(dP_m, zero)), math::Pow2(simdMin(dP_p, zero))) - : simdMax(math::Pow2(simdMin(dP_m, zero)), math::Pow2(simdMax(dP_p, zero))); - return simdSum(v);//should be v[0]+v[1]+v[2] -} -#endif - -template -struct D1 -{ - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk); - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk); - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk); - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S); - - template - static typename Stencil::ValueType inY(const Stencil& S); - - template - static typename Stencil::ValueType inZ(const Stencil& S); -}; - -template<> -struct D1 -{ - // the difference opperator - template - static ValueType difference(const ValueType& xp1, const ValueType& xm1) { - return xp1 - xm1; - } - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(1, 0, 0)), - grid.getValue(ijk.offsetBy(-1, 0, 0))); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0, 1, 0)), - grid.getValue(ijk.offsetBy( 0, -1, 0))); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0, 0, 1)), - grid.getValue(ijk.offsetBy( 0, 0, -1))); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue< 1, 0, 0>(), S.template getValue<-1, 0, 0>()); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 1, 0>(), S.template getValue< 0,-1, 0>()); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 1>(), S.template getValue< 0, 0,-1>()); - } -}; - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp1, const ValueType& xm1) { - return (xp1 - xm1)*ValueType(0.5); - } - - - // random access - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(1, 0, 0)), - grid.getValue(ijk.offsetBy(-1, 0, 0))); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0, 1, 0)), - grid.getValue(ijk.offsetBy( 0, -1, 0))); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0, 0, 1)), - grid.getValue(ijk.offsetBy( 0, 0, -1))); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue< 1, 0, 0>(), S.template getValue<-1, 0, 0>()); - } - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference(S.template getValue< 0, 1, 0>(), S.template getValue< 0,-1, 0>()); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference(S.template getValue< 0, 0, 1>(), S.template getValue< 0, 0,-1>()); - } - -}; - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference( const ValueType& xp2, const ValueType& xp1, - const ValueType& xm1, const ValueType& xm2 ) { - return ValueType(2./3.)*(xp1 - xm1) + ValueType(1./12.)*(xm2 - xp2) ; - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 2,0,0)), grid.getValue(ijk.offsetBy( 1,0,0)), - grid.getValue(ijk.offsetBy(-1,0,0)), grid.getValue(ijk.offsetBy(-2,0,0)) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - - return difference( - grid.getValue(ijk.offsetBy( 0, 2, 0)), grid.getValue(ijk.offsetBy( 0, 1, 0)), - grid.getValue(ijk.offsetBy( 0,-1, 0)), grid.getValue(ijk.offsetBy( 0,-2, 0)) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - - return difference( - grid.getValue(ijk.offsetBy( 0, 0, 2)), grid.getValue(ijk.offsetBy( 0, 0, 1)), - grid.getValue(ijk.offsetBy( 0, 0,-1)), grid.getValue(ijk.offsetBy( 0, 0,-2)) ); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue<-2, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0,-2, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0,-2>() ); - } -}; - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference( const ValueType& xp3, const ValueType& xp2, const ValueType& xp1, - const ValueType& xm1, const ValueType& xm2, const ValueType& xm3 ) - { - return ValueType(3./4.)*(xp1 - xm1) - ValueType(0.15)*(xp2 - xm2) - + ValueType(1./60.)*(xp3-xm3); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 3,0,0)), grid.getValue(ijk.offsetBy( 2,0,0)), - grid.getValue(ijk.offsetBy( 1,0,0)), grid.getValue(ijk.offsetBy(-1,0,0)), - grid.getValue(ijk.offsetBy(-2,0,0)), grid.getValue(ijk.offsetBy(-3,0,0))); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 0, 3, 0)), grid.getValue(ijk.offsetBy( 0, 2, 0)), - grid.getValue(ijk.offsetBy( 0, 1, 0)), grid.getValue(ijk.offsetBy( 0,-1, 0)), - grid.getValue(ijk.offsetBy( 0,-2, 0)), grid.getValue(ijk.offsetBy( 0,-3, 0))); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 0, 0, 3)), grid.getValue(ijk.offsetBy( 0, 0, 2)), - grid.getValue(ijk.offsetBy( 0, 0, 1)), grid.getValue(ijk.offsetBy( 0, 0,-1)), - grid.getValue(ijk.offsetBy( 0, 0,-2)), grid.getValue(ijk.offsetBy( 0, 0,-3))); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue< 3, 0, 0>(), - S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue<-2, 0, 0>(), - S.template getValue<-3, 0, 0>()); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - - return difference( S.template getValue< 0, 3, 0>(), - S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0,-2, 0>(), - S.template getValue< 0,-3, 0>()); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - - return difference( S.template getValue< 0, 0, 3>(), - S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0,-2>(), - S.template getValue< 0, 0,-3>()); - } -}; - - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp1, const ValueType& xp0) { - return xp1 - xp0; - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(1, 0, 0)), grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(0, 1, 0)), grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(0, 0, 1)), grid.getValue(ijk)); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue< 1, 0, 0>(), S.template getValue< 0, 0, 0>()); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference(S.template getValue< 0, 1, 0>(), S.template getValue< 0, 0, 0>()); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference(S.template getValue< 0, 0, 1>(), S.template getValue< 0, 0, 0>()); - } -}; - - -template<> -struct D1 -{ - // the difference opperator - template - static ValueType difference(const ValueType& xp2, const ValueType& xp1, const ValueType& xp0) - { - return ValueType(2)*xp1 -(ValueType(0.5)*xp2 + ValueType(3./2.)*xp0); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(2,0,0)), - grid.getValue(ijk.offsetBy(1,0,0)), - grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0,2,0)), - grid.getValue(ijk.offsetBy(0,1,0)), - grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0,0,2)), - grid.getValue(ijk.offsetBy(0,0,1)), - grid.getValue(ijk)); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0, 0>() ); - } - -}; - - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp3, const ValueType& xp2, - const ValueType& xp1, const ValueType& xp0) - { - return ValueType(1./3.)*xp3 - ValueType(1.5)*xp2 - + ValueType(3.)*xp1 - ValueType(11./6.)*xp0; - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(3,0,0)), - grid.getValue(ijk.offsetBy(2,0,0)), - grid.getValue(ijk.offsetBy(1,0,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(0,3,0)), - grid.getValue(ijk.offsetBy(0,2,0)), - grid.getValue(ijk.offsetBy(0,1,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(0,0,3)), - grid.getValue(ijk.offsetBy(0,0,2)), - grid.getValue(ijk.offsetBy(0,0,1)), - grid.getValue(ijk) ); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue< 3, 0, 0>(), - S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference(S.template getValue< 0, 3, 0>(), - S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 3>(), - S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0, 0>() ); - } -}; - - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xm1, const ValueType& xm0) { - return -D1::difference(xm1, xm0); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(-1,0,0)), grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(0,-1,0)), grid.getValue(ijk)); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference(grid.getValue(ijk.offsetBy(0, 0,-1)), grid.getValue(ijk)); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue<-1, 0, 0>(), S.template getValue< 0, 0, 0>()); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference(S.template getValue< 0,-1, 0>(), S.template getValue< 0, 0, 0>()); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference(S.template getValue< 0, 0,-1>(), S.template getValue< 0, 0, 0>()); - } -}; - - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xm2, const ValueType& xm1, const ValueType& xm0) - { - return -D1::difference(xm2, xm1, xm0); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(-2,0,0)), - grid.getValue(ijk.offsetBy(-1,0,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(0,-2,0)), - grid.getValue(ijk.offsetBy(0,-1,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(0,0,-2)), - grid.getValue(ijk.offsetBy(0,0,-1)), - grid.getValue(ijk) ); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue<-2, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0,-2, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0,-2>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0, 0>() ); - } -}; - - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xm3, const ValueType& xm2, - const ValueType& xm1, const ValueType& xm0) - { - return -D1::difference(xm3, xm2, xm1, xm0); - } - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy(-3,0,0)), - grid.getValue(ijk.offsetBy(-2,0,0)), - grid.getValue(ijk.offsetBy(-1,0,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy( 0,-3,0)), - grid.getValue(ijk.offsetBy( 0,-2,0)), - grid.getValue(ijk.offsetBy( 0,-1,0)), - grid.getValue(ijk) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy( 0, 0,-3)), - grid.getValue(ijk.offsetBy( 0, 0,-2)), - grid.getValue(ijk.offsetBy( 0, 0,-1)), - grid.getValue(ijk) ); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue<-3, 0, 0>(), - S.template getValue<-2, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0,-3, 0>(), - S.template getValue< 0,-2, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0, 0, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0,-3>(), - S.template getValue< 0, 0,-2>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0, 0>() ); - } - -}; - -template<> -struct D1 -{ - // the difference operator - template - static ValueType difference(const ValueType& xp3, const ValueType& xp2, - const ValueType& xp1, const ValueType& xp0, - const ValueType& xm1, const ValueType& xm2) { - return WENO5(xp3, xp2, xp1, xp0, xm1) - - WENO5(xp2, xp1, xp0, xm1, xm2); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(3,0,0)); - V[1] = grid.getValue(ijk.offsetBy(2,0,0)); - V[2] = grid.getValue(ijk.offsetBy(1,0,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(-1,0,0)); - V[5] = grid.getValue(ijk.offsetBy(-2,0,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,3,0)); - V[1] = grid.getValue(ijk.offsetBy(0,2,0)); - V[2] = grid.getValue(ijk.offsetBy(0,1,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,-1,0)); - V[5] = grid.getValue(ijk.offsetBy(0,-2,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,0,3)); - V[1] = grid.getValue(ijk.offsetBy(0,0,2)); - V[2] = grid.getValue(ijk.offsetBy(0,0,1)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,0,-1)); - V[5] = grid.getValue(ijk.offsetBy(0,0,-2)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - - return static_cast(difference( - S.template getValue< 3, 0, 0>(), - S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue<-2, 0, 0>() )); - - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return static_cast(difference( - S.template getValue< 0, 3, 0>(), - S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0,-2, 0>() )); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return static_cast(difference( - S.template getValue< 0, 0, 3>(), - S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0,-2>() )); - } -}; - -template<> -struct D1 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp3, const ValueType& xp2, - const ValueType& xp1, const ValueType& xp0, - const ValueType& xm1, const ValueType& xm2) { - return WENO5(xp3 - xp2, xp2 - xp1, xp1 - xp0, xp0-xm1, xm1-xm2); - } - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(3,0,0)); - V[1] = grid.getValue(ijk.offsetBy(2,0,0)); - V[2] = grid.getValue(ijk.offsetBy(1,0,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(-1,0,0)); - V[5] = grid.getValue(ijk.offsetBy(-2,0,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,3,0)); - V[1] = grid.getValue(ijk.offsetBy(0,2,0)); - V[2] = grid.getValue(ijk.offsetBy(0,1,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,-1,0)); - V[5] = grid.getValue(ijk.offsetBy(0,-2,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,0,3)); - V[1] = grid.getValue(ijk.offsetBy(0,0,2)); - V[2] = grid.getValue(ijk.offsetBy(0,0,1)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,0,-1)); - V[5] = grid.getValue(ijk.offsetBy(0,0,-2)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - - return difference( S.template getValue< 3, 0, 0>(), - S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue<-1, 0, 0>(), - S.template getValue<-2, 0, 0>() ); - - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 3, 0>(), - S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0,-1, 0>(), - S.template getValue< 0,-2, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - - return difference( S.template getValue< 0, 0, 3>(), - S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0, 0,-1>(), - S.template getValue< 0, 0,-2>() ); - } - -}; - -template<> -struct D1 -{ - - template - static ValueType difference(const ValueType& xm3, const ValueType& xm2, const ValueType& xm1, - const ValueType& xm0, const ValueType& xp1, const ValueType& xp2) - { - return -D1::difference(xm3, xm2, xm1, xm0, xp1, xp2); - } - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(-3,0,0)); - V[1] = grid.getValue(ijk.offsetBy(-2,0,0)); - V[2] = grid.getValue(ijk.offsetBy(-1,0,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(1,0,0)); - V[5] = grid.getValue(ijk.offsetBy(2,0,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,-3,0)); - V[1] = grid.getValue(ijk.offsetBy(0,-2,0)); - V[2] = grid.getValue(ijk.offsetBy(0,-1,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,1,0)); - V[5] = grid.getValue(ijk.offsetBy(0,2,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,0,-3)); - V[1] = grid.getValue(ijk.offsetBy(0,0,-2)); - V[2] = grid.getValue(ijk.offsetBy(0,0,-1)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,0,1)); - V[5] = grid.getValue(ijk.offsetBy(0,0,2)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue<-3, 0, 0>(); - V[1] = S.template getValue<-2, 0, 0>(); - V[2] = S.template getValue<-1, 0, 0>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 1, 0, 0>(); - V[5] = S.template getValue< 2, 0, 0>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue< 0,-3, 0>(); - V[1] = S.template getValue< 0,-2, 0>(); - V[2] = S.template getValue< 0,-1, 0>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 0, 1, 0>(); - V[5] = S.template getValue< 0, 2, 0>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue< 0, 0,-3>(); - V[1] = S.template getValue< 0, 0,-2>(); - V[2] = S.template getValue< 0, 0,-1>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 0, 0, 1>(); - V[5] = S.template getValue< 0, 0, 2>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } -}; - - -template<> -struct D1 -{ - template - static ValueType difference(const ValueType& xm3, const ValueType& xm2, const ValueType& xm1, - const ValueType& xm0, const ValueType& xp1, const ValueType& xp2) - { - return -D1::difference(xm3, xm2, xm1, xm0, xp1, xp2); - } - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(-3,0,0)); - V[1] = grid.getValue(ijk.offsetBy(-2,0,0)); - V[2] = grid.getValue(ijk.offsetBy(-1,0,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(1,0,0)); - V[5] = grid.getValue(ijk.offsetBy(2,0,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,-3,0)); - V[1] = grid.getValue(ijk.offsetBy(0,-2,0)); - V[2] = grid.getValue(ijk.offsetBy(0,-1,0)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,1,0)); - V[5] = grid.getValue(ijk.offsetBy(0,2,0)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType V[6]; - V[0] = grid.getValue(ijk.offsetBy(0,0,-3)); - V[1] = grid.getValue(ijk.offsetBy(0,0,-2)); - V[2] = grid.getValue(ijk.offsetBy(0,0,-1)); - V[3] = grid.getValue(ijk); - V[4] = grid.getValue(ijk.offsetBy(0,0,1)); - V[5] = grid.getValue(ijk.offsetBy(0,0,2)); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue<-3, 0, 0>(); - V[1] = S.template getValue<-2, 0, 0>(); - V[2] = S.template getValue<-1, 0, 0>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 1, 0, 0>(); - V[5] = S.template getValue< 2, 0, 0>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue< 0,-3, 0>(); - V[1] = S.template getValue< 0,-2, 0>(); - V[2] = S.template getValue< 0,-1, 0>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 0, 1, 0>(); - V[5] = S.template getValue< 0, 2, 0>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - typedef typename Stencil::ValueType ValueType; - ValueType V[6]; - V[0] = S.template getValue< 0, 0,-3>(); - V[1] = S.template getValue< 0, 0,-2>(); - V[2] = S.template getValue< 0, 0,-1>(); - V[3] = S.template getValue< 0, 0, 0>(); - V[4] = S.template getValue< 0, 0, 1>(); - V[5] = S.template getValue< 0, 0, 2>(); - - return difference(V[0], V[1], V[2], V[3], V[4], V[5]); - } -}; - - -template -struct D1Vec -{ - // random access version - template - static typename Accessor::ValueType::value_type - inX(const Accessor& grid, const Coord& ijk, int n) - { - return D1::inX(grid, ijk)[n]; - } - - template - static typename Accessor::ValueType::value_type - inY(const Accessor& grid, const Coord& ijk, int n) - { - return D1::inY(grid, ijk)[n]; - } - template - static typename Accessor::ValueType::value_type - inZ(const Accessor& grid, const Coord& ijk, int n) - { - return D1::inZ(grid, ijk)[n]; - } - - - // stencil access version - template - static typename Stencil::ValueType::value_type inX(const Stencil& S, int n) - { - return D1::inX(S)[n]; - } - - template - static typename Stencil::ValueType::value_type inY(const Stencil& S, int n) - { - return D1::inY(S)[n]; - } - - template - static typename Stencil::ValueType::value_type inZ(const Stencil& S, int n) - { - return D1::inZ(S)[n]; - } -}; - - -template<> -struct D1Vec -{ - - // random access version - template - static typename Accessor::ValueType::value_type - inX(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy( 1, 0, 0))[n], - grid.getValue(ijk.offsetBy(-1, 0, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inY(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy(0, 1, 0))[n], - grid.getValue(ijk.offsetBy(0,-1, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inZ(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy(0, 0, 1))[n], - grid.getValue(ijk.offsetBy(0, 0,-1))[n] ); - } - - // stencil access version - template - static typename Stencil::ValueType::value_type inX(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 1, 0, 0>()[n], - S.template getValue<-1, 0, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inY(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 0, 1, 0>()[n], - S.template getValue< 0,-1, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inZ(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 0, 0, 1>()[n], - S.template getValue< 0, 0,-1>()[n] ); - } -}; - -template<> -struct D1Vec -{ - - // random access version - template - static typename Accessor::ValueType::value_type - inX(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy( 1, 0, 0))[n] , - grid.getValue(ijk.offsetBy(-1, 0, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inY(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy(0, 1, 0))[n] , - grid.getValue(ijk.offsetBy(0,-1, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inZ(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( grid.getValue(ijk.offsetBy(0, 0, 1))[n] , - grid.getValue(ijk.offsetBy(0, 0,-1))[n] ); - } - - - // stencil access version - template - static typename Stencil::ValueType::value_type inX(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 1, 0, 0>()[n], - S.template getValue<-1, 0, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inY(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 0, 1, 0>()[n], - S.template getValue< 0,-1, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inZ(const Stencil& S, int n) - { - return D1::difference( S.template getValue< 0, 0, 1>()[n], - S.template getValue< 0, 0,-1>()[n] ); - } -}; - - -template<> -struct D1Vec { - // typedef typename Accessor::ValueType::value_type value_type; - - - // random access version - template - static typename Accessor::ValueType::value_type - inX(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy(2, 0, 0))[n], grid.getValue(ijk.offsetBy( 1, 0, 0))[n], - grid.getValue(ijk.offsetBy(-1,0, 0))[n], grid.getValue(ijk.offsetBy(-2, 0, 0))[n]); - } - - template - static typename Accessor::ValueType::value_type - inY(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy( 0, 2, 0))[n], grid.getValue(ijk.offsetBy( 0, 1, 0))[n], - grid.getValue(ijk.offsetBy( 0,-1, 0))[n], grid.getValue(ijk.offsetBy( 0,-2, 0))[n]); - } - - template - static typename Accessor::ValueType::value_type - inZ(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy(0,0, 2))[n], grid.getValue(ijk.offsetBy( 0, 0, 1))[n], - grid.getValue(ijk.offsetBy(0,0,-1))[n], grid.getValue(ijk.offsetBy( 0, 0,-2))[n]); - } - - // stencil access version - template - static typename Stencil::ValueType::value_type inX(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 2, 0, 0>()[n], S.template getValue< 1, 0, 0>()[n], - S.template getValue<-1, 0, 0>()[n], S.template getValue<-2, 0, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inY(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 0, 2, 0>()[n], S.template getValue< 0, 1, 0>()[n], - S.template getValue< 0,-1, 0>()[n], S.template getValue< 0,-2, 0>()[n]); - } - - template - static typename Stencil::ValueType::value_type inZ(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 0, 0, 2>()[n], S.template getValue< 0, 0, 1>()[n], - S.template getValue< 0, 0,-1>()[n], S.template getValue< 0, 0,-2>()[n]); - } -}; - - -template<> -struct D1Vec -{ - //typedef typename Accessor::ValueType::value_type::value_type ValueType; - - // random access version - template - static typename Accessor::ValueType::value_type - inX(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy( 3, 0, 0))[n], grid.getValue(ijk.offsetBy( 2, 0, 0))[n], - grid.getValue(ijk.offsetBy( 1, 0, 0))[n], grid.getValue(ijk.offsetBy(-1, 0, 0))[n], - grid.getValue(ijk.offsetBy(-2, 0, 0))[n], grid.getValue(ijk.offsetBy(-3, 0, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inY(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy( 0, 3, 0))[n], grid.getValue(ijk.offsetBy( 0, 2, 0))[n], - grid.getValue(ijk.offsetBy( 0, 1, 0))[n], grid.getValue(ijk.offsetBy( 0,-1, 0))[n], - grid.getValue(ijk.offsetBy( 0,-2, 0))[n], grid.getValue(ijk.offsetBy( 0,-3, 0))[n] ); - } - - template - static typename Accessor::ValueType::value_type - inZ(const Accessor& grid, const Coord& ijk, int n) - { - return D1::difference( - grid.getValue(ijk.offsetBy( 0, 0, 3))[n], grid.getValue(ijk.offsetBy( 0, 0, 2))[n], - grid.getValue(ijk.offsetBy( 0, 0, 1))[n], grid.getValue(ijk.offsetBy( 0, 0,-1))[n], - grid.getValue(ijk.offsetBy( 0, 0,-2))[n], grid.getValue(ijk.offsetBy( 0, 0,-3))[n] ); - } - - - // stencil access version - template - static typename Stencil::ValueType::value_type inX(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 3, 0, 0>()[n], S.template getValue< 2, 0, 0>()[n], - S.template getValue< 1, 0, 0>()[n], S.template getValue<-1, 0, 0>()[n], - S.template getValue<-2, 0, 0>()[n], S.template getValue<-3, 0, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inY(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 0, 3, 0>()[n], S.template getValue< 0, 2, 0>()[n], - S.template getValue< 0, 1, 0>()[n], S.template getValue< 0,-1, 0>()[n], - S.template getValue< 0,-2, 0>()[n], S.template getValue< 0,-3, 0>()[n] ); - } - - template - static typename Stencil::ValueType::value_type inZ(const Stencil& S, int n) - { - return D1::difference( - S.template getValue< 0, 0, 3>()[n], S.template getValue< 0, 0, 2>()[n], - S.template getValue< 0, 0, 1>()[n], S.template getValue< 0, 0,-1>()[n], - S.template getValue< 0, 0,-2>()[n], S.template getValue< 0, 0,-3>()[n] ); - } -}; - -template -struct D2 -{ - - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk); - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk); - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk); - - // cross derivatives - template - static typename Accessor::ValueType inXandY(const Accessor& grid, const Coord& ijk); - - template - static typename Accessor::ValueType inXandZ(const Accessor& grid, const Coord& ijk); - - template - static typename Accessor::ValueType inYandZ(const Accessor& grid, const Coord& ijk); - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S); - template - static typename Stencil::ValueType inY(const Stencil& S); - template - static typename Stencil::ValueType inZ(const Stencil& S); - - // cross derivatives - template - static typename Stencil::ValueType inXandY(const Stencil& S); - - template - static typename Stencil::ValueType inXandZ(const Stencil& S); - - template - static typename Stencil::ValueType inYandZ(const Stencil& S); -}; - -template<> -struct D2 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp1, const ValueType& xp0, const ValueType& xm1) - { - return xp1 + xm1 - ValueType(2)*xp0; - } - - template - static ValueType crossdifference(const ValueType& xpyp, const ValueType& xpym, - const ValueType& xmyp, const ValueType& xmym) - { - return ValueType(0.25)*(xpyp + xmym - xpym - xmyp); - } - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy( 1,0,0)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy(-1,0,0)) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - - return difference( grid.getValue(ijk.offsetBy(0, 1,0)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy(0,-1,0)) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( grid.getValue(ijk.offsetBy( 0,0, 1)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy( 0,0,-1)) ); - } - - // cross derivatives - template - static typename Accessor::ValueType inXandY(const Accessor& grid, const Coord& ijk) - { - return crossdifference( - grid.getValue(ijk.offsetBy(1, 1,0)), grid.getValue(ijk.offsetBy( 1,-1,0)), - grid.getValue(ijk.offsetBy(-1,1,0)), grid.getValue(ijk.offsetBy(-1,-1,0))); - - } - - template - static typename Accessor::ValueType inXandZ(const Accessor& grid, const Coord& ijk) - { - return crossdifference( - grid.getValue(ijk.offsetBy(1,0, 1)), grid.getValue(ijk.offsetBy(1, 0,-1)), - grid.getValue(ijk.offsetBy(-1,0,1)), grid.getValue(ijk.offsetBy(-1,0,-1)) ); - } - - template - static typename Accessor::ValueType inYandZ(const Accessor& grid, const Coord& ijk) - { - return crossdifference( - grid.getValue(ijk.offsetBy(0, 1,1)), grid.getValue(ijk.offsetBy(0, 1,-1)), - grid.getValue(ijk.offsetBy(0,-1,1)), grid.getValue(ijk.offsetBy(0,-1,-1)) ); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue< 1, 0, 0>(), S.template getValue< 0, 0, 0>(), - S.template getValue<-1, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 1, 0>(), S.template getValue< 0, 0, 0>(), - S.template getValue< 0,-1, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 1>(), S.template getValue< 0, 0, 0>(), - S.template getValue< 0, 0,-1>() ); - } - - // cross derivatives - template - static typename Stencil::ValueType inXandY(const Stencil& S) - { - return crossdifference(S.template getValue< 1, 1, 0>(), S.template getValue< 1,-1, 0>(), - S.template getValue<-1, 1, 0>(), S.template getValue<-1,-1, 0>() ); - } - - template - static typename Stencil::ValueType inXandZ(const Stencil& S) - { - return crossdifference(S.template getValue< 1, 0, 1>(), S.template getValue< 1, 0,-1>(), - S.template getValue<-1, 0, 1>(), S.template getValue<-1, 0,-1>() ); - } - - template - static typename Stencil::ValueType inYandZ(const Stencil& S) - { - return crossdifference(S.template getValue< 0, 1, 1>(), S.template getValue< 0, 1,-1>(), - S.template getValue< 0,-1, 1>(), S.template getValue< 0,-1,-1>() ); - } -}; - - -template<> -struct D2 -{ - - // the difference opperator - template - static ValueType difference(const ValueType& xp2, const ValueType& xp1, const ValueType& xp0, - const ValueType& xm1, const ValueType& xm2) { - return ValueType(-1./12.)*(xp2 + xm2) + ValueType(4./3.)*(xp1 + xm1) -ValueType(2.5)*xp0; - } - - template - static ValueType crossdifference(const ValueType& xp2yp2, const ValueType& xp2yp1, - const ValueType& xp2ym1, const ValueType& xp2ym2, - const ValueType& xp1yp2, const ValueType& xp1yp1, - const ValueType& xp1ym1, const ValueType& xp1ym2, - const ValueType& xm2yp2, const ValueType& xm2yp1, - const ValueType& xm2ym1, const ValueType& xm2ym2, - const ValueType& xm1yp2, const ValueType& xm1yp1, - const ValueType& xm1ym1, const ValueType& xm1ym2 ) { - ValueType tmp1 = - ValueType(2./3.0)*(xp1yp1 - xm1yp1 - xp1ym1 + xm1ym1)- - ValueType(1./12.)*(xp2yp1 - xm2yp1 - xp2ym1 + xm2ym1); - ValueType tmp2 = - ValueType(2./3.0)*(xp1yp2 - xm1yp2 - xp1ym2 + xm1ym2)- - ValueType(1./12.)*(xp2yp2 - xm2yp2 - xp2ym2 + xm2ym2); - - return ValueType(2./3.)*tmp1 - ValueType(1./12.)*tmp2; - } - - - - // random access version - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(2,0,0)), grid.getValue(ijk.offsetBy( 1,0,0)), - grid.getValue(ijk), - grid.getValue(ijk.offsetBy(-1,0,0)), grid.getValue(ijk.offsetBy(-2, 0, 0))); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0, 2,0)), grid.getValue(ijk.offsetBy(0, 1,0)), - grid.getValue(ijk), - grid.getValue(ijk.offsetBy(0,-1,0)), grid.getValue(ijk.offsetBy(0,-2, 0))); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy(0,0, 2)), grid.getValue(ijk.offsetBy(0, 0,1)), - grid.getValue(ijk), - grid.getValue(ijk.offsetBy(0,0,-1)), grid.getValue(ijk.offsetBy(0,0,-2))); - } - - // cross derivatives - template - static typename Accessor::ValueType inXandY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typename Accessor::ValueType tmp1 = - D1::inX(grid, ijk.offsetBy(0, 1, 0)) - - D1::inX(grid, ijk.offsetBy(0,-1, 0)); - typename Accessor::ValueType tmp2 = - D1::inX(grid, ijk.offsetBy(0, 2, 0)) - - D1::inX(grid, ijk.offsetBy(0,-2, 0)); - return ValueType(2./3.)*tmp1 - ValueType(1./12.)*tmp2; - } - - template - static typename Accessor::ValueType inXandZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typename Accessor::ValueType tmp1 = - D1::inX(grid, ijk.offsetBy(0, 0, 1)) - - D1::inX(grid, ijk.offsetBy(0, 0,-1)); - typename Accessor::ValueType tmp2 = - D1::inX(grid, ijk.offsetBy(0, 0, 2)) - - D1::inX(grid, ijk.offsetBy(0, 0,-2)); - return ValueType(2./3.)*tmp1 - ValueType(1./12.)*tmp2; - } - - template - static typename Accessor::ValueType inYandZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typename Accessor::ValueType tmp1 = - D1::inY(grid, ijk.offsetBy(0, 0, 1)) - - D1::inY(grid, ijk.offsetBy(0, 0,-1)); - typename Accessor::ValueType tmp2 = - D1::inY(grid, ijk.offsetBy(0, 0, 2)) - - D1::inY(grid, ijk.offsetBy(0, 0,-2)); - return ValueType(2./3.)*tmp1 - ValueType(1./12.)*tmp2; - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference(S.template getValue< 2, 0, 0>(), S.template getValue< 1, 0, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue<-1, 0, 0>(), S.template getValue<-2, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference(S.template getValue< 0, 2, 0>(), S.template getValue< 0, 1, 0>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0,-1, 0>(), S.template getValue< 0,-2, 0>() ); - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference(S.template getValue< 0, 0, 2>(), S.template getValue< 0, 0, 1>(), - S.template getValue< 0, 0, 0>(), - S.template getValue< 0, 0,-1>(), S.template getValue< 0, 0,-2>() ); - } - - // cross derivatives - template - static typename Stencil::ValueType inXandY(const Stencil& S) - { - return crossdifference( - S.template getValue< 2, 2, 0>(), S.template getValue< 2, 1, 0>(), - S.template getValue< 2,-1, 0>(), S.template getValue< 2,-2, 0>(), - S.template getValue< 1, 2, 0>(), S.template getValue< 1, 1, 0>(), - S.template getValue< 1,-1, 0>(), S.template getValue< 1,-2, 0>(), - S.template getValue<-2, 2, 0>(), S.template getValue<-2, 1, 0>(), - S.template getValue<-2,-1, 0>(), S.template getValue<-2,-2, 0>(), - S.template getValue<-1, 2, 0>(), S.template getValue<-1, 1, 0>(), - S.template getValue<-1,-1, 0>(), S.template getValue<-1,-2, 0>() ); - } - - template - static typename Stencil::ValueType inXandZ(const Stencil& S) - { - return crossdifference( - S.template getValue< 2, 0, 2>(), S.template getValue< 2, 0, 1>(), - S.template getValue< 2, 0,-1>(), S.template getValue< 2, 0,-2>(), - S.template getValue< 1, 0, 2>(), S.template getValue< 1, 0, 1>(), - S.template getValue< 1, 0,-1>(), S.template getValue< 1, 0,-2>(), - S.template getValue<-2, 0, 2>(), S.template getValue<-2, 0, 1>(), - S.template getValue<-2, 0,-1>(), S.template getValue<-2, 0,-2>(), - S.template getValue<-1, 0, 2>(), S.template getValue<-1, 0, 1>(), - S.template getValue<-1, 0,-1>(), S.template getValue<-1, 0,-2>() ); - } - - template - static typename Stencil::ValueType inYandZ(const Stencil& S) - { - return crossdifference( - S.template getValue< 0, 2, 2>(), S.template getValue< 0, 2, 1>(), - S.template getValue< 0, 2,-1>(), S.template getValue< 0, 2,-2>(), - S.template getValue< 0, 1, 2>(), S.template getValue< 0, 1, 1>(), - S.template getValue< 0, 1,-1>(), S.template getValue< 0, 1,-2>(), - S.template getValue< 0,-2, 2>(), S.template getValue< 0,-2, 1>(), - S.template getValue< 0,-2,-1>(), S.template getValue< 0,-2,-2>(), - S.template getValue< 0,-1, 2>(), S.template getValue< 0,-1, 1>(), - S.template getValue< 0,-1,-1>(), S.template getValue< 0,-1,-2>() ); - } -}; - - -template<> -struct D2 -{ - // the difference opperator - template - static ValueType difference(const ValueType& xp3, const ValueType& xp2, const ValueType& xp1, - const ValueType& xp0, - const ValueType& xm1, const ValueType& xm2, const ValueType& xm3) - { - return ValueType(1./90.)*(xp3 + xm3) - ValueType(3./20.)*(xp2 + xm2) - + ValueType(1.5)*(xp1 + xm1) - ValueType(49./18.)*xp0; - } - - template - static ValueType crossdifference( const ValueType& xp1yp1,const ValueType& xm1yp1, - const ValueType& xp1ym1,const ValueType& xm1ym1, - const ValueType& xp2yp1,const ValueType& xm2yp1, - const ValueType& xp2ym1,const ValueType& xm2ym1, - const ValueType& xp3yp1,const ValueType& xm3yp1, - const ValueType& xp3ym1,const ValueType& xm3ym1, - const ValueType& xp1yp2,const ValueType& xm1yp2, - const ValueType& xp1ym2,const ValueType& xm1ym2, - const ValueType& xp2yp2,const ValueType& xm2yp2, - const ValueType& xp2ym2,const ValueType& xm2ym2, - const ValueType& xp3yp2,const ValueType& xm3yp2, - const ValueType& xp3ym2,const ValueType& xm3ym2, - const ValueType& xp1yp3,const ValueType& xm1yp3, - const ValueType& xp1ym3,const ValueType& xm1ym3, - const ValueType& xp2yp3,const ValueType& xm2yp3, - const ValueType& xp2ym3,const ValueType& xm2ym3, - const ValueType& xp3yp3,const ValueType& xm3yp3, - const ValueType& xp3ym3,const ValueType& xm3ym3 ) - { - ValueType tmp1 = - ValueType(0.7500)*(xp1yp1 - xm1yp1 - xp1ym1 + xm1ym1) - - ValueType(0.1500)*(xp2yp1 - xm2yp1 - xp2ym1 + xm2ym1) + - ValueType(1./60.)*(xp3yp1 - xm3yp1 - xp3ym1 + xm3ym1); - - ValueType tmp2 = - ValueType(0.7500)*(xp1yp2 - xm1yp2 - xp1ym2 + xm1ym2) - - ValueType(0.1500)*(xp2yp2 - xm2yp2 - xp2ym2 + xm2ym2) + - ValueType(1./60.)*(xp3yp2 - xm3yp2 - xp3ym2 + xm3ym2); - - ValueType tmp3 = - ValueType(0.7500)*(xp1yp3 - xm1yp3 - xp1ym3 + xm1ym3) - - ValueType(0.1500)*(xp2yp3 - xm2yp3 - xp2ym3 + xm2ym3) + - ValueType(1./60.)*(xp3yp3 - xm3yp3 - xp3ym3 + xm3ym3); - - return ValueType(0.75)*tmp1 - ValueType(0.15)*tmp2 + ValueType(1./60)*tmp3; - } - - // random access version - - template - static typename Accessor::ValueType inX(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 3, 0, 0)), grid.getValue(ijk.offsetBy( 2, 0, 0)), - grid.getValue(ijk.offsetBy( 1, 0, 0)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy(-1, 0, 0)), grid.getValue(ijk.offsetBy(-2, 0, 0)), - grid.getValue(ijk.offsetBy(-3, 0, 0)) ); - } - - template - static typename Accessor::ValueType inY(const Accessor& grid, const Coord& ijk) - { - return difference( - grid.getValue(ijk.offsetBy( 0, 3, 0)), grid.getValue(ijk.offsetBy( 0, 2, 0)), - grid.getValue(ijk.offsetBy( 0, 1, 0)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy( 0,-1, 0)), grid.getValue(ijk.offsetBy( 0,-2, 0)), - grid.getValue(ijk.offsetBy( 0,-3, 0)) ); - } - - template - static typename Accessor::ValueType inZ(const Accessor& grid, const Coord& ijk) - { - - return difference( - grid.getValue(ijk.offsetBy( 0, 0, 3)), grid.getValue(ijk.offsetBy( 0, 0, 2)), - grid.getValue(ijk.offsetBy( 0, 0, 1)), grid.getValue(ijk), - grid.getValue(ijk.offsetBy( 0, 0,-1)), grid.getValue(ijk.offsetBy( 0, 0,-2)), - grid.getValue(ijk.offsetBy( 0, 0,-3)) ); - } - - template - static typename Accessor::ValueType inXandY(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueT; - ValueT tmp1 = - D1::inX(grid, ijk.offsetBy(0, 1, 0)) - - D1::inX(grid, ijk.offsetBy(0,-1, 0)); - ValueT tmp2 = - D1::inX(grid, ijk.offsetBy(0, 2, 0)) - - D1::inX(grid, ijk.offsetBy(0,-2, 0)); - ValueT tmp3 = - D1::inX(grid, ijk.offsetBy(0, 3, 0)) - - D1::inX(grid, ijk.offsetBy(0,-3, 0)); - return ValueT(0.75*tmp1 - 0.15*tmp2 + 1./60*tmp3); - } - - template - static typename Accessor::ValueType inXandZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueT; - ValueT tmp1 = - D1::inX(grid, ijk.offsetBy(0, 0, 1)) - - D1::inX(grid, ijk.offsetBy(0, 0,-1)); - ValueT tmp2 = - D1::inX(grid, ijk.offsetBy(0, 0, 2)) - - D1::inX(grid, ijk.offsetBy(0, 0,-2)); - ValueT tmp3 = - D1::inX(grid, ijk.offsetBy(0, 0, 3)) - - D1::inX(grid, ijk.offsetBy(0, 0,-3)); - return ValueT(0.75*tmp1 - 0.15*tmp2 + 1./60*tmp3); - } - - template - static typename Accessor::ValueType inYandZ(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueT; - ValueT tmp1 = - D1::inY(grid, ijk.offsetBy(0, 0, 1)) - - D1::inY(grid, ijk.offsetBy(0, 0,-1)); - ValueT tmp2 = - D1::inY(grid, ijk.offsetBy(0, 0, 2)) - - D1::inY(grid, ijk.offsetBy(0, 0,-2)); - ValueT tmp3 = - D1::inY(grid, ijk.offsetBy(0, 0, 3)) - - D1::inY(grid, ijk.offsetBy(0, 0,-3)); - return ValueT(0.75*tmp1 - 0.15*tmp2 + 1./60*tmp3); - } - - - // stencil access version - template - static typename Stencil::ValueType inX(const Stencil& S) - { - return difference( S.template getValue< 3, 0, 0>(), S.template getValue< 2, 0, 0>(), - S.template getValue< 1, 0, 0>(), S.template getValue< 0, 0, 0>(), - S.template getValue<-1, 0, 0>(), S.template getValue<-2, 0, 0>(), - S.template getValue<-3, 0, 0>() ); - } - - template - static typename Stencil::ValueType inY(const Stencil& S) - { - return difference( S.template getValue< 0, 3, 0>(), S.template getValue< 0, 2, 0>(), - S.template getValue< 0, 1, 0>(), S.template getValue< 0, 0, 0>(), - S.template getValue< 0,-1, 0>(), S.template getValue< 0,-2, 0>(), - S.template getValue< 0,-3, 0>() ); - - } - - template - static typename Stencil::ValueType inZ(const Stencil& S) - { - return difference( S.template getValue< 0, 0, 3>(), S.template getValue< 0, 0, 2>(), - S.template getValue< 0, 0, 1>(), S.template getValue< 0, 0, 0>(), - S.template getValue< 0, 0,-1>(), S.template getValue< 0, 0,-2>(), - S.template getValue< 0, 0,-3>() ); - } - - template - static typename Stencil::ValueType inXandY(const Stencil& S) - { - return crossdifference( S.template getValue< 1, 1, 0>(), S.template getValue<-1, 1, 0>(), - S.template getValue< 1,-1, 0>(), S.template getValue<-1,-1, 0>(), - S.template getValue< 2, 1, 0>(), S.template getValue<-2, 1, 0>(), - S.template getValue< 2,-1, 0>(), S.template getValue<-2,-1, 0>(), - S.template getValue< 3, 1, 0>(), S.template getValue<-3, 1, 0>(), - S.template getValue< 3,-1, 0>(), S.template getValue<-3,-1, 0>(), - S.template getValue< 1, 2, 0>(), S.template getValue<-1, 2, 0>(), - S.template getValue< 1,-2, 0>(), S.template getValue<-1,-2, 0>(), - S.template getValue< 2, 2, 0>(), S.template getValue<-2, 2, 0>(), - S.template getValue< 2,-2, 0>(), S.template getValue<-2,-2, 0>(), - S.template getValue< 3, 2, 0>(), S.template getValue<-3, 2, 0>(), - S.template getValue< 3,-2, 0>(), S.template getValue<-3,-2, 0>(), - S.template getValue< 1, 3, 0>(), S.template getValue<-1, 3, 0>(), - S.template getValue< 1,-3, 0>(), S.template getValue<-1,-3, 0>(), - S.template getValue< 2, 3, 0>(), S.template getValue<-2, 3, 0>(), - S.template getValue< 2,-3, 0>(), S.template getValue<-2,-3, 0>(), - S.template getValue< 3, 3, 0>(), S.template getValue<-3, 3, 0>(), - S.template getValue< 3,-3, 0>(), S.template getValue<-3,-3, 0>() ); - } - - template - static typename Stencil::ValueType inXandZ(const Stencil& S) - { - return crossdifference( S.template getValue< 1, 0, 1>(), S.template getValue<-1, 0, 1>(), - S.template getValue< 1, 0,-1>(), S.template getValue<-1, 0,-1>(), - S.template getValue< 2, 0, 1>(), S.template getValue<-2, 0, 1>(), - S.template getValue< 2, 0,-1>(), S.template getValue<-2, 0,-1>(), - S.template getValue< 3, 0, 1>(), S.template getValue<-3, 0, 1>(), - S.template getValue< 3, 0,-1>(), S.template getValue<-3, 0,-1>(), - S.template getValue< 1, 0, 2>(), S.template getValue<-1, 0, 2>(), - S.template getValue< 1, 0,-2>(), S.template getValue<-1, 0,-2>(), - S.template getValue< 2, 0, 2>(), S.template getValue<-2, 0, 2>(), - S.template getValue< 2, 0,-2>(), S.template getValue<-2, 0,-2>(), - S.template getValue< 3, 0, 2>(), S.template getValue<-3, 0, 2>(), - S.template getValue< 3, 0,-2>(), S.template getValue<-3, 0,-2>(), - S.template getValue< 1, 0, 3>(), S.template getValue<-1, 0, 3>(), - S.template getValue< 1, 0,-3>(), S.template getValue<-1, 0,-3>(), - S.template getValue< 2, 0, 3>(), S.template getValue<-2, 0, 3>(), - S.template getValue< 2, 0,-3>(), S.template getValue<-2, 0,-3>(), - S.template getValue< 3, 0, 3>(), S.template getValue<-3, 0, 3>(), - S.template getValue< 3, 0,-3>(), S.template getValue<-3, 0,-3>() ); - } - - template - static typename Stencil::ValueType inYandZ(const Stencil& S) - { - return crossdifference( S.template getValue< 0, 1, 1>(), S.template getValue< 0,-1, 1>(), - S.template getValue< 0, 1,-1>(), S.template getValue< 0,-1,-1>(), - S.template getValue< 0, 2, 1>(), S.template getValue< 0,-2, 1>(), - S.template getValue< 0, 2,-1>(), S.template getValue< 0,-2,-1>(), - S.template getValue< 0, 3, 1>(), S.template getValue< 0,-3, 1>(), - S.template getValue< 0, 3,-1>(), S.template getValue< 0,-3,-1>(), - S.template getValue< 0, 1, 2>(), S.template getValue< 0,-1, 2>(), - S.template getValue< 0, 1,-2>(), S.template getValue< 0,-1,-2>(), - S.template getValue< 0, 2, 2>(), S.template getValue< 0,-2, 2>(), - S.template getValue< 0, 2,-2>(), S.template getValue< 0,-2,-2>(), - S.template getValue< 0, 3, 2>(), S.template getValue< 0,-3, 2>(), - S.template getValue< 0, 3,-2>(), S.template getValue< 0,-3,-2>(), - S.template getValue< 0, 1, 3>(), S.template getValue< 0,-1, 3>(), - S.template getValue< 0, 1,-3>(), S.template getValue< 0,-1,-3>(), - S.template getValue< 0, 2, 3>(), S.template getValue< 0,-2, 3>(), - S.template getValue< 0, 2,-3>(), S.template getValue< 0,-2,-3>(), - S.template getValue< 0, 3, 3>(), S.template getValue< 0,-3, 3>(), - S.template getValue< 0, 3,-3>(), S.template getValue< 0,-3,-3>() ); - } - -}; - -} // end math namespace -} // namespace OPENVDB_VERSION_NAME -} // end openvdb namespace - -#endif // OPENVDB_MATH_FINITEDIFFERENCE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Hermite.cc b/openvdb_3_0_0_library/math/Hermite.cc deleted file mode 100755 index 819fcad..0000000 --- a/openvdb_3_0_0_library/math/Hermite.cc +++ /dev/null @@ -1,167 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Hermite.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - -// min and max on compressd data - -Hermite -min(const Hermite& lhs, const Hermite& rhs) -{ - Hermite ret; - - if(!lhs && !rhs) { - - if(lhs.isInside()) ret = lhs; - else ret = rhs; - - return ret; - } - - ret.setIsInside(lhs.isInside() || rhs.isInside()); - - if(lhs.isGreaterX(rhs)) ret.setX(rhs); - else ret.setX(lhs); - - if(lhs.isGreaterY(rhs)) ret.setY(rhs); - else ret.setY(lhs); - - if(lhs.isGreaterZ(rhs)) ret.setZ(rhs); - else ret.setZ(lhs); - - return ret; -} - -Hermite -max(const Hermite& lhs, const Hermite& rhs) -{ - Hermite ret; - - if(!lhs && !rhs) { - - if(!lhs.isInside()) ret = lhs; - else ret = rhs; - - return ret; - } - - ret.setIsInside(lhs.isInside() && rhs.isInside()); - - if(rhs.isGreaterX(lhs)) ret.setX(rhs); - else ret.setX(lhs); - - if(rhs.isGreaterY(lhs)) ret.setY(rhs); - else ret.setY(lhs); - - if(rhs.isGreaterZ(lhs)) ret.setZ(rhs); - else ret.setZ(lhs); - - return ret; -} - - -//////////////////////////////////////// - -// constructors - -Hermite::Hermite(): - mXNormal(0), - mYNormal(0), - mZNormal(0), - mData(0) -{ -} - -Hermite::Hermite(const Hermite& rhs): - mXNormal(rhs.mXNormal), - mYNormal(rhs.mYNormal), - mZNormal(rhs.mZNormal), - mData(rhs.mData) -{ -} - - -//////////////////////////////////////// - -// string representation - -std::string -Hermite::str() const -{ - std::ostringstream ss; - - ss << "{ " << (isInside() ? "inside" : "outside"); - if(hasOffsetX()) ss << " |x " << getOffsetX() << " " << getNormalX(); - if(hasOffsetY()) ss << " |y " << getOffsetY() << " " << getNormalY(); - if(hasOffsetZ()) ss << " |z " << getOffsetZ() << " " << getNormalZ(); - ss << " }"; - - return ss.str(); -} - - -//////////////////////////////////////// - - -void -Hermite::read(std::istream& is) -{ - is.read(reinterpret_cast(&mXNormal), sizeof(uint16_t)); - is.read(reinterpret_cast(&mYNormal), sizeof(uint16_t)); - is.read(reinterpret_cast(&mZNormal), sizeof(uint16_t)); - is.read(reinterpret_cast(&mData), sizeof(uint32_t)); -} - -void -Hermite::write(std::ostream& os) const -{ - os.write(reinterpret_cast(&mXNormal), sizeof(uint16_t)); - os.write(reinterpret_cast(&mYNormal), sizeof(uint16_t)); - os.write(reinterpret_cast(&mZNormal), sizeof(uint16_t)); - os.write(reinterpret_cast(&mData), sizeof(uint32_t)); -} - - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Hermite.h b/openvdb_3_0_0_library/math/Hermite.h deleted file mode 100755 index 97974ac..0000000 --- a/openvdb_3_0_0_library/math/Hermite.h +++ /dev/null @@ -1,493 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_HERMITE_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_HERMITE_HAS_BEEN_INCLUDED - -#include -#include -#include "QuantizedUnitVec.h" -#include "Math.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -// Forward declaration -class Hermite; - - -//////////////////////////////////////// - -// Utility methods - - -//@{ -/// min and max operations done directly on the compressed data. -OPENVDB_API Hermite min(const Hermite&, const Hermite&); -OPENVDB_API Hermite max(const Hermite&, const Hermite&); -//@} - - -//////////////////////////////////////// - - -/// @brief Quantized Hermite data object that stores compressed intersection -/// information (offsets and normlas) for the up-wind edges of a voxel. (Size 10 bytes) -class OPENVDB_API Hermite -{ -public: - - Hermite(); - Hermite(const Hermite&); - const Hermite& operator=(const Hermite&); - - /// clears all intersection data - void clear(); - - /// @return true if this Hermite objet has any edge intersection data. - operator bool() const; - - /// equality operator - inline bool operator==(const Hermite&) const; - /// inequality operator - bool operator!=(const Hermite& rhs) const { return !(*this == rhs); } - - /// unary negation operator, flips inside/outside state and normals. - Hermite operator-() const; - - //@{ - /// @brief methods to compress and store edge data. - /// @note @c offset is expected to be in the [0 to 1) range. - template - void setX(T offset, const Vec3&); - - template - void setY(T offset, const Vec3&); - - template - void setZ(T offset, const Vec3&); - //@} - - /// @return true if the current Hermite object is classified - // as being inside a contour. - bool isInside() const { return MASK_SIGN & mData; } - /// Set the inside/outside state to reflect if this Hermite object - /// is located at a point in space that is inside/outside a contour. - void setIsInside(bool); - - //@{ - /// @return true if this Hermite object has intersection data - /// for the corresponding edge. - bool hasOffsetX() const { return mXNormal; }; - bool hasOffsetY() const { return mYNormal; } - bool hasOffsetZ() const { return MASK_ZFLAG & mData; } - //@} - - //@{ - /// Edge offset greater-than comparisson operators - /// @note is @c this offset > than @c other offset - bool isGreaterX(const Hermite& other) const; - bool isGreaterY(const Hermite& other) const; - bool isGreaterZ(const Hermite& other) const; - //@} - - //@{ - /// Edge offset less-than comparisson operators - /// @note is @c this offset < than @c other offset - bool isLessX(const Hermite& other) const; - bool isLessY(const Hermite& other) const; - bool isLessZ(const Hermite& other) const; - //@} - - //@{ - /// @return uncompressed edge intersection offsets - float getOffsetX() const; - float getOffsetY() const; - float getOffsetZ() const; - //@} - - //@{ - /// @return uncompressed edge intersection normals - Vec3s getNormalX() const { return QuantizedUnitVec::unpack(mXNormal); } - Vec3s getNormalY() const { return QuantizedUnitVec::unpack(mYNormal); } - Vec3s getNormalZ() const { return QuantizedUnitVec::unpack(mZNormal); } - //@} - - //@{ - /// copy edge data from other Hermite object - /// @note copies data in the compressed form - void setX(const Hermite&); - void setY(const Hermite&); - void setZ(const Hermite&); - //@} - - /// String representation. - std::string str() const; - - /// Unserialize this transform from the given stream. - void read(std::istream&); - /// Serialize this transform to the given stream. - void write(std::ostream&) const; - - //@{ - /// Operators required by OpenVDB. - /// @note These methods don't perform meaningful operations on Hermite data. - bool operator< (const Hermite&) const { return false; }; - bool operator> (const Hermite&) const { return false; }; - template Hermite operator+(const T&) const { return *this; } - template Hermite operator-(const T&) const { return *this; } - //@} - -private: - /// Helper function that quantizes a [0, 1) offset using 10-bits. - template - static uint32_t quantizeOffset(T offset); - - /// Helper function that returns (signed) compressed-offsets, - /// used by comparisson operators. - static void getSignedOffsets(const Hermite& lhs, const Hermite& rhs, - const uint32_t bitmask, int& lhsV, int& rhsV); - - - // Bits masks - // 10000000000000000000000000000000 - static const uint32_t MASK_SIGN = 0x80000000; - // 01000000000000000000000000000000 - static const uint32_t MASK_ZFLAG = 0x40000000; - // 00111111111100000000000000000000 - static const uint32_t MASK_XSLOT = 0x3FF00000; - // 00000000000011111111110000000000 - static const uint32_t MASK_YSLOT = 0x000FFC00; - // 00000000000000000000001111111111 - static const uint32_t MASK_ZSLOT = 0x000003FF; - // 00111111111111111111111111111111 - static const uint32_t MASK_SLOTS = 0x3FFFFFFF; - - - uint16_t mXNormal, mYNormal, mZNormal; - uint32_t mData; - -}; // class Hermite - - -//////////////////////////////////////// - -// output-stream insertion operator - -inline std::ostream& -operator<<(std::ostream& ostr, const Hermite& rhs) -{ - ostr << rhs.str(); - return ostr; -} - - -//////////////////////////////////////// - -// construction and assignment - -inline const Hermite& -Hermite::operator=(const Hermite& rhs) -{ - mData = rhs.mData; - mXNormal = rhs.mXNormal; - mYNormal = rhs.mYNormal; - mZNormal = rhs.mZNormal; - return *this; -} - - -inline void -Hermite::clear() -{ - mXNormal = 0; - mYNormal = 0; - mZNormal = 0; - mData = 0; -} - - -//////////////////////////////////////// - -// bool operator and equality - -inline -Hermite::operator bool() const -{ - if (0 != (mXNormal | mYNormal)) return true; - return hasOffsetZ(); -} - - -inline bool -Hermite::operator==(const Hermite& rhs) const -{ - if(mXNormal != rhs.mXNormal) return false; - if(mYNormal != rhs.mYNormal) return false; - if(mZNormal != rhs.mZNormal) return false; - return mData == rhs.mData; -} - - -//////////////////////////////////////// - -// unary negation operator - -inline Hermite -Hermite::operator-() const -{ - Hermite ret(*this); - QuantizedUnitVec::flipSignBits(ret.mXNormal); - QuantizedUnitVec::flipSignBits(ret.mYNormal); - QuantizedUnitVec::flipSignBits(ret.mZNormal); - ret.mData = (~MASK_SIGN & ret.mData) | (MASK_SIGN & ~ret.mData); - return ret; -} - - -//////////////////////////////////////// - -// Helper funcions - -template -inline uint32_t -Hermite::quantizeOffset(T offset) -{ - // the offset is expected to be normalized [0 to 1) - assert(offset < 1.0); - assert(offset > -1.0e-8); - - // quantize the offset using 10-bits. (higher bits are masked out) - return uint32_t(1023 * offset) & MASK_ZSLOT; -} - -inline void -Hermite::getSignedOffsets(const Hermite& lhs, const Hermite& rhs, - const uint32_t bitmask, int& lhsV, int& rhsV) -{ - lhsV = bitmask & lhs.mData; - rhsV = bitmask & rhs.mData; - - if(lhs.isInside()) lhsV = -lhsV; - if(rhs.isInside()) rhsV = -rhsV; -} - - -//////////////////////////////////////// - -// compress and set edge data - -template -inline void -Hermite::setX(T offset, const Vec3& n) -{ - mData &= ~MASK_XSLOT; // clear xslot - mData |= quantizeOffset(offset) << 20; - mXNormal = QuantizedUnitVec::pack(n); -} - -template -inline void -Hermite::setY(T offset, const Vec3& n) -{ - mData &= ~MASK_YSLOT; // clear yslot - mData |= quantizeOffset(offset) << 10; - mYNormal = QuantizedUnitVec::pack(n); -} - -template -inline void -Hermite::setZ(T offset, const Vec3& n) -{ - mData &= ~MASK_ZSLOT; // clear zslot - mData |= MASK_ZFLAG | quantizeOffset(offset); - mZNormal = QuantizedUnitVec::pack(n); -} - - -//////////////////////////////////////// - -// change inside/outside state - -inline void -Hermite::setIsInside(bool isInside) -{ - mData &= ~MASK_SIGN; // clear sign-bit - mData |= uint32_t(isInside) * MASK_SIGN; -} - - -//////////////////////////////////////// - -// Uncompress and return the edge intersection-offsets -// 0.000977517 = 1.0 / 1023 - -inline float -Hermite::getOffsetX() const -{ - return float(((mData >> 20) & MASK_ZSLOT) * 0.000977517); -} - -inline float -Hermite::getOffsetY() const -{ - return float(((mData >> 10) & MASK_ZSLOT) * 0.000977517); -} - -inline float -Hermite::getOffsetZ() const -{ - return float((mData & MASK_ZSLOT) * 0.000977517); -} - - -//////////////////////////////////////// - -// copy compressed edge data from other object - -inline void -Hermite::setX(const Hermite& rhs) -{ - mData &= ~MASK_XSLOT; // clear xslot - mData |= MASK_XSLOT & rhs.mData; // copy xbits from rhs - mXNormal = rhs.mXNormal; // copy compressed normal - - // Flip the copied normal if the rhs object has - // a different inside/outside state. - if(hasOffsetX() && isInside() != rhs.isInside()) - QuantizedUnitVec::flipSignBits(mXNormal); -} - -inline void -Hermite::setY(const Hermite& rhs) -{ - mData &= ~MASK_YSLOT; - mData |= MASK_YSLOT & rhs.mData; - mYNormal = rhs.mYNormal; - - if(hasOffsetY() && isInside() != rhs.isInside()) - QuantizedUnitVec::flipSignBits(mYNormal); -} - -inline void -Hermite::setZ(const Hermite& rhs) -{ - mData &= ~MASK_ZSLOT; - mData |= (MASK_ZFLAG | MASK_ZSLOT) & rhs.mData; - mZNormal = rhs.mZNormal; - if(hasOffsetZ() && isInside() != rhs.isInside()) - QuantizedUnitVec::flipSignBits(mZNormal); -} - - -//////////////////////////////////////// - -// edge comparison operators - -inline bool -Hermite::isGreaterX(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_XSLOT, lhsV, rhsV); - return lhsV > rhsV; -} - -inline bool -Hermite::isGreaterY(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_YSLOT, lhsV, rhsV); - return lhsV > rhsV; -} - -inline bool -Hermite::isGreaterZ(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_ZSLOT, lhsV, rhsV); - return lhsV > rhsV; -} - -inline bool -Hermite::isLessX(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_XSLOT, lhsV, rhsV); - return lhsV < rhsV; -} - -inline bool -Hermite::isLessY(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_YSLOT, lhsV, rhsV); - return lhsV < rhsV; -} - -inline bool -Hermite::isLessZ(const Hermite& rhs) const -{ - int lhsV, rhsV; - getSignedOffsets(*this, rhs, MASK_ZSLOT, lhsV, rhsV); - return lhsV < rhsV; -} - - -//////////////////////////////////////// - - -inline bool -isApproxEqual(const Hermite& lhs, const Hermite& rhs) { return lhs == rhs; } - -inline bool -isApproxEqual(const Hermite& lhs, const Hermite& rhs, const Hermite& /*tolerance*/) - { return isApproxEqual(lhs, rhs); } - - -} // namespace math - - -//////////////////////////////////////// - - -template<> inline math::Hermite zeroVal() { return math::Hermite(); } - - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_HERMITE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/LegacyFrustum.h b/openvdb_3_0_0_library/math/LegacyFrustum.h deleted file mode 100755 index b30811a..0000000 --- a/openvdb_3_0_0_library/math/LegacyFrustum.h +++ /dev/null @@ -1,196 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file math/LegacyFrustum.h - -#ifndef OPENVDB_MATH_LEGACYFRUSTUM_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_LEGACYFRUSTUM_HAS_BEEN_INCLUDED - -#include -#include // for Real typedef -#include "Coord.h" -#include "Mat4.h" -#include "Vec3.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { -namespace internal { - -/// @brief LegacyFrustum class used at DreamWorks for converting old vdb files. -class LegacyFrustum -{ -public: - LegacyFrustum(std::istream& is) - { - // First read in the old transform's base class. - // the "extents" - Vec3i tmpMin, tmpMax; - is.read(reinterpret_cast(&tmpMin), sizeof(Vec3i::ValueType) * 3); - is.read(reinterpret_cast(&tmpMax), sizeof(Vec3i::ValueType) * 3); - - Coord tmpMinCoord(tmpMin); - Coord tmpMaxCoord(tmpMax); - - // set the extents - mExtents = CoordBBox(tmpMinCoord, tmpMaxCoord); - - // read the old-frustum class member data - //Mat4d tmpW2C; - Mat4d tmpW2C, tmpC2S, tmpS2C, tmpWorldToLocal; - Mat4d tmpS2U, tmpXYLocalToUnit, tmpZLocalToUnit; - Real tmpWindow[6]; - Real tmpPadding; - - //Mat4d tmpXYUnitToLocal, tmpZUnitToLocal - - // read in each matrix. - is.read(reinterpret_cast(&tmpW2C), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&mC2W), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&tmpC2S), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&tmpS2C), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&tmpWorldToLocal), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&mLocalToWorld), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - - is.read(reinterpret_cast(&tmpWindow[0]), sizeof(Real)); - is.read(reinterpret_cast(&tmpWindow[1]), sizeof(Real)); - is.read(reinterpret_cast(&tmpWindow[2]), sizeof(Real)); - is.read(reinterpret_cast(&tmpWindow[3]), sizeof(Real)); - is.read(reinterpret_cast(&tmpWindow[4]), sizeof(Real)); - is.read(reinterpret_cast(&tmpWindow[5]), sizeof(Real)); - - is.read(reinterpret_cast(&tmpPadding), sizeof(Real)); - - is.read(reinterpret_cast(&tmpS2U), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&mXYUnitToLocal), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&tmpXYLocalToUnit), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&mZUnitToLocal), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - is.read(reinterpret_cast(&tmpZLocalToUnit), - sizeof(Mat4d::value_type) * Mat4d::size * Mat4d::size); - - - mNearPlane = tmpWindow[4]; - mFarPlane = tmpWindow[5]; - - // Look up the world space corners of the - // frustum grid. - mFrNearOrigin = unitToLocalFrustum(Vec3R(0,0,0)); - mFrFarOrigin = unitToLocalFrustum(Vec3R(0,0,1)); - - Vec3d frNearXTip = unitToLocalFrustum(Vec3R(1,0,0)); - Vec3d frNearYTip = unitToLocalFrustum(Vec3R(0,1,0)); - mFrNearXBasis = frNearXTip - mFrNearOrigin; - mFrNearYBasis = frNearYTip - mFrNearOrigin; - - Vec3R frFarXTip = unitToLocalFrustum(Vec3R(1,0,1)); - Vec3R frFarYTip = unitToLocalFrustum(Vec3R(0,1,1)); - mFrFarXBasis = frFarXTip - mFrFarOrigin; - mFrFarYBasis = frFarYTip - mFrFarOrigin; - } - - ~LegacyFrustum(){}; - - const Mat4d& getCamXForm() const {return mC2W; } - - double getDepth() const {return (mFarPlane - mNearPlane); } - double getTaper() const { - - return getNearPlaneWidth() / getFarPlaneWidth(); - } - - double getNearPlaneWidth() const { - double nearPlaneWidth = (unitToWorld(Vec3d(0,0,0)) - unitToWorld(Vec3d(1,0,0))).length(); - return nearPlaneWidth; - } - - double getFarPlaneWidth() const { - double farPlaneWidth = (unitToWorld(Vec3d(0,0,1)) - unitToWorld(Vec3d(1,0,1))).length(); - return farPlaneWidth; - } - - double getNearPlaneDist() const { return mNearPlane; } - - const CoordBBox& getBBox() const {return mExtents; } - - Vec3d unitToWorld(const Vec3d& in) const {return mLocalToWorld.transform( unitToLocal(in) ); } - -private: - LegacyFrustum(){}; - - Vec3d unitToLocal(const Vec3d& U) const { - - // We first find the local space coordinates - // of the unit point projected onto the near - // and far planes of the frustum by using a - // linear combination of the planes basis vectors - Vec3d nearLS = ( U[0] * mFrNearXBasis ) + ( U[1] * mFrNearYBasis ) + mFrNearOrigin; - Vec3d farLS = ( U[0] * mFrFarXBasis ) + ( U[1] * mFrFarYBasis ) + mFrFarOrigin; - - // then we lerp the two ws points in frustum z space - return U[2] * farLS + ( 1.0 - U[2] ) * nearLS; - } - - Vec3d unitToLocalFrustum(const Vec3d& u) const { - Vec3d fzu = mZUnitToLocal.transformH(u); - Vec3d fu = u; - fu[2] = fzu.z(); - return mXYUnitToLocal.transformH(fu); - } - -private: - Mat4d mC2W, mLocalToWorld, mXYUnitToLocal, mZUnitToLocal; - CoordBBox mExtents; - Vec3d mFrNearXBasis, mFrNearYBasis, mFrFarXBasis, mFrFarYBasis; - Vec3d mFrNearOrigin, mFrFarOrigin; - double mNearPlane, mFarPlane; -}; - -} // namespace internal -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_LEGACYFRUSTUM_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Maps.cc b/openvdb_3_0_0_library/math/Maps.cc deleted file mode 100755 index 10852dc..0000000 --- a/openvdb_3_0_0_library/math/Maps.cc +++ /dev/null @@ -1,301 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Maps.h" -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -namespace { - -typedef tbb::mutex Mutex; -typedef Mutex::scoped_lock Lock; - -// Declare this at file scope to ensure thread-safe initialization. -// NOTE: Do *NOT* move this into Maps.h or else we will need to pull in -// Windows.h with things like 'rad2' defined! -Mutex sInitMapRegistryMutex; - -} // unnamed namespace - - -//////////////////////////////////////// - - -MapRegistry* MapRegistry::mInstance = NULL; - - -// Caller is responsible for calling this function serially. -MapRegistry* -MapRegistry::staticInstance() -{ - if (mInstance == NULL) { - OPENVDB_START_THREADSAFE_STATIC_WRITE - mInstance = new MapRegistry(); - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - return mInstance; - } - return mInstance; -} - - -MapRegistry* -MapRegistry::instance() -{ - Lock lock(sInitMapRegistryMutex); - return staticInstance(); -} - - -MapBase::Ptr -MapRegistry::createMap(const Name& name) -{ - Lock lock(sInitMapRegistryMutex); - MapDictionary::const_iterator iter = staticInstance()->mMap.find(name); - - if (iter == staticInstance()->mMap.end()) { - OPENVDB_THROW(LookupError, "Cannot create map of unregistered type " << name); - } - - return (iter->second)(); -} - - -bool -MapRegistry::isRegistered(const Name& name) -{ - Lock lock(sInitMapRegistryMutex); - return (staticInstance()->mMap.find(name) != staticInstance()->mMap.end()); -} - - -void -MapRegistry::registerMap(const Name& name, MapBase::MapFactory factory) -{ - Lock lock(sInitMapRegistryMutex); - - if (staticInstance()->mMap.find(name) != staticInstance()->mMap.end()) { - OPENVDB_THROW(KeyError, "Map type " << name << " is already registered"); - } - - staticInstance()->mMap[name] = factory; -} - - -void -MapRegistry::unregisterMap(const Name& name) -{ - Lock lock(sInitMapRegistryMutex); - staticInstance()->mMap.erase(name); -} - - -void -MapRegistry::clear() -{ - Lock lock(sInitMapRegistryMutex); - staticInstance()->mMap.clear(); -} - - -//////////////////////////////////////// - -// Utility methods for decomposition - - -SymmetricMap::Ptr -createSymmetricMap(const Mat3d& m) -{ - // test that the mat3 is a rotation || reflection - if (!isSymmetric(m)) { - OPENVDB_THROW(ArithmeticError, - "3x3 Matrix initializing symmetric map was not symmetric"); - } - Vec3d eigenValues; - Mat3d Umatrix; - - bool converged = math::diagonalizeSymmetricMatrix(m, Umatrix, eigenValues); - if (!converged) { - OPENVDB_THROW(ArithmeticError, "Diagonalization of the symmetric matrix failed"); - } - - UnitaryMap rotation(Umatrix); - ScaleMap diagonal(eigenValues); - CompoundMap first(rotation, diagonal); - - UnitaryMap rotationInv(Umatrix.transpose()); - return SymmetricMap::Ptr( new SymmetricMap(first, rotationInv)); -} - - -PolarDecomposedMap::Ptr -createPolarDecomposedMap(const Mat3d& m) -{ - // Because our internal libary left-multiplies vectors against matrices - // we are constructing M = Symmetric * Unitary instead of the more - // standard M = Unitary * Symmetric - Mat3d unitary, symmetric, mat3 = m.transpose(); - - // factor mat3 = U * S where U is unitary and S is symmetric - bool gotPolar = math::polarDecomposition(mat3, unitary, symmetric); - if (!gotPolar) { - OPENVDB_THROW(ArithmeticError, "Polar decomposition of transform failed"); - } - // put the result in a polar map and then copy it into the output polar - UnitaryMap unitary_map(unitary.transpose()); - SymmetricMap::Ptr symmetric_map = createSymmetricMap(symmetric); - - return PolarDecomposedMap::Ptr(new PolarDecomposedMap(*symmetric_map, unitary_map)); -} - - -FullyDecomposedMap::Ptr -createFullyDecomposedMap(const Mat4d& m) -{ - if (!isAffine(m)) { - OPENVDB_THROW(ArithmeticError, - "4x4 Matrix initializing Decomposition map was not affine"); - } - - TranslationMap translate(m.getTranslation()); - PolarDecomposedMap::Ptr polar = createPolarDecomposedMap(m.getMat3()); - - UnitaryAndTranslationMap rotationAndTranslate(polar->secondMap(), translate); - - return FullyDecomposedMap::Ptr(new FullyDecomposedMap(polar->firstMap(), rotationAndTranslate)); -} - - -MapBase::Ptr -simplify(AffineMap::Ptr affine) -{ - if (affine->isScale()) { // can be simplified into a ScaleMap - - Vec3d scale = affine->applyMap(Vec3d(1,1,1)); - if (isApproxEqual(scale[0], scale[1]) && isApproxEqual(scale[0], scale[2])) { - return MapBase::Ptr(new UniformScaleMap(scale[0])); - } else { - return MapBase::Ptr(new ScaleMap(scale)); - } - - } else if (affine->isScaleTranslate()) { // can be simplified into a ScaleTranslateMap - - Vec3d translate = affine->applyMap(Vec3d(0,0,0)); - Vec3d scale = affine->applyMap(Vec3d(1,1,1)) - translate; - - if (isApproxEqual(scale[0], scale[1]) && isApproxEqual(scale[0], scale[2])) { - return MapBase::Ptr(new UniformScaleTranslateMap(scale[0], translate)); - } else { - return MapBase::Ptr(new ScaleTranslateMap(scale, translate)); - } - } - - // could not simplify the general Affine map. - return boost::static_pointer_cast(affine); -} - - -Mat4d -approxInverse(const Mat4d& mat4d) -{ - if (std::abs(mat4d.det()) >= 3 * math::Tolerance::value()) { - try { - return mat4d.inverse(); - } catch (ArithmeticError& ) { - // Mat4 code couldn't invert. - } - } - - const Mat3d mat3 = mat4d.getMat3(); - const Mat3d mat3T = mat3.transpose(); - const Vec3d trans = mat4d.getTranslation(); - - // absolute tolerance used for the symmetric test. - const double tol = 1.e-6; - - // only create the pseudoInverse for symmetric - bool symmetric = true; - for (int i = 0; i < 3; ++i ) { - for (int j = 0; j < 3; ++j ) { - if (!isApproxEqual(mat3[i][j], mat3T[i][j], tol)) { - symmetric = false; - } - } - } - - if (!symmetric) { - - // not symmetric, so just zero out the mat3 inverse and reverse the translation - - Mat4d result = Mat4d::zero(); - result.setTranslation(-trans); - result[3][3] = 1.f; - return result; - - } else { - - // compute the pseudo inverse - - Mat3d eigenVectors; - Vec3d eigenValues; - - diagonalizeSymmetricMatrix(mat3, eigenVectors, eigenValues); - - Mat3d d = Mat3d::identity(); - for (int i = 0; i < 3; ++i ) { - if (std::abs(eigenValues[i]) < 10.0 * math::Tolerance::value()) { - d[i][i] = 0.f; - } else { - d[i][i] = 1.f/eigenValues[i]; - } - } - // assemble the pseudo inverse - - Mat3d pseudoInv = eigenVectors * d * eigenVectors.transpose(); - Vec3d invTrans = -trans * pseudoInv; - - Mat4d result = Mat4d::identity(); - result.setMat3(pseudoInv); - result.setTranslation(invTrans); - - return result; - } -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Maps.h b/openvdb_3_0_0_library/math/Maps.h deleted file mode 100755 index 9b787f2..0000000 --- a/openvdb_3_0_0_library/math/Maps.h +++ /dev/null @@ -1,2685 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Maps.h - -#ifndef OPENVDB_MATH_MAPS_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_MAPS_HAS_BEEN_INCLUDED - -#include "Math.h" -#include "Mat4.h" -#include "Vec3.h" -#include "BBox.h" -#include "Coord.h" -#include // for io::getFormatVersion() -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - -/// Forward declarations of the different map types - -class MapBase; -class ScaleMap; -class TranslationMap; -class ScaleTranslateMap; -class UniformScaleMap; -class UniformScaleTranslateMap; -class AffineMap; -class UnitaryMap; -class NonlinearFrustumMap; - -template class CompoundMap; - -typedef CompoundMap UnitaryAndTranslationMap; -typedef CompoundMap, UnitaryMap> SpectralDecomposedMap; -typedef SpectralDecomposedMap SymmetricMap; -typedef CompoundMap FullyDecomposedMap; -typedef CompoundMap PolarDecomposedMap; - - -//////////////////////////////////////// - -/// Map traits - -template struct is_linear { static const bool value = false; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; -template<> struct is_linear { static const bool value = true; }; - -template struct is_linear > { - static const bool value = is_linear::value && is_linear::value; -}; - - -template struct is_uniform_scale { static const bool value = false; }; -template<> struct is_uniform_scale { static const bool value = true; }; - -template struct is_uniform_scale_translate { static const bool value = false; }; -template<> struct is_uniform_scale_translate { static const bool value = true; }; -template<> struct is_uniform_scale_translate { - static const bool value = true; -}; - - -template struct is_scale { static const bool value = false; }; -template<> struct is_scale { static const bool value = true; }; - -template struct is_scale_translate { static const bool value = false; }; -template<> struct is_scale_translate { static const bool value = true; }; - - -template struct is_uniform_diagonal_jacobian { - static const bool value = is_uniform_scale::value || is_uniform_scale_translate::value; -}; - -template struct is_diagonal_jacobian { - static const bool value = is_scale::value || is_scale_translate::value; -}; - - -//////////////////////////////////////// - -/// Utility methods - -/// @brief Create a SymmetricMap from a symmetric matrix. -/// Decomposes the map into Rotation Diagonal Rotation^T -OPENVDB_API boost::shared_ptr createSymmetricMap(const Mat3d& m); - - -/// @brief General decomposition of a Matrix into a Unitary (e.g. rotation) -/// following a Symmetric (e.g. stretch & shear) -OPENVDB_API boost::shared_ptr createFullyDecomposedMap(const Mat4d& m); - - -/// @brief Decomposes a general linear into translation following polar decomposition. -/// -/// T U S where: -/// -/// T: Translation -/// U: Unitary (rotation or reflection) -/// S: Symmetric -/// -/// @note: the Symmetric is automatically decomposed into Q D Q^T, where -/// Q is rotation and D is diagonal. -OPENVDB_API boost::shared_ptr createPolarDecomposedMap(const Mat3d& m); - - -/// @brief reduces an AffineMap to a ScaleMap or a ScaleTranslateMap when it can -OPENVDB_API boost::shared_ptr simplify(boost::shared_ptr affine); - -/// @brief Returns the left pseudoInverse of the input matrix when the 3x3 part is symmetric -/// otherwise it zeros the 3x3 and reverses the translation. -OPENVDB_API Mat4d approxInverse(const Mat4d& mat); - - -//////////////////////////////////////// - - -/// @brief Abstract base class for maps -class OPENVDB_API MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - typedef Ptr (*MapFactory)(); - - virtual ~MapBase(){} - - virtual boost::shared_ptr getAffineMap() const = 0; - - /// Return the name of this map's concrete type (e.g., @c "AffineMap"). - virtual Name type() const = 0; - - /// Return @c true if this map is of concrete type @c MapT (e.g., AffineMap). - template bool isType() const { return this->type() == MapT::mapType(); } - - /// Return @c true if this map is equal to the given map. - virtual bool isEqual(const MapBase& other) const = 0; - - /// Return @c true if this map is linear. - virtual bool isLinear() const = 0; - /// Return @c true if the spacing between the image of latice is uniform in all directions - virtual bool hasUniformScale() const = 0; - - virtual Vec3d applyMap(const Vec3d& in) const = 0; - virtual Vec3d applyInverseMap(const Vec3d& in) const = 0; - - //@{ - /// @brief Apply the Inverse Jacobian Transpose of this map to a vector. - /// For a linear map this is equivalent to applying the transpose of - /// inverse map excluding translation. - virtual Vec3d applyIJT(const Vec3d& in) const = 0; - virtual Vec3d applyIJT(const Vec3d& in, const Vec3d& domainPos) const = 0; - //@} - - virtual Mat3d applyIJC(const Mat3d& m) const = 0; - virtual Mat3d applyIJC(const Mat3d& m, const Vec3d& v, const Vec3d& domainPos) const = 0; - - - virtual double determinant() const = 0; - virtual double determinant(const Vec3d&) const = 0; - - - //@{ - /// @brief Method to return the local size of a voxel. - /// When a location is specified as an argument, it is understood to be - /// be in the domain of the map (i.e. index space) - virtual Vec3d voxelSize() const = 0; - virtual Vec3d voxelSize(const Vec3d&) const = 0; - //@} - - virtual void read(std::istream&) = 0; - virtual void write(std::ostream&) const = 0; - - virtual std::string str() const = 0; - - virtual MapBase::Ptr copy() const = 0; - - //@{ - /// @brief Methods to update the map - virtual MapBase::Ptr preRotate(double radians, Axis axis = X_AXIS) const = 0; - virtual MapBase::Ptr preTranslate(const Vec3d&) const = 0; - virtual MapBase::Ptr preScale(const Vec3d&) const = 0; - virtual MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const = 0; - - virtual MapBase::Ptr postRotate(double radians, Axis axis = X_AXIS) const = 0; - virtual MapBase::Ptr postTranslate(const Vec3d&) const = 0; - virtual MapBase::Ptr postScale(const Vec3d&) const = 0; - virtual MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const = 0; - //@} - - //@{ - /// @brief Apply the Jacobian of this map to a vector. - /// For a linear map this is equivalent to applying the map excluding translation. - /// @warning Houdini 12.5 uses an earlier version of OpenVDB, and maps created - /// with that version lack a virtual table entry for this method. Do not call - /// this method from Houdini 12.5. - virtual Vec3d applyJacobian(const Vec3d& in) const = 0; - virtual Vec3d applyJacobian(const Vec3d& in, const Vec3d& domainPos) const = 0; - //@} - - //@{ - /// @brief Apply the InverseJacobian of this map to a vector. - /// For a linear map this is equivalent to applying the map inverse excluding translation. - /// @warning Houdini 12.5 uses an earlier version of OpenVDB, and maps created - /// with that version lack a virtual table entry for this method. Do not call - /// this method from Houdini 12.5. - virtual Vec3d applyInverseJacobian(const Vec3d& in) const = 0; - virtual Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d& domainPos) const = 0; - //@} - - - //@{ - /// @brief Apply the Jacobian transpose of this map to a vector. - /// For a linear map this is equivalent to applying the transpose of the map - /// excluding translation. - /// @warning Houdini 12.5 uses an earlier version of OpenVDB, and maps created - /// with that version lack a virtual table entry for this method. Do not call - /// this method from Houdini 12.5. - virtual Vec3d applyJT(const Vec3d& in) const = 0; - virtual Vec3d applyJT(const Vec3d& in, const Vec3d& domainPos) const = 0; - //@} - - /// @brief Return a new map representing the inverse of this map. - /// @throw NotImplementedError if the map is a NonlinearFrustumMap. - /// @warning Houdini 12.5 uses an earlier version of OpenVDB, and maps created - /// with that version lack a virtual table entry for this method. Do not call - /// this method from Houdini 12.5. - virtual MapBase::Ptr inverseMap() const = 0; - -protected: - MapBase() {} - - template - static bool isEqualBase(const MapT& self, const MapBase& other) - { - return other.isType() && (self == *static_cast(&other)); - } -}; - - -//////////////////////////////////////// - - -/// @brief Threadsafe singleton object for accessing the map type-name dictionary. -/// Associates a map type-name with a factory function. -class OPENVDB_API MapRegistry -{ -public: - typedef std::map MapDictionary; - - static MapRegistry* instance(); - - /// Create a new map of the given (registered) type name. - static MapBase::Ptr createMap(const Name&); - - /// Return @c true if the given map type name is registered. - static bool isRegistered(const Name&); - - /// Register a map type along with a factory function. - static void registerMap(const Name&, MapBase::MapFactory); - - /// Remove a map type from the registry. - static void unregisterMap(const Name&); - - /// Clear the map type registry. - static void clear(); - -private: - MapRegistry() {} - - static MapRegistry* staticInstance(); - - static MapRegistry* mInstance; - - MapDictionary mMap; -}; - - -//////////////////////////////////////// - - -/// @brief A general linear transform using homogeneous coordinates to perform -/// rotation, scaling, shear and translation -class OPENVDB_API AffineMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - AffineMap(): - mMatrix(Mat4d::identity()), - mMatrixInv(Mat4d::identity()), - mJacobianInv(Mat3d::identity()), - mDeterminant(1), - mVoxelSize(Vec3d(1,1,1)), - mIsDiagonal(true), - mIsIdentity(true) - // the default constructor for translation is zero - { - } - - AffineMap(const Mat3d& m) - { - Mat4d mat4(Mat4d::identity()); - mat4.setMat3(m); - mMatrix = mat4; - updateAcceleration(); - } - - AffineMap(const Mat4d& m): mMatrix(m) - { - if (!isAffine(m)) { - OPENVDB_THROW(ArithmeticError, - "Tried to initialize an affine transform from a non-affine 4x4 matrix"); - } - updateAcceleration(); - } - - AffineMap(const AffineMap& other): - MapBase(other), - mMatrix(other.mMatrix), - mMatrixInv(other.mMatrixInv), - mJacobianInv(other.mJacobianInv), - mDeterminant(other.mDeterminant), - mVoxelSize(other.mVoxelSize), - mIsDiagonal(other.mIsDiagonal), - mIsIdentity(other.mIsIdentity) - { - } - - /// @brief constructor that merges the matrixes for two affine maps - AffineMap(const AffineMap& first, const AffineMap& second): - mMatrix(first.mMatrix * second.mMatrix) - { - updateAcceleration(); - } - - ~AffineMap() {} - - /// Return a MapBase::Ptr to a new AffineMap - static MapBase::Ptr create() { return MapBase::Ptr(new AffineMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new AffineMap(*this)); } - - MapBase::Ptr inverseMap() const { return MapBase::Ptr(new AffineMap(mMatrixInv)); } - - static bool isRegistered() { return MapRegistry::isRegistered(AffineMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - AffineMap::mapType(), - AffineMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("AffineMap"); } - - /// Return @c true (an AffineMap is always linear). - bool isLinear() const { return true; } - - /// Return @c false ( test if this is unitary with translation ) - bool hasUniformScale() const - { - Mat3d mat = mMatrix.getMat3(); - const double det = mat.det(); - if (isApproxEqual(det, double(0))) { - return false; - } else { - mat *= (1.f / pow(std::abs(det),1./3.)); - return isUnitary(mat); - } - } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const AffineMap& other) const - { - // the Mat.eq() is approximate - if (!mMatrix.eq(other.mMatrix)) { return false; } - if (!mMatrixInv.eq(other.mMatrixInv)) { return false; } - return true; - } - - bool operator!=(const AffineMap& other) const { return !(*this == other); } - - AffineMap& operator=(const AffineMap& other) - { - mMatrix = other.mMatrix; - mMatrixInv = other.mMatrixInv; - - mJacobianInv = other.mJacobianInv; - mDeterminant = other.mDeterminant; - mVoxelSize = other.mVoxelSize; - mIsDiagonal = other.mIsDiagonal; - mIsIdentity = other.mIsIdentity; - return *this; - } - /// Return the image of @c in under the map - Vec3d applyMap(const Vec3d& in) const { return in * mMatrix; } - /// Return the pre-image of @c in under the map - Vec3d applyInverseMap(const Vec3d& in) const {return in * mMatrixInv; } - - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in, const Vec3d&) const { return applyJacobian(in); } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in) const { return mMatrix.transform3x3(in); } - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d&) const { return applyInverseJacobian(in); } - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return mMatrixInv.transform3x3(in); } - - /// Return the Jacobian Transpose of the map applied to @a in. - /// This tranforms range-space gradients to domain-space gradients - Vec3d applyJT(const Vec3d& in, const Vec3d&) const { return applyJT(in); } - /// Return the Jacobian Transpose of the map applied to @a in. - Vec3d applyJT(const Vec3d& in) const { - const double* m = mMatrix.asPointer(); - return Vec3d( m[ 0] * in[0] + m[ 1] * in[1] + m[ 2] * in[2], - m[ 4] * in[0] + m[ 5] * in[1] + m[ 6] * in[2], - m[ 8] * in[0] + m[ 9] * in[1] + m[10] * in[2] ); - } - - /// Return the transpose of the inverse Jacobian of the map applied to @a in. - Vec3d applyIJT(const Vec3d& in, const Vec3d&) const { return applyIJT(in); } - /// Return the transpose of the inverse Jacobian of the map applied to @c in - Vec3d applyIJT(const Vec3d& in) const { return in * mJacobianInv; } - /// Return the Jacobian Curvature: zero for a linear map - Mat3d applyIJC(const Mat3d& m) const { - return mJacobianInv.transpose()* m * mJacobianInv; - } - Mat3d applyIJC(const Mat3d& in, const Vec3d& , const Vec3d& ) const { - return applyIJC(in); - } - /// Return the determinant of the Jacobian, ignores argument - double determinant(const Vec3d& ) const { return determinant(); } - /// Return the determinant of the Jacobian - double determinant() const { return mDeterminant; } - - //@{ - /// @brief Return the lengths of the images of the segments - /// (0,0,0)-(1,0,0), (0,0,0)-(0,1,0) and (0,0,0)-(0,0,1). - Vec3d voxelSize() const { return mVoxelSize; } - Vec3d voxelSize(const Vec3d&) const { return voxelSize(); } - //@} - - /// Return @c true if the underlying matrix is approximately an identity - bool isIdentity() const { return mIsIdentity; } - /// Return @c true if the underylying matrix is diagonal - bool isDiagonal() const { return mIsDiagonal; } - /// Return @c true if the map is equivalent to a ScaleMap - bool isScale() const { return isDiagonal(); } - /// Return @c true if the map is equivalent to a ScaleTranslateMap - bool isScaleTranslate() const { return math::isDiagonal(mMatrix.getMat3()); } - - - // Methods that modify the existing affine map - - //@{ - /// @brief Modify the existing affine map by pre-applying the given operation. - void accumPreRotation(Axis axis, double radians) - { - mMatrix.preRotate(axis, radians); - updateAcceleration(); - } - void accumPreScale(const Vec3d& v) - { - mMatrix.preScale(v); - updateAcceleration(); - } - void accumPreTranslation(const Vec3d& v) - { - mMatrix.preTranslate(v); - updateAcceleration(); - } - void accumPreShear(Axis axis0, Axis axis1, double shear) - { - mMatrix.preShear(axis0, axis1, shear); - updateAcceleration(); - } - //@} - - - //@{ - /// @brief Modify the existing affine map by post-applying the given operation. - void accumPostRotation(Axis axis, double radians) - { - mMatrix.postRotate(axis, radians); - updateAcceleration(); - } - void accumPostScale(const Vec3d& v) - { - mMatrix.postScale(v); - updateAcceleration(); - } - void accumPostTranslation(const Vec3d& v) - { - mMatrix.postTranslate(v); - updateAcceleration(); - } - void accumPostShear(Axis axis0, Axis axis1, double shear) - { - mMatrix.postShear(axis0, axis1, shear); - updateAcceleration(); - } - //@} - - - /// read serialization - void read(std::istream& is) - { - mMatrix.read(is); - updateAcceleration(); - } - - /// write serialization - void write(std::ostream& os) const - { - mMatrix.write(os); - } - - /// string serialization, useful for debugging - std::string str() const - { - std::ostringstream buffer; - buffer << " - mat4:\n" << mMatrix.str() << std::endl; - buffer << " - voxel dimensions: " << mVoxelSize << std::endl; - return buffer.str(); - } - - /// on-demand decomposition of the affine map - boost::shared_ptr createDecomposedMap() - { - return createFullyDecomposedMap(mMatrix); - } - - /// Return AffineMap::Ptr to a deep copy of the current AffineMap - AffineMap::Ptr getAffineMap() const { return AffineMap::Ptr(new AffineMap(*this)); } - - /// Return AffineMap::Ptr to the inverse of this map - AffineMap::Ptr inverse() const { return AffineMap::Ptr(new AffineMap(mMatrixInv)); } - - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropraite operation. - MapBase::Ptr preRotate(double radians, Axis axis = X_AXIS) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreRotation(axis, radians); - return simplify(affineMap); - } - MapBase::Ptr preTranslate(const Vec3d& t) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreTranslation(t); - return boost::static_pointer_cast(affineMap); - } - MapBase::Ptr preScale(const Vec3d& s) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreScale(s); - return boost::static_pointer_cast(affineMap); - } - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of postfixing the appropraite operation. - MapBase::Ptr postRotate(double radians, Axis axis = X_AXIS) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostRotation(axis, radians); - return simplify(affineMap); - } - MapBase::Ptr postTranslate(const Vec3d& t) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostTranslation(t); - return boost::static_pointer_cast(affineMap); - } - MapBase::Ptr postScale(const Vec3d& s) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostScale(s); - return boost::static_pointer_cast(affineMap); - } - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - /// Return the matrix representation of this AffineMap - Mat4d getMat4() const { return mMatrix;} - const Mat4d& getConstMat4() const {return mMatrix;} - const Mat3d& getConstJacobianInv() const {return mJacobianInv;} - -private: - void updateAcceleration() { - Mat3d mat3 = mMatrix.getMat3(); - mDeterminant = mat3.det(); - - if (std::abs(mDeterminant) < (3.0 * math::Tolerance::value())) { - OPENVDB_THROW(ArithmeticError, - "Tried to initialize an affine transform from a nearly singular matrix"); - } - mMatrixInv = mMatrix.inverse(); - mJacobianInv = mat3.inverse().transpose(); - mIsDiagonal = math::isDiagonal(mMatrix); - mIsIdentity = math::isIdentity(mMatrix); - Vec3d pos = applyMap(Vec3d(0,0,0)); - mVoxelSize(0) = (applyMap(Vec3d(1,0,0)) - pos).length(); - mVoxelSize(1) = (applyMap(Vec3d(0,1,0)) - pos).length(); - mVoxelSize(2) = (applyMap(Vec3d(0,0,1)) - pos).length(); - } - - // the underlying matrix - Mat4d mMatrix; - - // stored for acceleration - Mat4d mMatrixInv; - Mat3d mJacobianInv; - double mDeterminant; - Vec3d mVoxelSize; - bool mIsDiagonal, mIsIdentity; -}; // class AffineMap - - -//////////////////////////////////////// - - -/// @brief A specialized Affine transform that scales along the principal axis -/// the scaling need not be uniform in the three-directions -class OPENVDB_API ScaleMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - ScaleMap(): MapBase(), mScaleValues(Vec3d(1,1,1)), mVoxelSize(Vec3d(1,1,1)), - mScaleValuesInverse(Vec3d(1,1,1)), - mInvScaleSqr(1,1,1), mInvTwiceScale(0.5,0.5,0.5){} - - ScaleMap(const Vec3d& scale): - MapBase(), - mScaleValues(scale), - mVoxelSize(Vec3d(std::abs(scale(0)),std::abs(scale(1)), std::abs(scale(2)))) - { - double determinant = scale[0]* scale[1] * scale[2]; - if (std::abs(determinant) < 3.0 * math::Tolerance::value()) { - OPENVDB_THROW(ArithmeticError, "Non-zero scale values required"); - } - mScaleValuesInverse = 1.0 / mScaleValues; - mInvScaleSqr = mScaleValuesInverse * mScaleValuesInverse; - mInvTwiceScale = mScaleValuesInverse / 2; - } - - ScaleMap(const ScaleMap& other): - MapBase(), - mScaleValues(other.mScaleValues), - mVoxelSize(other.mVoxelSize), - mScaleValuesInverse(other.mScaleValuesInverse), - mInvScaleSqr(other.mInvScaleSqr), - mInvTwiceScale(other.mInvTwiceScale) - { - } - - ~ScaleMap() {} - - /// Return a MapBase::Ptr to a new ScaleMap - static MapBase::Ptr create() { return MapBase::Ptr(new ScaleMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new ScaleMap(*this)); } - - MapBase::Ptr inverseMap() const { return MapBase::Ptr(new ScaleMap(mScaleValuesInverse)); } - - static bool isRegistered() { return MapRegistry::isRegistered(ScaleMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - ScaleMap::mapType(), - ScaleMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("ScaleMap"); } - - /// Return @c true (a ScaleMap is always linear). - bool isLinear() const { return true; } - - /// Return @c true if the values have the same magitude (eg. -1, 1, -1 would be a rotation). - bool hasUniformScale() const - { - bool value = isApproxEqual( - std::abs(mScaleValues.x()), std::abs(mScaleValues.y()), double(5e-7)); - value = value && isApproxEqual( - std::abs(mScaleValues.x()), std::abs(mScaleValues.z()), double(5e-7)); - return value; - } - - /// Return the image of @c in under the map - Vec3d applyMap(const Vec3d& in) const - { - return Vec3d( - in.x() * mScaleValues.x(), - in.y() * mScaleValues.y(), - in.z() * mScaleValues.z()); - } - /// Return the pre-image of @c in under the map - Vec3d applyInverseMap(const Vec3d& in) const - { - return Vec3d( - in.x() * mScaleValuesInverse.x(), - in.y() * mScaleValuesInverse.y(), - in.z() * mScaleValuesInverse.z()); - } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in, const Vec3d&) const { return applyJacobian(in); } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in) const { return applyMap(in); } - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d&) const { return applyInverseJacobian(in); } - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return applyInverseMap(in); } - - /// Return the Jacobian Transpose of the map applied to @a in. - /// This tranforms range-space gradients to domain-space gradients - Vec3d applyJT(const Vec3d& in, const Vec3d&) const { return applyJT(in); } - /// Return the Jacobian Transpose of the map applied to @a in. - Vec3d applyJT(const Vec3d& in) const { return applyMap(in); } - - - - /// @brief Return the transpose of the inverse Jacobian of the map applied to @a in. - /// @details Ignores second argument - Vec3d applyIJT(const Vec3d& in, const Vec3d&) const { return applyIJT(in);} - /// Return the transpose of the inverse Jacobian of the map applied to @c in - Vec3d applyIJT(const Vec3d& in) const { return applyInverseMap(in); } - /// Return the Jacobian Curvature: zero for a linear map - Mat3d applyIJC(const Mat3d& in) const - { - Mat3d tmp; - for (int i = 0; i < 3; i++) { - tmp.setRow(i, in.row(i) * mScaleValuesInverse(i)); - } - for (int i = 0; i < 3; i++) { - tmp.setCol(i, tmp.col(i) * mScaleValuesInverse(i)); - } - return tmp; - } - Mat3d applyIJC(const Mat3d& in, const Vec3d&, const Vec3d&) const { return applyIJC(in); } - /// Return the product of the scale values, ignores argument - double determinant(const Vec3d&) const { return determinant(); } - /// Return the product of the scale values - double determinant() const { return mScaleValues.x() * mScaleValues.y() * mScaleValues.z(); } - - /// Return the scale values that define the map - const Vec3d& getScale() const {return mScaleValues;} - - /// Return the square of the scale. Used to optimize some finite difference calculations - const Vec3d& getInvScaleSqr() const { return mInvScaleSqr; } - /// Return 1/(2 scale). Used to optimize some finite difference calculations - const Vec3d& getInvTwiceScale() const { return mInvTwiceScale; } - /// Return 1/(scale) - const Vec3d& getInvScale() const { return mScaleValuesInverse; } - - //@{ - /// @brief Returns the lengths of the images - /// of the segments - /// \f$(0,0,0)-(1,0,0)\f$, \f$(0,0,0)-(0,1,0)\f$, \f$(0,0,0)-(0,0,1)\f$ - /// this is equivalent to the absolute values of the scale values - Vec3d voxelSize() const { return mVoxelSize; } - Vec3d voxelSize(const Vec3d&) const { return voxelSize(); } - //@} - - /// read serialization - void read(std::istream& is) - { - mScaleValues.read(is); - mVoxelSize.read(is); - mScaleValuesInverse.read(is); - mInvScaleSqr.read(is); - mInvTwiceScale.read(is); - } - /// write serialization - void write(std::ostream& os) const - { - mScaleValues.write(os); - mVoxelSize.write(os); - mScaleValuesInverse.write(os); - mInvScaleSqr.write(os); - mInvTwiceScale.write(os); - } - /// string serialization, useful for debuging - std::string str() const - { - std::ostringstream buffer; - buffer << " - scale: " << mScaleValues << std::endl; - buffer << " - voxel dimensions: " << mVoxelSize << std::endl; - return buffer.str(); - } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const ScaleMap& other) const - { - // ::eq() uses a tolerance - if (!mScaleValues.eq(other.mScaleValues)) { return false; } - return true; - } - - bool operator!=(const ScaleMap& other) const { return !(*this == other); } - - /// Return a AffineMap equivalent to this map - AffineMap::Ptr getAffineMap() const - { - return AffineMap::Ptr(new AffineMap(math::scale(mScaleValues))); - } - - - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropraite operation to the existing map - MapBase::Ptr preRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreRotation(axis, radians); - return simplify(affineMap); - } - - MapBase::Ptr preTranslate(const Vec3d& tr) const; - - MapBase::Ptr preScale(const Vec3d& v) const; - - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropraite operation to the existing map. - MapBase::Ptr postRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostRotation(axis, radians); - return simplify(affineMap); - } - - MapBase::Ptr postTranslate(const Vec3d& tr) const; - - MapBase::Ptr postScale(const Vec3d& v) const; - - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - -private: - Vec3d mScaleValues, mVoxelSize, mScaleValuesInverse, mInvScaleSqr, mInvTwiceScale; -}; // class ScaleMap - - -/// @brief A specialized Affine transform that scales along the principal axis -/// the scaling is uniform in the three-directions -class OPENVDB_API UniformScaleMap: public ScaleMap -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - UniformScaleMap(): ScaleMap(Vec3d(1,1,1)) {} - UniformScaleMap(double scale): ScaleMap(Vec3d(scale, scale, scale)) {} - UniformScaleMap(const UniformScaleMap& other): ScaleMap(other) {} - ~UniformScaleMap() {} - - /// Return a MapBase::Ptr to a new UniformScaleMap - static MapBase::Ptr create() { return MapBase::Ptr(new UniformScaleMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new UniformScaleMap(*this)); } - - MapBase::Ptr inverseMap() const - { - const Vec3d& invScale = getInvScale(); - return MapBase::Ptr(new UniformScaleMap( invScale[0])); - } - - static bool isRegistered() { return MapRegistry::isRegistered(UniformScaleMap::mapType()); } - static void registerMap() - { - MapRegistry::registerMap( - UniformScaleMap::mapType(), - UniformScaleMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("UniformScaleMap"); } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const UniformScaleMap& other) const { return ScaleMap::operator==(other); } - bool operator!=(const UniformScaleMap& other) const { return !(*this == other); } - - /// Return a MapBase::Ptr to a UniformScaleTraslateMap that is the result of - /// pre-translation on this map - MapBase::Ptr preTranslate(const Vec3d& tr) const; - - /// Return a MapBase::Ptr to a UniformScaleTraslateMap that is the result of - /// post-translation on this map - MapBase::Ptr postTranslate(const Vec3d& tr) const; - -}; // class UniformScaleMap - - -//////////////////////////////////////// - - -inline MapBase::Ptr -ScaleMap::preScale(const Vec3d& v) const -{ - const Vec3d new_scale(v * mScaleValues); - if (isApproxEqual(new_scale[0],new_scale[1]) && isApproxEqual(new_scale[0],new_scale[2])) { - return MapBase::Ptr(new UniformScaleMap(new_scale[0])); - } else { - return MapBase::Ptr(new ScaleMap(new_scale)); - } -} - - -inline MapBase::Ptr -ScaleMap::postScale(const Vec3d& v) const -{ // pre-post Scale are the same for a scale map - return preScale(v); -} - - -/// @brief A specialized linear transform that performs a translation -class OPENVDB_API TranslationMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - // default constructor is a translation by zero. - TranslationMap(): MapBase(), mTranslation(Vec3d(0,0,0)) {} - TranslationMap(const Vec3d& t): MapBase(), mTranslation(t) {} - TranslationMap(const TranslationMap& other): MapBase(), mTranslation(other.mTranslation) {} - - ~TranslationMap() {} - - /// Return a MapBase::Ptr to a new TranslationMap - static MapBase::Ptr create() { return MapBase::Ptr(new TranslationMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new TranslationMap(*this)); } - - MapBase::Ptr inverseMap() const { return MapBase::Ptr(new TranslationMap(-mTranslation)); } - - static bool isRegistered() { return MapRegistry::isRegistered(TranslationMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - TranslationMap::mapType(), - TranslationMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("TranslationMap"); } - - /// Return @c true (a TranslationMap is always linear). - bool isLinear() const { return true; } - - /// Return @c false (by convention true) - bool hasUniformScale() const { return true; } - - /// Return the image of @c in under the map - Vec3d applyMap(const Vec3d& in) const { return in + mTranslation; } - /// Return the pre-image of @c in under the map - Vec3d applyInverseMap(const Vec3d& in) const { return in - mTranslation; } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in, const Vec3d&) const { return applyJacobian(in); } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in) const { return in; } - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d&) const { return applyInverseJacobian(in); } - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return in; } - - - /// Return the Jacobian Transpose of the map applied to @a in. - /// This tranforms range-space gradients to domain-space gradients - Vec3d applyJT(const Vec3d& in, const Vec3d&) const { return applyJT(in); } - /// Return the Jacobian Transpose of the map applied to @a in. - Vec3d applyJT(const Vec3d& in) const { return in; } - - /// @brief Return the transpose of the inverse Jacobian (Identity for TranslationMap) - /// of the map applied to @c in, ignores second argument - Vec3d applyIJT(const Vec3d& in, const Vec3d& ) const { return applyIJT(in);} - /// @brief Return the transpose of the inverse Jacobian (Identity for TranslationMap) - /// of the map applied to @c in - Vec3d applyIJT(const Vec3d& in) const {return in;} - /// Return the Jacobian Curvature: zero for a linear map - Mat3d applyIJC(const Mat3d& mat) const {return mat;} - Mat3d applyIJC(const Mat3d& mat, const Vec3d&, const Vec3d&) const { return applyIJC(mat); } - - /// Return @c 1 - double determinant(const Vec3d& ) const { return determinant(); } - /// Return @c 1 - double determinant() const { return 1.0; } - - /// Return \f$ (1,1,1) \f$ - Vec3d voxelSize() const { return Vec3d(1,1,1);} - /// Return \f$ (1,1,1) \f$ - Vec3d voxelSize(const Vec3d&) const { return voxelSize();} - - /// Return the translation vector - const Vec3d& getTranslation() const { return mTranslation; } - /// read serialization - void read(std::istream& is) { mTranslation.read(is); } - /// write serialization - void write(std::ostream& os) const { mTranslation.write(os); } - - /// string serialization, useful for debuging - std::string str() const - { - std::ostringstream buffer; - buffer << " - translation: " << mTranslation << std::endl; - return buffer.str(); - } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const TranslationMap& other) const - { - // ::eq() uses a tolerance - return mTranslation.eq(other.mTranslation); - } - - bool operator!=(const TranslationMap& other) const { return !(*this == other); } - - /// Return AffineMap::Ptr to an AffineMap equivalent to *this - AffineMap::Ptr getAffineMap() const - { - Mat4d matrix(Mat4d::identity()); - matrix.setTranslation(mTranslation); - - AffineMap::Ptr affineMap(new AffineMap(matrix)); - return affineMap; - } - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropriate operation. - MapBase::Ptr preRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreRotation(axis, radians); - return simplify(affineMap); - - } - MapBase::Ptr preTranslate(const Vec3d& t) const - { - return MapBase::Ptr(new TranslationMap(t + mTranslation)); - } - - MapBase::Ptr preScale(const Vec3d& v) const; - - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of postfixing the appropriate operation. - MapBase::Ptr postRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostRotation(axis, radians); - return simplify(affineMap); - - } - MapBase::Ptr postTranslate(const Vec3d& t) const - { // post and pre are the same for this - return MapBase::Ptr(new TranslationMap(t + mTranslation)); - } - - MapBase::Ptr postScale(const Vec3d& v) const; - - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - -private: - Vec3d mTranslation; -}; // class TranslationMap - - -//////////////////////////////////////// - - -/// @brief A specialized Affine transform that scales along the principal axis -/// the scaling need not be uniform in the three-directions, and then -/// translates the result. -class OPENVDB_API ScaleTranslateMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - ScaleTranslateMap(): - MapBase(), - mTranslation(Vec3d(0,0,0)), - mScaleValues(Vec3d(1,1,1)), - mVoxelSize(Vec3d(1,1,1)), - mScaleValuesInverse(Vec3d(1,1,1)), - mInvScaleSqr(1,1,1), - mInvTwiceScale(0.5,0.5,0.5) - { - } - - ScaleTranslateMap(const Vec3d& scale, const Vec3d& translate): - MapBase(), - mTranslation(translate), - mScaleValues(scale), - mVoxelSize(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2))) - { - const double determinant = scale[0]* scale[1] * scale[2]; - if (std::abs(determinant) < 3.0 * math::Tolerance::value()) { - OPENVDB_THROW(ArithmeticError, "Non-zero scale values required"); - } - mScaleValuesInverse = 1.0 / mScaleValues; - mInvScaleSqr = mScaleValuesInverse * mScaleValuesInverse; - mInvTwiceScale = mScaleValuesInverse / 2; - } - - ScaleTranslateMap(const ScaleMap& scale, const TranslationMap& translate): - MapBase(), - mTranslation(translate.getTranslation()), - mScaleValues(scale.getScale()), - mVoxelSize(std::abs(mScaleValues(0)), - std::abs(mScaleValues(1)), - std::abs(mScaleValues(2))), - mScaleValuesInverse(1.0 / scale.getScale()) - { - mInvScaleSqr = mScaleValuesInverse * mScaleValuesInverse; - mInvTwiceScale = mScaleValuesInverse / 2; - } - - ScaleTranslateMap(const ScaleTranslateMap& other): - MapBase(), - mTranslation(other.mTranslation), - mScaleValues(other.mScaleValues), - mVoxelSize(other.mVoxelSize), - mScaleValuesInverse(other.mScaleValuesInverse), - mInvScaleSqr(other.mInvScaleSqr), - mInvTwiceScale(other.mInvTwiceScale) - {} - - ~ScaleTranslateMap() {} - - /// Return a MapBase::Ptr to a new ScaleTranslateMap - static MapBase::Ptr create() { return MapBase::Ptr(new ScaleTranslateMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new ScaleTranslateMap(*this)); } - - MapBase::Ptr inverseMap() const - { - return MapBase::Ptr(new ScaleTranslateMap( - mScaleValuesInverse, -mScaleValuesInverse * mTranslation)); - } - - static bool isRegistered() { return MapRegistry::isRegistered(ScaleTranslateMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - ScaleTranslateMap::mapType(), - ScaleTranslateMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("ScaleTranslateMap"); } - - /// Return @c true (a ScaleTranslateMap is always linear). - bool isLinear() const { return true; } - - /// @brief Return @c true if the scale values have the same magnitude - /// (eg. -1, 1, -1 would be a rotation). - bool hasUniformScale() const - { - bool value = isApproxEqual( - std::abs(mScaleValues.x()), std::abs(mScaleValues.y()), double(5e-7)); - value = value && isApproxEqual( - std::abs(mScaleValues.x()), std::abs(mScaleValues.z()), double(5e-7)); - return value; - } - - /// Return the image of @c under the map - Vec3d applyMap(const Vec3d& in) const - { - return Vec3d( - in.x() * mScaleValues.x() + mTranslation.x(), - in.y() * mScaleValues.y() + mTranslation.y(), - in.z() * mScaleValues.z() + mTranslation.z()); - } - /// Return the pre-image of @c under the map - Vec3d applyInverseMap(const Vec3d& in) const - { - return Vec3d( - (in.x() - mTranslation.x() ) * mScaleValuesInverse.x(), - (in.y() - mTranslation.y() ) * mScaleValuesInverse.y(), - (in.z() - mTranslation.z() ) * mScaleValuesInverse.z()); - } - - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in, const Vec3d&) const { return applyJacobian(in); } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in) const { return in * mScaleValues; } - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d&) const { return applyInverseJacobian(in); } - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return in * mScaleValuesInverse; } - - /// Return the Jacobian Transpose of the map applied to @a in. - /// This tranforms range-space gradients to domain-space gradients - Vec3d applyJT(const Vec3d& in, const Vec3d&) const { return applyJT(in); } - /// Return the Jacobian Transpose of the map applied to @a in. - Vec3d applyJT(const Vec3d& in) const { return applyJacobian(in); } - - /// @brief Return the transpose of the inverse Jacobian of the map applied to @a in - /// @details Ignores second argument - Vec3d applyIJT(const Vec3d& in, const Vec3d& ) const { return applyIJT(in);} - /// Return the transpose of the inverse Jacobian of the map applied to @c in - Vec3d applyIJT(const Vec3d& in) const - { - return Vec3d( - in.x() * mScaleValuesInverse.x(), - in.y() * mScaleValuesInverse.y(), - in.z() * mScaleValuesInverse.z()); - } - /// Return the Jacobian Curvature: zero for a linear map - Mat3d applyIJC(const Mat3d& in) const - { - Mat3d tmp; - for (int i=0; i<3; i++){ - tmp.setRow(i, in.row(i)*mScaleValuesInverse(i)); - } - for (int i=0; i<3; i++){ - tmp.setCol(i, tmp.col(i)*mScaleValuesInverse(i)); - } - return tmp; - } - Mat3d applyIJC(const Mat3d& in, const Vec3d&, const Vec3d& ) const { return applyIJC(in); } - - /// Return the product of the scale values, ignores argument - double determinant(const Vec3d& ) const { return determinant(); } - /// Return the product of the scale values - double determinant() const { return mScaleValues.x()*mScaleValues.y()*mScaleValues.z(); } - /// Return the absolute values of the scale values - Vec3d voxelSize() const { return mVoxelSize;} - /// Return the absolute values of the scale values, ignores - ///argument - Vec3d voxelSize(const Vec3d&) const { return voxelSize();} - - /// Returns the scale values - const Vec3d& getScale() const { return mScaleValues; } - /// Returns the translation - const Vec3d& getTranslation() const { return mTranslation; } - - /// Return the square of the scale. Used to optimize some finite difference calculations - const Vec3d& getInvScaleSqr() const {return mInvScaleSqr;} - /// Return 1/(2 scale). Used to optimize some finite difference calculations - const Vec3d& getInvTwiceScale() const {return mInvTwiceScale;} - /// Return 1/(scale) - const Vec3d& getInvScale() const {return mScaleValuesInverse; } - - /// read serialization - void read(std::istream& is) - { - mTranslation.read(is); - mScaleValues.read(is); - mVoxelSize.read(is); - mScaleValuesInverse.read(is); - mInvScaleSqr.read(is); - mInvTwiceScale.read(is); - } - /// write serialization - void write(std::ostream& os) const - { - mTranslation.write(os); - mScaleValues.write(os); - mVoxelSize.write(os); - mScaleValuesInverse.write(os); - mInvScaleSqr.write(os); - mInvTwiceScale.write(os); - } - /// string serialization, useful for debuging - std::string str() const - { - std::ostringstream buffer; - buffer << " - translation: " << mTranslation << std::endl; - buffer << " - scale: " << mScaleValues << std::endl; - buffer << " - voxel dimensions: " << mVoxelSize << std::endl; - return buffer.str(); - } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const ScaleTranslateMap& other) const - { - // ::eq() uses a tolerance - if (!mScaleValues.eq(other.mScaleValues)) { return false; } - if (!mTranslation.eq(other.mTranslation)) { return false; } - return true; - } - - bool operator!=(const ScaleTranslateMap& other) const { return !(*this == other); } - - /// Return AffineMap::Ptr to an AffineMap equivalent to *this - AffineMap::Ptr getAffineMap() const - { - AffineMap::Ptr affineMap(new AffineMap(math::scale(mScaleValues))); - affineMap->accumPostTranslation(mTranslation); - return affineMap; - } - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropraite operation. - MapBase::Ptr preRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreRotation(axis, radians); - return simplify(affineMap); - } - MapBase::Ptr preTranslate(const Vec3d& t) const - { - const Vec3d& s = mScaleValues; - const Vec3d scaled_trans( t.x() * s.x(), - t.y() * s.y(), - t.z() * s.z() ); - return MapBase::Ptr( new ScaleTranslateMap(mScaleValues, mTranslation + scaled_trans)); - } - - MapBase::Ptr preScale(const Vec3d& v) const; - - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of postfixing the appropraite operation. - MapBase::Ptr postRotate(double radians, Axis axis) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostRotation(axis, radians); - return simplify(affineMap); - } - MapBase::Ptr postTranslate(const Vec3d& t) const - { - return MapBase::Ptr( new ScaleTranslateMap(mScaleValues, mTranslation + t)); - } - - MapBase::Ptr postScale(const Vec3d& v) const; - - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - -private: - Vec3d mTranslation, mScaleValues, mVoxelSize, mScaleValuesInverse, - mInvScaleSqr, mInvTwiceScale; -}; // class ScaleTanslateMap - - -inline MapBase::Ptr -ScaleMap::postTranslate(const Vec3d& t) const -{ - return MapBase::Ptr(new ScaleTranslateMap(mScaleValues, t)); -} - - -inline MapBase::Ptr -ScaleMap::preTranslate(const Vec3d& t) const -{ - - const Vec3d& s = mScaleValues; - const Vec3d scaled_trans( t.x() * s.x(), - t.y() * s.y(), - t.z() * s.z() ); - return MapBase::Ptr(new ScaleTranslateMap(mScaleValues, scaled_trans)); -} - - -/// @brief A specialized Affine transform that uniformaly scales along the principal axis -/// and then translates the result. -class OPENVDB_API UniformScaleTranslateMap: public ScaleTranslateMap -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - UniformScaleTranslateMap():ScaleTranslateMap(Vec3d(1,1,1), Vec3d(0,0,0)) {} - UniformScaleTranslateMap(double scale, const Vec3d& translate): - ScaleTranslateMap(Vec3d(scale,scale,scale), translate) {} - UniformScaleTranslateMap(const UniformScaleMap& scale, const TranslationMap& translate): - ScaleTranslateMap(scale.getScale(), translate.getTranslation()) {} - - UniformScaleTranslateMap(const UniformScaleTranslateMap& other):ScaleTranslateMap(other) {} - ~UniformScaleTranslateMap() {} - - /// Return a MapBase::Ptr to a new UniformScaleTranslateMap - static MapBase::Ptr create() { return MapBase::Ptr(new UniformScaleTranslateMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new UniformScaleTranslateMap(*this)); } - - MapBase::Ptr inverseMap() const - { - const Vec3d& scaleInv = getInvScale(); - const Vec3d& trans = getTranslation(); - return MapBase::Ptr(new UniformScaleTranslateMap(scaleInv[0], -scaleInv[0] * trans)); - } - - static bool isRegistered() - { - return MapRegistry::isRegistered(UniformScaleTranslateMap::mapType()); - } - - static void registerMap() - { - MapRegistry::registerMap( - UniformScaleTranslateMap::mapType(), - UniformScaleTranslateMap::create); - } - - Name type() const { return mapType(); } - static Name mapType() { return Name("UniformScaleTranslateMap"); } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const UniformScaleTranslateMap& other) const - { - return ScaleTranslateMap::operator==(other); - } - bool operator!=(const UniformScaleTranslateMap& other) const { return !(*this == other); } - - /// @brief Return a MapBase::Ptr to a UniformScaleTranslateMap that is - /// the result of prepending translation on this map. - MapBase::Ptr preTranslate(const Vec3d& t) const - { - const double scale = this->getScale().x(); - const Vec3d new_trans = this->getTranslation() + scale * t; - return MapBase::Ptr( new UniformScaleTranslateMap(scale, new_trans)); - } - - /// @brief Return a MapBase::Ptr to a UniformScaleTranslateMap that is - /// the result of postfixing translation on this map. - MapBase::Ptr postTranslate(const Vec3d& t) const - { - const double scale = this->getScale().x(); - return MapBase::Ptr( new UniformScaleTranslateMap(scale, this->getTranslation() + t)); - } -}; // class UniformScaleTanslateMap - - -inline MapBase::Ptr -UniformScaleMap::postTranslate(const Vec3d& t) const -{ - const double scale = this->getScale().x(); - return MapBase::Ptr(new UniformScaleTranslateMap(scale, t)); -} - - -inline MapBase::Ptr -UniformScaleMap::preTranslate(const Vec3d& t) const -{ - const double scale = this->getScale().x(); - return MapBase::Ptr(new UniformScaleTranslateMap(scale, scale*t)); -} - - -inline MapBase::Ptr -TranslationMap::preScale(const Vec3d& v) const -{ - if (isApproxEqual(v[0],v[1]) && isApproxEqual(v[0],v[2])) { - return MapBase::Ptr(new UniformScaleTranslateMap(v[0], mTranslation)); - } else { - return MapBase::Ptr(new ScaleTranslateMap(v, mTranslation)); - } -} - - -inline MapBase::Ptr -TranslationMap::postScale(const Vec3d& v) const -{ - if (isApproxEqual(v[0],v[1]) && isApproxEqual(v[0],v[2])) { - return MapBase::Ptr(new UniformScaleTranslateMap(v[0], v[0]*mTranslation)); - } else { - const Vec3d trans(mTranslation.x()*v.x(), - mTranslation.y()*v.y(), - mTranslation.z()*v.z()); - return MapBase::Ptr(new ScaleTranslateMap(v, trans)); - } -} - - -inline MapBase::Ptr -ScaleTranslateMap::preScale(const Vec3d& v) const -{ - const Vec3d new_scale( v * mScaleValues ); - if (isApproxEqual(new_scale[0],new_scale[1]) && isApproxEqual(new_scale[0],new_scale[2])) { - return MapBase::Ptr( new UniformScaleTranslateMap(new_scale[0], mTranslation)); - } else { - return MapBase::Ptr( new ScaleTranslateMap(new_scale, mTranslation)); - } -} - - -inline MapBase::Ptr -ScaleTranslateMap::postScale(const Vec3d& v) const -{ - const Vec3d new_scale( v * mScaleValues ); - const Vec3d new_trans( mTranslation.x()*v.x(), - mTranslation.y()*v.y(), - mTranslation.z()*v.z() ); - - if (isApproxEqual(new_scale[0],new_scale[1]) && isApproxEqual(new_scale[0],new_scale[2])) { - return MapBase::Ptr( new UniformScaleTranslateMap(new_scale[0], new_trans)); - } else { - return MapBase::Ptr( new ScaleTranslateMap(new_scale, new_trans)); - } -} - - -//////////////////////////////////////// - - -/// @brief A specialized linear transform that performs a unitary maping -/// i.e. rotation and or reflection. -class OPENVDB_API UnitaryMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - /// default constructor makes an Idenity. - UnitaryMap(): mAffineMap(Mat4d::identity()) - { - } - - UnitaryMap(const Vec3d& axis, double radians) - { - Mat3d matrix; - matrix.setToRotation(axis, radians); - mAffineMap = AffineMap(matrix); - } - - UnitaryMap(Axis axis, double radians) - { - Mat4d matrix; - matrix.setToRotation(axis, radians); - mAffineMap = AffineMap(matrix); - } - - UnitaryMap(const Mat3d& m) - { - // test that the mat3 is a rotation || reflection - if (!isUnitary(m)) { - OPENVDB_THROW(ArithmeticError, "Matrix initializing unitary map was not unitary"); - } - - Mat4d matrix(Mat4d::identity()); - matrix.setMat3(m); - mAffineMap = AffineMap(matrix); - } - - UnitaryMap(const Mat4d& m) - { - if (!isInvertible(m)) { - OPENVDB_THROW(ArithmeticError, - "4x4 Matrix initializing unitary map was not unitary: not invertible"); - } - - if (!isAffine(m)) { - OPENVDB_THROW(ArithmeticError, - "4x4 Matrix initializing unitary map was not unitary: not affine"); - } - - if (hasTranslation(m)) { - OPENVDB_THROW(ArithmeticError, - "4x4 Matrix initializing unitary map was not unitary: had translation"); - } - - if (!isUnitary(m.getMat3())) { - OPENVDB_THROW(ArithmeticError, - "4x4 Matrix initializing unitary map was not unitary"); - } - - mAffineMap = AffineMap(m); - } - - UnitaryMap(const UnitaryMap& other): - MapBase(other), - mAffineMap(other.mAffineMap) - { - } - - UnitaryMap(const UnitaryMap& first, const UnitaryMap& second): - mAffineMap(*(first.getAffineMap()), *(second.getAffineMap())) - { - } - - ~UnitaryMap() {} - /// Return a MapBase::Ptr to a new UnitaryMap - static MapBase::Ptr create() { return MapBase::Ptr(new UnitaryMap()); } - /// Returns a MapBase::Ptr to a deep copy of *this - MapBase::Ptr copy() const { return MapBase::Ptr(new UnitaryMap(*this)); } - - MapBase::Ptr inverseMap() const - { - return MapBase::Ptr(new UnitaryMap(mAffineMap.getMat4().inverse())); - } - - static bool isRegistered() { return MapRegistry::isRegistered(UnitaryMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - UnitaryMap::mapType(), - UnitaryMap::create); - } - - /// Return @c UnitaryMap - Name type() const { return mapType(); } - /// Return @c UnitaryMap - static Name mapType() { return Name("UnitaryMap"); } - - /// Return @c true (a UnitaryMap is always linear). - bool isLinear() const { return true; } - - /// Return @c false (by convention true) - bool hasUniformScale() const { return true; } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const UnitaryMap& other) const - { - // compare underlying linear map. - if (mAffineMap!=other.mAffineMap) return false; - return true; - } - - bool operator!=(const UnitaryMap& other) const { return !(*this == other); } - /// Return the image of @c in under the map - Vec3d applyMap(const Vec3d& in) const { return mAffineMap.applyMap(in); } - /// Return the pre-image of @c in under the map - Vec3d applyInverseMap(const Vec3d& in) const { return mAffineMap.applyInverseMap(in); } - - Vec3d applyJacobian(const Vec3d& in, const Vec3d&) const { return applyJacobian(in); } - /// Return the Jacobian of the map applied to @a in. - Vec3d applyJacobian(const Vec3d& in) const { return mAffineMap.applyJacobian(in); } - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d&) const { return applyInverseJacobian(in); } - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return mAffineMap.applyInverseJacobian(in); } - - - /// Return the Jacobian Transpose of the map applied to @a in. - /// This tranforms range-space gradients to domain-space gradients - Vec3d applyJT(const Vec3d& in, const Vec3d&) const { return applyJT(in); } - /// Return the Jacobian Transpose of the map applied to @a in. - Vec3d applyJT(const Vec3d& in) const { - // The transpose of the unitary map is its inverse - return applyInverseMap(in); - } - - - /// @brief Return the transpose of the inverse Jacobian of the map applied to @a in - /// @details Ignores second argument - Vec3d applyIJT(const Vec3d& in, const Vec3d& ) const { return applyIJT(in);} - /// Return the transpose of the inverse Jacobian of the map applied to @c in - Vec3d applyIJT(const Vec3d& in) const { return mAffineMap.applyIJT(in); } - /// Return the Jacobian Curvature: zero for a linear map - Mat3d applyIJC(const Mat3d& in) const { return mAffineMap.applyIJC(in); } - Mat3d applyIJC(const Mat3d& in, const Vec3d&, const Vec3d& ) const { return applyIJC(in); } - /// Return the determinant of the Jacobian, ignores argument - double determinant(const Vec3d& ) const { return determinant(); } - /// Return the determinant of the Jacobian - double determinant() const { return mAffineMap.determinant(); } - - - /// @brief Returns the lengths of the images - /// of the segments - /// \f$(0,0,0)-(1,0,0)\f$, \f$(0,0,0)-(0,1,0)\f$, - /// \f$(0,0,0)-(0,0,1)\f$ - Vec3d voxelSize() const { return mAffineMap.voxelSize();} - Vec3d voxelSize(const Vec3d&) const { return voxelSize();} - - /// read serialization - void read(std::istream& is) - { - mAffineMap.read(is); - } - - /// write serialization - void write(std::ostream& os) const - { - mAffineMap.write(os); - } - /// string serialization, useful for debuging - std::string str() const - { - std::ostringstream buffer; - buffer << mAffineMap.str(); - return buffer.str(); - } - /// Return AffineMap::Ptr to an AffineMap equivalent to *this - AffineMap::Ptr getAffineMap() const { return AffineMap::Ptr(new AffineMap(mAffineMap)); } - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropraite operation. - MapBase::Ptr preRotate(double radians, Axis axis) const - { - UnitaryMap first(axis, radians); - UnitaryMap::Ptr unitaryMap(new UnitaryMap(first, *this)); - return boost::static_pointer_cast(unitaryMap); - } - MapBase::Ptr preTranslate(const Vec3d& t) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreTranslation(t); - return simplify(affineMap); - } - MapBase::Ptr preScale(const Vec3d& v) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreScale(v); - return simplify(affineMap); - } - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPreShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of postfixing the appropraite operation. - MapBase::Ptr postRotate(double radians, Axis axis) const - { - UnitaryMap second(axis, radians); - UnitaryMap::Ptr unitaryMap(new UnitaryMap(*this, second)); - return boost::static_pointer_cast(unitaryMap); - } - MapBase::Ptr postTranslate(const Vec3d& t) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostTranslation(t); - return simplify(affineMap); - } - MapBase::Ptr postScale(const Vec3d& v) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostScale(v); - return simplify(affineMap); - } - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - AffineMap::Ptr affineMap = getAffineMap(); - affineMap->accumPostShear(axis0, axis1, shear); - return simplify(affineMap); - } - //@} - -private: - AffineMap mAffineMap; -}; // class UnitaryMap - - -//////////////////////////////////////// - - -/// @brief This map is composed of three steps. -/// Frist it will take a box of size (Lx X Ly X Lz) defined by an member data bounding box -/// and map it into a frustum with near plane (1 X Ly/Lx) and precribed depth -/// Then this frustum is transformed by an internal second map: most often a uniform scale, -/// but other affects can be achieved by accumulating translation, shear and rotation: these -/// are all applied to the second map -class OPENVDB_API NonlinearFrustumMap: public MapBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - NonlinearFrustumMap(): - MapBase(), - mBBox(Vec3d(0), Vec3d(1)), - mTaper(1), - mDepth(1) - { - init(); - } - - /// @brief Constructor that takes an index-space bounding box - /// to be mapped into a frustum with a given @a depth and @a taper - /// (defined as ratio of nearplane/farplane). - NonlinearFrustumMap(const BBoxd& bb, double taper, double depth): - MapBase(),mBBox(bb), mTaper(taper), mDepth(depth) - { - init(); - } - - /// @brief Constructor that takes an index-space bounding box - /// to be mapped into a frustum with a given @a depth and @a taper - /// (defined as ratio of nearplane/farplane). - /// @details This frustum is further modifed by the @a secondMap, - /// intended to be a simple translation and rotation and uniform scale - NonlinearFrustumMap(const BBoxd& bb, double taper, double depth, - const MapBase::Ptr& secondMap): - mBBox(bb), mTaper(taper), mDepth(depth) - { - if (!secondMap->isLinear() ) { - OPENVDB_THROW(ArithmeticError, - "The second map in the Frustum transfrom must be linear"); - } - mSecondMap = *( secondMap->getAffineMap() ); - init(); - } - - NonlinearFrustumMap(const NonlinearFrustumMap& other): - MapBase(), - mBBox(other.mBBox), - mTaper(other.mTaper), - mDepth(other.mDepth), - mSecondMap(other.mSecondMap), - mHasSimpleAffine(other.mHasSimpleAffine) - { - init(); - } - - /// @brief Constructor from a camera frustum - /// - /// @param position the tip of the frustum (i.e., the camera's position). - /// @param direction a vector pointing from @a position toward the near plane. - /// @param up a non-unit vector describing the direction and extent of - /// the frustum's intersection on the near plane. Together, - /// @a up must be orthogonal to @a direction. - /// @param aspect the aspect ratio of the frustum intersection with near plane - /// defined as width / height - /// @param z_near,depth the distance from @a position along @a direction to the - /// near and far planes of the frustum. - /// @param x_count the number of voxels, aligned with @a left, - /// across the face of the frustum - /// @param z_count the number of voxels, aligned with @a direction, - /// between the near and far planes - NonlinearFrustumMap(const Vec3d& position, - const Vec3d& direction, - const Vec3d& up, - double aspect /* width / height */, - double z_near, double depth, - Coord::ValueType x_count, Coord::ValueType z_count) { - - /// @todo check that depth > 0 - /// @todo check up.length > 0 - /// @todo check that direction dot up = 0 - if (!(depth > 0)) { - OPENVDB_THROW(ArithmeticError, - "The frustum depth must be non-zero and positive"); - } - if (!(up.length() > 0)) { - OPENVDB_THROW(ArithmeticError, - "The frustum height must be non-zero and positive"); - } - if (!(aspect > 0)) { - OPENVDB_THROW(ArithmeticError, - "The frustum aspect ratio must be non-zero and positive"); - } - if (!(isApproxEqual(up.dot(direction), 0.))) { - OPENVDB_THROW(ArithmeticError, - "The frustum up orientation must be perpendicular to into-frustum direction"); - } - - double near_plane_height = 2 * up.length(); - double near_plane_width = aspect * near_plane_height; - - Coord::ValueType y_count = static_cast(Round(x_count / aspect)); - - mBBox = BBoxd(Vec3d(0,0,0), Vec3d(x_count, y_count, z_count)); - mDepth = depth / near_plane_width; // depth non-dimensionalized on width - double gamma = near_plane_width / z_near; - mTaper = 1./(mDepth*gamma + 1.); - - Vec3d direction_unit = direction; - direction_unit.normalize(); - - Mat4d r1(Mat4d::identity()); - r1.setToRotation(/*from*/Vec3d(0,0,1), /*to */direction_unit); - Mat4d r2(Mat4d::identity()); - Vec3d temp = r1.inverse().transform(up); - r2.setToRotation(/*from*/Vec3d(0,1,0), /*to*/temp ); - Mat4d scale = math::scale( - Vec3d(near_plane_width, near_plane_width, near_plane_width)); - - // move the near plane to origin, rotate to align with axis, and scale down - // T_inv * R1_inv * R2_inv * scale_inv - Mat4d mat = scale * r2 * r1; - mat.setTranslation(position + z_near*direction_unit); - - mSecondMap = AffineMap(mat); - - init(); - } - - ~NonlinearFrustumMap(){} - /// Return a MapBase::Ptr to a new NonlinearFrustumMap - static MapBase::Ptr create() { return MapBase::Ptr(new NonlinearFrustumMap()); } - /// Return a MapBase::Ptr to a deep copy of this map - MapBase::Ptr copy() const { return MapBase::Ptr(new NonlinearFrustumMap(*this)); } - - /// @brief Not implemented, since there is currently no map type that can - /// represent the inverse of a frustum - /// @throw NotImplementedError - MapBase::Ptr inverseMap() const - { - OPENVDB_THROW(NotImplementedError, - "inverseMap() is not implemented for NonlinearFrustumMap"); - } - static bool isRegistered() { return MapRegistry::isRegistered(NonlinearFrustumMap::mapType()); } - - static void registerMap() - { - MapRegistry::registerMap( - NonlinearFrustumMap::mapType(), - NonlinearFrustumMap::create); - } - /// Return @c NonlinearFrustumMap - Name type() const { return mapType(); } - /// Return @c NonlinearFrustumMap - static Name mapType() { return Name("NonlinearFrustumMap"); } - - /// Return @c false (a NonlinearFrustumMap is never linear). - bool isLinear() const { return false; } - - /// Return @c false (by convention false) - bool hasUniformScale() const { return false; } - - /// Return @c true if the map is equivalent to an identity - bool isIdentity() const - { - // The frustum can only be consistent with a linear map if the taper value is 1 - if (!isApproxEqual(mTaper, double(1)) ) return false; - - // There are various ways an identity can decomposed between the two parts of the - // map. Best to just check that the principle vectors are stationary. - const Vec3d e1(1,0,0); - if (!applyMap(e1).eq(e1)) return false; - - const Vec3d e2(0,1,0); - if (!applyMap(e2).eq(e2)) return false; - - const Vec3d e3(0,0,1); - if (!applyMap(e3).eq(e3)) return false; - - return true; - } - - virtual bool isEqual(const MapBase& other) const { return isEqualBase(*this, other); } - - bool operator==(const NonlinearFrustumMap& other) const - { - if (mBBox!=other.mBBox) return false; - if (!isApproxEqual(mTaper, other.mTaper)) return false; - if (!isApproxEqual(mDepth, other.mDepth)) return false; - - // Two linear transforms are equivalent iff they have the same translation - // and have the same affects on orthongal spanning basis check translation - Vec3d e(0,0,0); - if (!mSecondMap.applyMap(e).eq(other.mSecondMap.applyMap(e))) return false; - /// check spanning vectors - e(0) = 1; - if (!mSecondMap.applyMap(e).eq(other.mSecondMap.applyMap(e))) return false; - e(0) = 0; - e(1) = 1; - if (!mSecondMap.applyMap(e).eq(other.mSecondMap.applyMap(e))) return false; - e(1) = 0; - e(2) = 1; - if (!mSecondMap.applyMap(e).eq(other.mSecondMap.applyMap(e))) return false; - return true; - } - - bool operator!=(const NonlinearFrustumMap& other) const { return !(*this == other); } - - /// Return the image of @c in under the map - Vec3d applyMap(const Vec3d& in) const - { - return mSecondMap.applyMap(applyFrustumMap(in)); - } - - /// Return the pre-image of @c in under the map - Vec3d applyInverseMap(const Vec3d& in) const - { - return applyFrustumInverseMap(mSecondMap.applyInverseMap(in)); - } - /// Return the Jacobian of the linear second map applied to @c in - Vec3d applyJacobian(const Vec3d& in) const { return mSecondMap.applyJacobian(in); } - /// Return the Jacobian defined at @c isloc applied to @c in - Vec3d applyJacobian(const Vec3d& in, const Vec3d& isloc) const - { - // Move the center of the x-face of the bbox - // to the origin in index space. - Vec3d centered(isloc); - centered = centered - mBBox.min(); - centered.x() -= mXo; - centered.y() -= mYo; - - // scale the z-direction on depth / K count - const double zprime = centered.z()*mDepthOnLz; - - const double scale = (mGamma * zprime + 1.) / mLx; - const double scale2 = mGamma * mDepthOnLz / mLx; - - const Vec3d tmp(scale * in.x() + scale2 * centered.x()* in.z(), - scale * in.y() + scale2 * centered.y()* in.z(), - mDepthOnLz * in.z()); - - return mSecondMap.applyJacobian(tmp); - } - - - /// Return the Inverse Jacobian of the map applied to @a in. (i.e. inverse map with out translation) - Vec3d applyInverseJacobian(const Vec3d& in) const { return mSecondMap.applyInverseJacobian(in); } - /// Return the Inverse Jacobian defined at @c isloc of the map applied to @a in. - Vec3d applyInverseJacobian(const Vec3d& in, const Vec3d& isloc) const { - - // Move the center of the x-face of the bbox - // to the origin in index space. - Vec3d centered(isloc); - centered = centered - mBBox.min(); - centered.x() -= mXo; - centered.y() -= mYo; - - // scale the z-direction on depth / K count - const double zprime = centered.z()*mDepthOnLz; - - const double scale = (mGamma * zprime + 1.) / mLx; - const double scale2 = mGamma * mDepthOnLz / mLx; - - - Vec3d out = mSecondMap.applyInverseJacobian(in); - - out.x() = (out.x() - scale2 * centered.x() * out.z() / mDepthOnLz) / scale; - out.y() = (out.y() - scale2 * centered.y() * out.z() / mDepthOnLz) / scale; - out.z() = out.z() / mDepthOnLz; - - return out; - } - - - - /// Return the Jacobian Transpose of the map applied to vector @c in at @c indexloc. - /// This tranforms range-space gradients to domain-space gradients. - /// - Vec3d applyJT(const Vec3d& in, const Vec3d& isloc) const { - const Vec3d tmp = mSecondMap.applyJT(in); - // Move the center of the x-face of the bbox - // to the origin in index space. - Vec3d centered(isloc); - centered = centered - mBBox.min(); - centered.x() -= mXo; - centered.y() -= mYo; - - // scale the z-direction on depth / K count - const double zprime = centered.z()*mDepthOnLz; - - const double scale = (mGamma * zprime + 1.) / mLx; - const double scale2 = mGamma * mDepthOnLz / mLx; - - return Vec3d(scale * tmp.x(), - scale * tmp.y(), - scale2 * centered.x()* tmp.x() + - scale2 * centered.y()* tmp.y() + - mDepthOnLz * tmp.z()); - } - /// Return the Jacobian Transpose of the second map applied to @c in. - Vec3d applyJT(const Vec3d& in) const { - return mSecondMap.applyJT(in); - } - - /// Return the transpose of the inverse Jacobian of the linear second map applied to @c in - Vec3d applyIJT(const Vec3d& in) const { return mSecondMap.applyIJT(in); } - - // the Jacobian of the nonlinear part of the transform is a sparse matrix - // Jacobian^(-T) = - // - // (Lx)( 1/s 0 0 ) - // ( 0 1/s 0 ) - // ( -(x-xo)g/(sLx) -(y-yo)g/(sLx) Lz/(Depth Lx) ) - /// Return the transpose of the inverse Jacobain (at @c locW applied to @c in. - /// @c ijk is the location in the pre-image space (e.g. index space) - Vec3d applyIJT(const Vec3d& d1_is, const Vec3d& ijk) const - { - const Vec3d loc = applyFrustumMap(ijk); - const double s = mGamma * loc.z() + 1.; - - // verify that we aren't at the singularity - if (isApproxEqual(s, 0.)) { - OPENVDB_THROW(ArithmeticError, "Tried to evaluate the frustum transform" - " at the singular focal point (e.g. camera)"); - } - - const double sinv = 1.0/s; // 1/(z*gamma + 1) - const double pt0 = mLx * sinv; // Lx / (z*gamma +1) - const double pt1 = mGamma * pt0; // gamma * Lx / ( z*gamma +1) - const double pt2 = pt1 * sinv; // gamma * Lx / ( z*gamma +1)**2 - - const Mat3d& jacinv = mSecondMap.getConstJacobianInv(); - - // compute \frac{\partial E_i}{\partial x_j} - Mat3d gradE(Mat3d::zero()); - for (int j = 0; j < 3; ++j ) { - gradE(0,j) = pt0 * jacinv(0,j) - pt2 * loc.x()*jacinv(2,j); - gradE(1,j) = pt0 * jacinv(1,j) - pt2 * loc.y()*jacinv(2,j); - gradE(2,j) = (1./mDepthOnLz) * jacinv(2,j); - } - - Vec3d result; - for (int i = 0; i < 3; ++i) { - result(i) = d1_is(0) * gradE(0,i) + d1_is(1) * gradE(1,i) + d1_is(2) * gradE(2,i); - } - - return result; - - } - - /// Return the Jacobian Curvature for the linear second map - Mat3d applyIJC(const Mat3d& in) const { return mSecondMap.applyIJC(in); } - /// Return the Jacobian Curvature: all the second derivatives in range space - /// @param d2_is second derivative matrix computed in index space - /// @param d1_is gradient computed in index space - /// @param ijk the index space location where the result is computed - Mat3d applyIJC(const Mat3d& d2_is, const Vec3d& d1_is, const Vec3d& ijk) const - { - const Vec3d loc = applyFrustumMap(ijk); - - const double s = mGamma * loc.z() + 1.; - - // verify that we aren't at the singularity - if (isApproxEqual(s, 0.)) { - OPENVDB_THROW(ArithmeticError, "Tried to evaluate the frustum transform" - " at the singular focal point (e.g. camera)"); - } - - // precompute - const double sinv = 1.0/s; // 1/(z*gamma + 1) - const double pt0 = mLx * sinv; // Lx / (z*gamma +1) - const double pt1 = mGamma * pt0; // gamma * Lx / ( z*gamma +1) - const double pt2 = pt1 * sinv; // gamma * Lx / ( z*gamma +1)**2 - const double pt3 = pt2 * sinv; // gamma * Lx / ( z*gamma +1)**3 - - const Mat3d& jacinv = mSecondMap.getConstJacobianInv(); - - // compute \frac{\partial^2 E_i}{\partial x_j \partial x_k} - - Mat3d matE0(Mat3d::zero()); - Mat3d matE1(Mat3d::zero()); // matE2 = 0 - for(int j = 0; j < 3; j++) { - for (int k = 0; k < 3; k++) { - - const double pt4 = 2. * jacinv(2,j) * jacinv(2,k) * pt3; - - matE0(j,k) = -(jacinv(0,j) * jacinv(2,k) + jacinv(2,j) * jacinv(0,k)) * pt2 + - pt4 * loc.x(); - - matE1(j,k) = -(jacinv(1,j) * jacinv(2,k) + jacinv(2,j) * jacinv(1,k)) * pt2 + - pt4 * loc.y(); - } - } - - // compute \frac{\partial E_i}{\partial x_j} - Mat3d gradE(Mat3d::zero()); - for (int j = 0; j < 3; ++j ) { - gradE(0,j) = pt0 * jacinv(0,j) - pt2 * loc.x()*jacinv(2,j); - gradE(1,j) = pt0 * jacinv(1,j) - pt2 * loc.y()*jacinv(2,j); - gradE(2,j) = (1./mDepthOnLz) * jacinv(2,j); - } - - Mat3d result(Mat3d::zero()); - // compute \fac{\partial E_j}{\partial x_m} \fac{\partial E_i}{\partial x_n} - // \frac{\partial^2 input}{\partial E_i \partial E_j} - for (int m = 0; m < 3; ++m ) { - for ( int n = 0; n < 3; ++n) { - for (int i = 0; i < 3; ++i ) { - for (int j = 0; j < 3; ++j) { - result(m, n) += gradE(j, m) * gradE(i, n) * d2_is(i, j); - } - } - } - } - - for (int m = 0; m < 3; ++m ) { - for ( int n = 0; n < 3; ++n) { - result(m, n) += - matE0(m, n) * d1_is(0) + matE1(m, n) * d1_is(1);// + matE2(m, n) * d1_is(2); - } - } - - return result; - } - - /// Return the determinant of the Jacobian of linear second map - double determinant() const {return mSecondMap.determinant();} // no implementation - - /// Return the determinate of the Jacobian evaluated at @c loc - /// @c loc is a location in the pre-image space (e.g., index space) - double determinant(const Vec3d& loc) const - { - double s = mGamma * loc.z() + 1.0; - double frustum_determinant = s * s * mDepthOnLzLxLx; - return mSecondMap.determinant() * frustum_determinant; - } - - /// Return the size of a voxel at the center of the near plane - Vec3d voxelSize() const - { - const Vec3d loc( 0.5*(mBBox.min().x() + mBBox.max().x()), - 0.5*(mBBox.min().y() + mBBox.max().y()), - mBBox.min().z()); - - return voxelSize(loc); - - } - - /// @brief Returns the lengths of the images of the three segments - /// from @a loc to @a loc + (1,0,0), from @a loc to @a loc + (0,1,0) - /// and from @a loc to @a loc + (0,0,1) - /// @param loc a location in the pre-image space (e.g., index space) - Vec3d voxelSize(const Vec3d& loc) const - { - Vec3d out, pos = applyMap(loc); - out(0) = (applyMap(loc + Vec3d(1,0,0)) - pos).length(); - out(1) = (applyMap(loc + Vec3d(0,1,0)) - pos).length(); - out(2) = (applyMap(loc + Vec3d(0,0,1)) - pos).length(); - return out; - } - - AffineMap::Ptr getAffineMap() const { return mSecondMap.getAffineMap(); } - - /// set the taper value, the ratio of nearplane width / far plane width - void setTaper(double t) { mTaper = t; init();} - /// Return the taper value. - double getTaper() const { return mTaper; } - /// set the frustum depth: distance between near and far plane = frustm depth * frustm x-width - void setDepth(double d) { mDepth = d; init();} - /// Return the unscaled frustm depth - double getDepth() const { return mDepth; } - // gamma a non-dimensional number: nearplane x-width / camera to near plane distance - double getGamma() const { return mGamma; } - - /// Return the bounding box that defines the frustum in pre-image space - const BBoxd& getBBox() const { return mBBox; } - - /// Return MapBase::Ptr& to the second map - const AffineMap& secondMap() const { return mSecondMap; } - /// Return @c true if the the bounding box in index space that defines the region that - /// is maped into the frustum is non-zero, otherwise @c false - bool isValid() const { return !mBBox.empty();} - - /// Return @c true if the second map is a uniform scale, Rotation and translation - bool hasSimpleAffine() const { return mHasSimpleAffine; } - - /// read serialization - void read(std::istream& is) - { - // for backward compatibility with earlier version - if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_FLOAT_FRUSTUM_BBOX ) { - CoordBBox bb; - bb.read(is); - mBBox = BBoxd(bb.min().asVec3d(), bb.max().asVec3d()); - } else { - mBBox.read(is); - } - - is.read(reinterpret_cast(&mTaper), sizeof(double)); - is.read(reinterpret_cast(&mDepth), sizeof(double)); - - // Read the second maps type. - Name type = readString(is); - - // Check if the map has been registered. - if(!MapRegistry::isRegistered(type)) { - OPENVDB_THROW(KeyError, "Map " << type << " is not registered"); - } - - // Create the second map of the type and then read it in. - MapBase::Ptr proxy = math::MapRegistry::createMap(type); - proxy->read(is); - mSecondMap = *(proxy->getAffineMap()); - init(); - } - - /// write serialization - void write(std::ostream& os) const - { - mBBox.write(os); - os.write(reinterpret_cast(&mTaper), sizeof(double)); - os.write(reinterpret_cast(&mDepth), sizeof(double)); - - writeString(os, mSecondMap.type()); - mSecondMap.write(os); - } - - /// string serialization, useful for debuging - std::string str() const - { - std::ostringstream buffer; - buffer << " - taper: " << mTaper << std::endl; - buffer << " - depth: " << mDepth << std::endl; - buffer << " SecondMap: "<< mSecondMap.type() << std::endl; - buffer << mSecondMap.str() << std::endl; - return buffer.str(); - } - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of prepending the appropriate operation to the linear part of this map - MapBase::Ptr preRotate(double radians, Axis axis = X_AXIS) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.preRotate(radians, axis))); - } - MapBase::Ptr preTranslate(const Vec3d& t) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.preTranslate(t))); - } - MapBase::Ptr preScale(const Vec3d& s) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.preScale(s))); - } - MapBase::Ptr preShear(double shear, Axis axis0, Axis axis1) const - { - return MapBase::Ptr(new NonlinearFrustumMap( - mBBox, mTaper, mDepth, mSecondMap.preShear(shear, axis0, axis1))); - } - //@} - - //@{ - /// @brief Return a MapBase::Ptr to a new map that is the result - /// of postfixing the appropiate operation to the linear part of this map. - MapBase::Ptr postRotate(double radians, Axis axis = X_AXIS) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.postRotate(radians, axis))); - } - MapBase::Ptr postTranslate(const Vec3d& t) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.postTranslate(t))); - } - MapBase::Ptr postScale(const Vec3d& s) const - { - return MapBase::Ptr( - new NonlinearFrustumMap(mBBox, mTaper, mDepth, mSecondMap.postScale(s))); - } - MapBase::Ptr postShear(double shear, Axis axis0, Axis axis1) const - { - return MapBase::Ptr(new NonlinearFrustumMap( - mBBox, mTaper, mDepth, mSecondMap.postShear(shear, axis0, axis1))); - } - //@} - -private: - void init() - { - // set up as a frustum - mLx = mBBox.extents().x(); - mLy = mBBox.extents().y(); - mLz = mBBox.extents().z(); - - if (isApproxEqual(mLx,0.) || isApproxEqual(mLy,0.) || isApproxEqual(mLz,0.) ) { - OPENVDB_THROW(ArithmeticError, "The index space bounding box" - " must have at least two index points in each direction."); - } - - mXo = 0.5* mLx; - mYo = 0.5* mLy; - - // mDepth is non-dimensionalized on near - mGamma = (1./mTaper - 1) / mDepth; - - mDepthOnLz = mDepth/mLz; - mDepthOnLzLxLx = mDepthOnLz/(mLx * mLx); - - /// test for shear and non-uniform scale - mHasSimpleAffine = true; - Vec3d tmp = mSecondMap.voxelSize(); - - /// false if there is non-uniform scale - if (!isApproxEqual(tmp(0), tmp(1))) { mHasSimpleAffine = false; return; } - if (!isApproxEqual(tmp(0), tmp(2))) { mHasSimpleAffine = false; return; } - - Vec3d trans = mSecondMap.applyMap(Vec3d(0,0,0)); - /// look for shear - Vec3d tmp1 = mSecondMap.applyMap(Vec3d(1,0,0)) - trans; - Vec3d tmp2 = mSecondMap.applyMap(Vec3d(0,1,0)) - trans; - Vec3d tmp3 = mSecondMap.applyMap(Vec3d(0,0,1)) - trans; - - /// false if there is shear - if (!isApproxEqual(tmp1.dot(tmp2), 0., 1.e-7)) { mHasSimpleAffine = false; return; } - if (!isApproxEqual(tmp2.dot(tmp3), 0., 1.e-7)) { mHasSimpleAffine = false; return; } - if (!isApproxEqual(tmp3.dot(tmp1), 0., 1.e-7)) { mHasSimpleAffine = false; return; } - } - - Vec3d applyFrustumMap(const Vec3d& in) const - { - - // Move the center of the x-face of the bbox - // to the origin in index space. - Vec3d out(in); - out = out - mBBox.min(); - out.x() -= mXo; - out.y() -= mYo; - - // scale the z-direction on depth / K count - out.z() *= mDepthOnLz; - - double scale = (mGamma * out.z() + 1.)/ mLx; - - // scale the x-y on the length I count and apply tapper - out.x() *= scale ; - out.y() *= scale ; - - return out; - } - - Vec3d applyFrustumInverseMap(const Vec3d& in) const - { - // invert taper and resize: scale = 1/( (z+1)/2 (mt-1) + 1) - Vec3d out(in); - double invScale = mLx / (mGamma * out.z() + 1.); - out.x() *= invScale; - out.y() *= invScale; - - out.x() += mXo; - out.y() += mYo; - - out.z() /= mDepthOnLz; - - // move back - out = out + mBBox.min(); - return out; - } - - // bounding box in index space used in Frustum transforms. - BBoxd mBBox; - - // taper value used in constructing Frustums. - double mTaper; - double mDepth; - - // defines the second map - AffineMap mSecondMap; - - // these are derived from the above. - double mLx, mLy, mLz; - double mXo, mYo, mGamma, mDepthOnLz, mDepthOnLzLxLx; - - // true: if the mSecondMap is linear and has no shear, and has no non-uniform scale - bool mHasSimpleAffine; -}; // class NonlinearFrustumMap - - -//////////////////////////////////////// - - -/// @brief Creates the composition of two maps, each of which could be a composition. -/// In the case that each component of the composition classified as linear an -/// acceleration AffineMap is stored. -template -class CompoundMap -{ -public: - typedef CompoundMap MyType; - - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - - CompoundMap() { updateAffineMatrix(); } - - CompoundMap(const FirstMapType& f, const SecondMapType& s): mFirstMap(f), mSecondMap(s) - { - updateAffineMatrix(); - } - - CompoundMap(const MyType& other): - mFirstMap(other.mFirstMap), - mSecondMap(other.mSecondMap), - mAffineMap(other.mAffineMap) - {} - - Name type() const { return mapType(); } - static Name mapType() - { - return (FirstMapType::mapType() + Name(":") + SecondMapType::mapType()); - } - - bool operator==(const MyType& other) const - { - if (mFirstMap != other.mFirstMap) return false; - if (mSecondMap != other.mSecondMap) return false; - if (mAffineMap != other.mAffineMap) return false; - return true; - } - - bool operator!=(const MyType& other) const { return !(*this == other); } - - MyType& operator=(const MyType& other) - { - mFirstMap = other.mFirstMap; - mSecondMap = other.mSecondMap; - mAffineMap = other.mAffineMap; - return *this; - } - - bool isIdentity() const - { - if (is_linear::value) { - return mAffineMap.isIdentity(); - } else { - return mFirstMap.isIdentity()&&mSecondMap.isIdentity(); - } - } - - bool isDiagonal() const { - if (is_linear::value) { - return mAffineMap.isDiagonal(); - } else { - return mFirstMap.isDiagonal()&&mSecondMap.isDiagonal(); - } - } - - AffineMap::Ptr getAffineMap() const - { - if (is_linear::value) { - AffineMap::Ptr affine(new AffineMap(mAffineMap)); - return affine; - } else { - OPENVDB_THROW(ArithmeticError, - "Constant affine matrix representation not possible for this nonlinear map"); - } - } - - // direct decompotion - const FirstMapType& firstMap() const { return mFirstMap; } - const SecondMapType& secondMap() const {return mSecondMap; } - - void setFirstMap(const FirstMapType& first) { mFirstMap = first; updateAffineMatrix(); } - void setSecondMap(const SecondMapType& second) { mSecondMap = second; updateAffineMatrix(); } - - void read(std::istream& is) - { - mAffineMap.read(is); - mFirstMap.read(is); - mSecondMap.read(is); - } - void write(std::ostream& os) const - { - mAffineMap.write(os); - mFirstMap.write(os); - mSecondMap.write(os); - } - -private: - void updateAffineMatrix() - { - if (is_linear::value) { - // both maps need to be linear, these methods are only defined for linear maps - AffineMap::Ptr first = mFirstMap.getAffineMap(); - AffineMap::Ptr second= mSecondMap.getAffineMap(); - mAffineMap = AffineMap(*first, *second); - } - } - - FirstMapType mFirstMap; - SecondMapType mSecondMap; - // used for acceleration - AffineMap mAffineMap; -}; // class CompoundMap - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_MAPS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Mat.h b/openvdb_3_0_0_library/math/Mat.h deleted file mode 100755 index db5e655..0000000 --- a/openvdb_3_0_0_library/math/Mat.h +++ /dev/null @@ -1,992 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Mat.h -/// @author Joshua Schpok - -#ifndef OPENVDB_MATH_MAT_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_MAT_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include "Math.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @class Mat "Mat.h" -/// A base class for square matrices. -template -class Mat -{ -public: - typedef T value_type; - typedef T ValueType; - enum SIZE_ { size = SIZE }; - - // Number of cols, rows, elements - static unsigned numRows() { return SIZE; } - static unsigned numColumns() { return SIZE; } - static unsigned numElements() { return SIZE*SIZE; } - - /// Default ctor. Does nothing. Required because declaring a copy (or - /// other) constructor means the default constructor gets left out. - Mat() { } - - /// Copy constructor. Used when the class signature matches exactly. - Mat(Mat const &src) { - for (unsigned i(0); i < numElements(); ++i) { - mm[i] = src.mm[i]; - } - } - - /// @return string representation of matrix - /// Since output is multiline, optional indentation argument prefixes - /// each newline with that much white space. It does not indent - /// the first line, since you might be calling this inline: - /// - /// cout << "matrix: " << mat.str(7) - /// - /// matrix: [[1 2] - /// [3 4]] - std::string - str(unsigned indentation = 0) const { - - std::string ret; - std::string indent; - - // We add +1 since we're indenting one for the first '[' - indent.append(indentation+1, ' '); - - ret.append("["); - - // For each row, - for (unsigned i(0); i < SIZE; i++) { - - ret.append("["); - - // For each column - for (unsigned j(0); j < SIZE; j++) { - - // Put a comma after everything except the last - if (j) ret.append(", "); - ret.append((boost::format("%1%") % mm[(i*SIZE)+j]).str()); - } - - ret.append("]"); - - // At the end of every row (except the last)... - if (i < SIZE-1 ) - // ...suffix the row bracket with a comma, newline, and - // advance indentation - ret.append((boost::format(",\n%1%") % indent).str()); - } - - ret.append("]"); - - return ret; - } - - /// Write a Mat to an output stream - friend std::ostream& operator<<( - std::ostream& ostr, - const Mat& m) - { - ostr << m.str(); - return ostr; - } - - void write(std::ostream& os) const { - os.write(reinterpret_cast(&mm), sizeof(T)*SIZE*SIZE); - } - - void read(std::istream& is) { - is.read(reinterpret_cast(&mm), sizeof(T)*SIZE*SIZE); - } - - -protected: - T mm[SIZE*SIZE]; -}; - - -template class Quat; -template class Vec3; - -/// @brief Return the rotation matrix specified by the given quaternion. -/// @details The quaternion is normalized and used to construct the matrix. -/// Note that the matrix is transposed to match post-multiplication semantics. -template -MatType -rotation(const Quat &q, - typename MatType::value_type eps = static_cast(1.0e-8)) -{ - typedef typename MatType::value_type T; - - T qdot(q.dot(q)); - T s(0); - - if (!isApproxEqual(qdot, T(0.0),eps)) { - s = T(2.0 / qdot); - } - - T x = s*q.x(); - T y = s*q.y(); - T z = s*q.z(); - T wx = x*q.w(); - T wy = y*q.w(); - T wz = z*q.w(); - T xx = x*q.x(); - T xy = y*q.x(); - T xz = z*q.x(); - T yy = y*q.y(); - T yz = z*q.y(); - T zz = z*q.z(); - - MatType r; - r[0][0]=T(1) - (yy+zz); r[0][1]=xy + wz; r[0][2]=xz - wy; - r[1][0]=xy - wz; r[1][1]=T(1) - (xx+zz); r[1][2]=yz + wx; - r[2][0]=xz + wy; r[2][1]=yz - wx; r[2][2]=T(1) - (xx+yy); - - if(MatType::numColumns() == 4) padMat4(r); - return r; -} - - - -/// @brief Return a matrix for rotation by @a angle radians about the given @a axis. -/// @param axis The axis (one of X, Y, Z) to rotate about. -/// @param angle The rotation angle, in radians. -template -MatType -rotation(Axis axis, typename MatType::value_type angle) -{ - typedef typename MatType::value_type T; - T c = static_cast(cos(angle)); - T s = static_cast(sin(angle)); - - MatType result; - result.setIdentity(); - - switch (axis) { - case X_AXIS: - result[1][1] = c; - result[1][2] = s; - result[2][1] = -s; - result[2][2] = c; - return result; - case Y_AXIS: - result[0][0] = c; - result[0][2] = -s; - result[2][0] = s; - result[2][2] = c; - return result; - case Z_AXIS: - result[0][0] = c; - result[0][1] = s; - result[1][0] = -s; - result[1][1] = c; - return result; - default: - throw ValueError("Unrecognized rotation axis"); - } -} - - -/// @brief Return a matrix for rotation by @a angle radians about the given @a axis. -/// @note The axis must be a unit vector. -template -MatType -rotation(const Vec3 &_axis, typename MatType::value_type angle) -{ - typedef typename MatType::value_type T; - T txy, txz, tyz, sx, sy, sz; - - Vec3 axis(_axis.unit()); - - // compute trig properties of angle: - T c(cos(double(angle))); - T s(sin(double(angle))); - T t(1 - c); - - MatType result; - // handle diagonal elements - result[0][0] = axis[0]*axis[0] * t + c; - result[1][1] = axis[1]*axis[1] * t + c; - result[2][2] = axis[2]*axis[2] * t + c; - - txy = axis[0]*axis[1] * t; - sz = axis[2] * s; - - txz = axis[0]*axis[2] * t; - sy = axis[1] * s; - - tyz = axis[1]*axis[2] * t; - sx = axis[0] * s; - - // right handed space - // Contribution from rotation about 'z' - result[0][1] = txy + sz; - result[1][0] = txy - sz; - // Contribution from rotation about 'y' - result[0][2] = txz - sy; - result[2][0] = txz + sy; - // Contribution from rotation about 'x' - result[1][2] = tyz + sx; - result[2][1] = tyz - sx; - - if(MatType::numColumns() == 4) padMat4(result); - return MatType(result); -} - - -/// @brief Return the Euler angles composing the given rotation matrix. -/// @details Optional axes arguments describe in what order elementary rotations -/// are applied. Note that in our convention, XYZ means Rz * Ry * Rx. -/// Because we are using rows rather than columns to represent the -/// local axes of a coordinate frame, the interpretation from a local -/// reference point of view is to first rotate about the x axis, then -/// about the newly rotated y axis, and finally by the new local z axis. -/// From a fixed reference point of view, the interpretation is to -/// rotate about the stationary world z, y, and x axes respectively. -/// -/// Irrespective of the Euler angle convention, in the case of distinct -/// axes, eulerAngles() returns the x, y, and z angles in the corresponding -/// x, y, z components of the returned Vec3. For the XZX convention, the -/// left X value is returned in Vec3.x, and the right X value in Vec3.y. -/// For the ZXZ convention the left Z value is returned in Vec3.z and -/// the right Z value in Vec3.y -/// -/// Examples of reconstructing r from its Euler angle decomposition -/// -/// v = eulerAngles(r, ZYX_ROTATION); -/// rx.setToRotation(Vec3d(1,0,0), v[0]); -/// ry.setToRotation(Vec3d(0,1,0), v[1]); -/// rz.setToRotation(Vec3d(0,0,1), v[2]); -/// r = rx * ry * rz; -/// -/// v = eulerAngles(r, ZXZ_ROTATION); -/// rz1.setToRotation(Vec3d(0,0,1), v[2]); -/// rx.setToRotation (Vec3d(1,0,0), v[0]); -/// rz2.setToRotation(Vec3d(0,0,1), v[1]); -/// r = rz2 * rx * rz1; -/// -/// v = eulerAngles(r, XZX_ROTATION); -/// rx1.setToRotation (Vec3d(1,0,0), v[0]); -/// rx2.setToRotation (Vec3d(1,0,0), v[1]); -/// rz.setToRotation (Vec3d(0,0,1), v[2]); -/// r = rx2 * rz * rx1; -/// -template -Vec3 -eulerAngles( - const MatType& mat, - RotationOrder rotationOrder, - typename MatType::value_type eps = static_cast(1.0e-8)) -{ - typedef typename MatType::value_type ValueType; - typedef Vec3 V; - ValueType phi, theta, psi; - - switch(rotationOrder) - { - case XYZ_ROTATION: - if (isApproxEqual(mat[2][0], ValueType(1.0), eps)) { - theta = ValueType(M_PI_2); - phi = ValueType(0.5 * atan2(mat[1][2], mat[1][1])); - psi = phi; - } else if (isApproxEqual(mat[2][0], ValueType(-1.0), eps)) { - theta = ValueType(-M_PI_2); - phi = ValueType(0.5 * atan2(mat[1][2], mat[1][1])); - psi = -phi; - } else { - psi = ValueType(atan2(-mat[1][0],mat[0][0])); - phi = ValueType(atan2(-mat[2][1],mat[2][2])); - theta = ValueType(atan2(mat[2][0], - sqrt( mat[2][1]*mat[2][1] + - mat[2][2]*mat[2][2]))); - } - return V(phi, theta, psi); - case ZXY_ROTATION: - if (isApproxEqual(mat[1][2], ValueType(1.0), eps)) { - theta = ValueType(M_PI_2); - phi = ValueType(0.5 * atan2(mat[0][1], mat[0][0])); - psi = phi; - } else if (isApproxEqual(mat[1][2], ValueType(-1.0), eps)) { - theta = ValueType(-M_PI/2); - phi = ValueType(0.5 * atan2(mat[0][1],mat[2][1])); - psi = -phi; - } else { - psi = ValueType(atan2(-mat[0][2], mat[2][2])); - phi = ValueType(atan2(-mat[1][0], mat[1][1])); - theta = ValueType(atan2(mat[1][2], - sqrt(mat[0][2] * mat[0][2] + - mat[2][2] * mat[2][2]))); - } - return V(theta, psi, phi); - - case YZX_ROTATION: - if (isApproxEqual(mat[0][1], ValueType(1.0), eps)) { - theta = ValueType(M_PI_2); - phi = ValueType(0.5 * atan2(mat[2][0], mat[2][2])); - psi = phi; - } else if (isApproxEqual(mat[0][1], ValueType(-1.0), eps)) { - theta = ValueType(-M_PI/2); - phi = ValueType(0.5 * atan2(mat[2][0], mat[1][0])); - psi = -phi; - } else { - psi = ValueType(atan2(-mat[2][1], mat[1][1])); - phi = ValueType(atan2(-mat[0][2], mat[0][0])); - theta = ValueType(atan2(mat[0][1], - sqrt(mat[0][0] * mat[0][0] + - mat[0][2] * mat[0][2]))); - } - return V(psi, phi, theta); - - case XZX_ROTATION: - - if (isApproxEqual(mat[0][0], ValueType(1.0), eps)) { - theta = ValueType(0.0); - phi = ValueType(0.5 * atan2(mat[1][2], mat[1][1])); - psi = phi; - } else if (isApproxEqual(mat[0][0], ValueType(-1.0), eps)) { - theta = ValueType(M_PI); - psi = ValueType(0.5 * atan2(mat[2][1], -mat[1][1])); - phi = - psi; - } else { - psi = ValueType(atan2(mat[2][0], -mat[1][0])); - phi = ValueType(atan2(mat[0][2], mat[0][1])); - theta = ValueType(atan2(sqrt(mat[0][1] * mat[0][1] + - mat[0][2] * mat[0][2]), - mat[0][0])); - } - return V(phi, psi, theta); - - case ZXZ_ROTATION: - - if (isApproxEqual(mat[2][2], ValueType(1.0), eps)) { - theta = ValueType(0.0); - phi = ValueType(0.5 * atan2(mat[0][1], mat[0][0])); - psi = phi; - } else if (isApproxEqual(mat[2][2], ValueType(-1.0), eps)) { - theta = ValueType(M_PI); - phi = ValueType(0.5 * atan2(mat[0][1], mat[0][0])); - psi = -phi; - } else { - psi = ValueType(atan2(mat[0][2], mat[1][2])); - phi = ValueType(atan2(mat[2][0], -mat[2][1])); - theta = ValueType(atan2(sqrt(mat[0][2] * mat[0][2] + - mat[1][2] * mat[1][2]), - mat[2][2])); - } - return V(theta, psi, phi); - - case YXZ_ROTATION: - - if (isApproxEqual(mat[2][1], ValueType(1.0), eps)) { - theta = ValueType(-M_PI_2); - phi = ValueType(0.5 * atan2(-mat[1][0], mat[0][0])); - psi = phi; - } else if (isApproxEqual(mat[2][1], ValueType(-1.0), eps)) { - theta = ValueType(M_PI_2); - phi = ValueType(0.5 * atan2(mat[1][0], mat[0][0])); - psi = -phi; - } else { - psi = ValueType(atan2(mat[0][1], mat[1][1])); - phi = ValueType(atan2(mat[2][0], mat[2][2])); - theta = ValueType(atan2(-mat[2][1], - sqrt(mat[0][1] * mat[0][1] + - mat[1][1] * mat[1][1]))); - } - return V(theta, phi, psi); - - case ZYX_ROTATION: - - if (isApproxEqual(mat[0][2], ValueType(1.0), eps)) { - theta = ValueType(-M_PI_2); - phi = ValueType(0.5 * atan2(-mat[1][0], mat[1][1])); - psi = phi; - } else if (isApproxEqual(mat[0][2], ValueType(-1.0), eps)) { - theta = ValueType(M_PI_2); - phi = ValueType(0.5 * atan2(mat[2][1], mat[2][0])); - psi = -phi; - } else { - psi = ValueType(atan2(mat[1][2], mat[2][2])); - phi = ValueType(atan2(mat[0][1], mat[0][0])); - theta = ValueType(atan2(-mat[0][2], - sqrt(mat[0][1] * mat[0][1] + - mat[0][0] * mat[0][0]))); - } - return V(psi, theta, phi); - - case XZY_ROTATION: - - if (isApproxEqual(mat[1][0], ValueType(-1.0), eps)) { - theta = ValueType(M_PI_2); - psi = ValueType(0.5 * atan2(mat[2][1], mat[2][2])); - phi = -psi; - } else if (isApproxEqual(mat[1][0], ValueType(1.0), eps)) { - theta = ValueType(-M_PI_2); - psi = ValueType(0.5 * atan2(- mat[2][1], mat[2][2])); - phi = psi; - } else { - psi = ValueType(atan2(mat[2][0], mat[0][0])); - phi = ValueType(atan2(mat[1][2], mat[1][1])); - theta = ValueType(atan2(- mat[1][0], - sqrt(mat[1][1] * mat[1][1] + - mat[1][2] * mat[1][2]))); - } - return V(phi, psi, theta); - } - - OPENVDB_THROW(NotImplementedError, "Euler extraction sequence not implemented"); -} - - -/// @brief Return a rotation matrix that maps @a v1 onto @a v2 -/// about the cross product of @a v1 and @a v2. -template -MatType -rotation( - const Vec3& _v1, - const Vec3& _v2, - typename MatType::value_type eps=1.0e-8) -{ - typedef typename MatType::value_type T; - Vec3 v1(_v1); - Vec3 v2(_v2); - - // Check if v1 and v2 are unit length - if (!isApproxEqual(1.0, v1.dot(v1), eps)) { - v1.normalize(); - } - if (!isApproxEqual(1.0, v2.dot(v2), eps)) { - v2.normalize(); - } - - Vec3 cross; - cross.cross(v1, v2); - - if (isApproxEqual(cross[0], 0.0, eps) && - isApproxEqual(cross[1], 0.0, eps) && - isApproxEqual(cross[2], 0.0, eps)) { - - - // Given two unit vectors v1 and v2 that are nearly parallel, build a - // rotation matrix that maps v1 onto v2. First find which principal axis - // p is closest to perpendicular to v1. Find a reflection that exchanges - // v1 and p, and find a reflection that exchanges p2 and v2. The desired - // rotation matrix is the composition of these two reflections. See the - // paper "Efficiently Building a Matrix to Rotate One Vector to - // Another" by Tomas Moller and John Hughes in Journal of Graphics - // Tools Vol 4, No 4 for details. - - Vec3 u, v, p(0.0, 0.0, 0.0); - - double x = Abs(v1[0]); - double y = Abs(v1[1]); - double z = Abs(v1[2]); - - if (x < y) { - if (z < x) { - p[2] = 1; - } else { - p[0] = 1; - } - } else { - if (z < y) { - p[2] = 1; - } else { - p[1] = 1; - } - } - u = p - v1; - v = p - v2; - - double udot = u.dot(u); - double vdot = v.dot(v); - - double a = -2 / udot; - double b = -2 / vdot; - double c = 4 * u.dot(v) / (udot * vdot); - - MatType result; - result.setIdentity(); - - for (int j = 0; j < 3; j++) { - for (int i = 0; i < 3; i++) - result[i][j] = - a * u[i] * u[j] + b * v[i] * v[j] + c * v[j] * u[i]; - } - result[0][0] += 1.0; - result[1][1] += 1.0; - result[2][2] += 1.0; - - if(MatType::numColumns() == 4) padMat4(result); - return result; - - } else { - double c = v1.dot(v2); - double a = (1.0 - c) / cross.dot(cross); - - double a0 = a * cross[0]; - double a1 = a * cross[1]; - double a2 = a * cross[2]; - - double a01 = a0 * cross[1]; - double a02 = a0 * cross[2]; - double a12 = a1 * cross[2]; - - MatType r; - - r[0][0] = c + a0 * cross[0]; - r[0][1] = a01 + cross[2]; - r[0][2] = a02 - cross[1], - r[1][0] = a01 - cross[2]; - r[1][1] = c + a1 * cross[1]; - r[1][2] = a12 + cross[0]; - r[2][0] = a02 + cross[1]; - r[2][1] = a12 - cross[0]; - r[2][2] = c + a2 * cross[2]; - - if(MatType::numColumns() == 4) padMat4(r); - return r; - - } -} - - -/// Return a matrix that scales by @a s. -template -MatType -scale(const Vec3& s) -{ - // Gets identity, then sets top 3 diagonal - // Inefficient by 3 sets. - - MatType result; - result.setIdentity(); - result[0][0] = s[0]; - result[1][1] = s[1]; - result[2][2] = s[2]; - - return result; -} - - -/// Return a Vec3 representing the lengths of the passed matrix's upper 3x3's rows. -template -Vec3 -getScale(const MatType &mat) -{ - typedef Vec3 V; - return V( - V(mat[0][0], mat[0][1], mat[0][2]).length(), - V(mat[1][0], mat[1][1], mat[1][2]).length(), - V(mat[2][0], mat[2][1], mat[2][2]).length()); -} - - -/// @brief Return a copy of the given matrix with its upper 3x3 rows normalized. -/// @details This can be geometrically interpreted as a matrix with no scaling -/// along its major axes. -template -MatType -unit(const MatType &mat, typename MatType::value_type eps = 1.0e-8) -{ - Vec3 dud; - return unit(mat, eps, dud); -} - - -/// @brief Return a copy of the given matrix with its upper 3x3 rows normalized, -/// and return the length of each of these rows in @a scaling. -/// @details This can be geometrically interpretted as a matrix with no scaling -/// along its major axes, and the scaling in the input vector -template -MatType -unit( - const MatType &in, - typename MatType::value_type eps, - Vec3& scaling) -{ - typedef typename MatType::value_type T; - MatType result(in); - - for (int i(0); i < 3; i++) { - try { - const Vec3 u( - Vec3(in[i][0], in[i][1], in[i][2]).unit(eps, scaling[i])); - for (int j=0; j<3; j++) result[i][j] = u[j]; - } catch (ArithmeticError&) { - for (int j=0; j<3; j++) result[i][j] = 0; - } - } - return result; -} - - -/// @brief Set the matrix to a shear along @a axis0 by a fraction of @a axis1. -/// @param axis0 The fixed axis of the shear. -/// @param axis1 The shear axis. -/// @param shear The shear factor. -template -MatType -shear(Axis axis0, Axis axis1, typename MatType::value_type shear) -{ - int index0 = static_cast(axis0); - int index1 = static_cast(axis1); - - MatType result; - result.setIdentity(); - if (axis0 == axis1) { - result[index1][index0] = shear + 1; - } else { - result[index1][index0] = shear; - } - - return result; -} - - -/// Return a matrix as the cross product of the given vector. -template -MatType -skew(const Vec3 &skew) -{ - typedef typename MatType::value_type T; - - MatType r; - r[0][0] = T(0); r[0][1] = skew.z(); r[0][2] = -skew.y(); - r[1][0] = -skew.z(); r[1][1] = T(0); r[2][1] = skew.x(); - r[2][0] = skew.y(); r[2][1] = -skew.x(); r[2][2] = T(0); - - if(MatType::numColumns() == 4) padMat4(r); - return r; -} - - -/// @brief Return an orientation matrix such that z points along @a direction, -/// and y is along the @a direction / @a vertical plane. -template -MatType -aim(const Vec3& direction, - const Vec3& vertical) -{ - typedef typename MatType::value_type T; - Vec3 forward(direction.unit()); - Vec3 horizontal(vertical.unit().cross(forward).unit()); - Vec3 up(forward.cross(horizontal).unit()); - - MatType r; - - r[0][0]=horizontal.x(); r[0][1]=horizontal.y(); r[0][2]=horizontal.z(); - r[1][0]=up.x(); r[1][1]=up.y(); r[1][2]=up.z(); - r[2][0]=forward.x(); r[2][1]=forward.y(); r[2][2]=forward.z(); - - if(MatType::numColumns() == 4) padMat4(r); - return r; -} - - -/// @brief Write 0s along Mat4's last row and column, and a 1 on its diagonal. -/// @details Useful initialization when we're initializing just the 3x3 block. -template -static MatType& -padMat4(MatType& dest) -{ - dest[0][3] = dest[1][3] = dest[2][3] = 0; - dest[3][2] = dest[3][1] = dest[3][0] = 0; - dest[3][3] = 1; - - return dest; -} - - -/// @brief Solve for A=B*B, given A. -/// @details Denman-Beavers square root iteration -template -inline void -sqrtSolve(const MatType &aA, MatType &aB, double aTol=0.01) -{ - unsigned int iterations = (unsigned int)(log(aTol)/log(0.5)); - MatType Y[2]; - MatType Z[2]; - MatType invY; - MatType invZ; - - unsigned int current = 0; - - Y[0]=aA; - Z[0] = MatType::identity(); - - unsigned int iteration; - for (iteration=0; iteration -inline void -powSolve(const MatType &aA, MatType &aB, double aPower, double aTol=0.01) -{ - unsigned int iterations = (unsigned int)(log(aTol)/log(0.5)); - - const bool inverted = ( aPower < 0.0 ); - - if (inverted) { - aPower = -aPower; - } - - unsigned int whole = (unsigned int)aPower; - double fraction = aPower - whole; - - MatType R; - R = MatType::identity(); - - MatType partial = aA; - - double contribution = 1.0; - - unsigned int iteration; - - for (iteration=0; iteration< iterations; iteration++) - { - sqrtSolve(partial, partial, aTol); - contribution *= 0.5; - - if (fraction>=contribution) - { - R *= partial; - fraction-=contribution; - } - } - - partial = aA; - while (whole) - { - if (whole & 1) { - R *= partial; - } - whole>>=1; - if(whole) { - partial*=partial; - } - } - - if (inverted) { - aB = R.inverse(); - } - else { - aB = R; - } -} - - -/// @brief Determine if a matrix is an identity matrix. -template -inline bool -isIdentity(const MatType& m) -{ - return m.eq(MatType::identity()); -} - - -/// @brief Determine if a matrix is invertible. -template -inline bool -isInvertible(const MatType& m) -{ - typedef typename MatType::ValueType value_type; - return !isApproxEqual(m.det(), (value_type)0); -} - - -/// @brief Determine if a matrix is symmetric. -/// @details This implicitly uses math::isApproxEqual() to determine equality. -template -inline bool -isSymmetric(const MatType& m) -{ - return m.eq(m.transpose()); -} - - -/// Determine if a matrix is unitary (i.e., rotation or reflection). -template -inline bool -isUnitary(const MatType& m) -{ - typedef typename MatType::ValueType value_type; - if (!isApproxEqual(std::abs(m.det()), value_type(1.0))) return false; - // check that the matrix transpose is the inverse - MatType temp = m * m.transpose(); - return temp.eq(MatType::identity()); -} - - -/// Determine if a matrix is diagonal. -template -inline bool -isDiagonal(const MatType& mat) -{ - int n = MatType::size; - typename MatType::ValueType temp(0); - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n; ++j) { - if (i != j) { - temp+=std::abs(mat(i,j)); - } - } - } - return isApproxEqual(temp, typename MatType::ValueType(0.0)); -} - - -/// Return the @f$L_\infty@f$ norm of an N x N matrix. -template -typename MatType::ValueType -lInfinityNorm(const MatType& matrix) -{ - int n = MatType::size; - typename MatType::ValueType norm = 0; - - for( int j = 0; j -typename MatType::ValueType -lOneNorm(const MatType& matrix) -{ - int n = MatType::size; - typename MatType::ValueType norm = 0; - - for( int i = 0; i -bool -polarDecomposition(const MatType& input, MatType& unitary, - MatType& positive_hermitian, unsigned int MAX_ITERATIONS=100) -{ - unitary = input; - MatType new_unitary(input); - MatType unitary_inv; - - if (fabs(unitary.det()) < math::Tolerance::value()) return false; - - unsigned int iteration(0); - - typename MatType::ValueType linf_of_u; - typename MatType::ValueType l1nm_of_u; - typename MatType::ValueType linf_of_u_inv; - typename MatType::ValueType l1nm_of_u_inv; - typename MatType::ValueType l1_error = 100; - double gamma; - - do { - unitary_inv = unitary.inverse(); - linf_of_u = lInfinityNorm(unitary); - l1nm_of_u = lOneNorm(unitary); - - linf_of_u_inv = lInfinityNorm(unitary_inv); - l1nm_of_u_inv = lOneNorm(unitary_inv); - - gamma = sqrt( sqrt( (l1nm_of_u_inv * linf_of_u_inv ) / (l1nm_of_u * linf_of_u) )); - - new_unitary = 0.5*(gamma * unitary + (1./gamma) * unitary_inv.transpose() ); - - l1_error = lInfinityNorm(unitary - new_unitary); - unitary = new_unitary; - - /// this generally converges in less than ten iterations - if (iteration > MAX_ITERATIONS) return false; - iteration++; - } while (l1_error > math::Tolerance::value()); - - positive_hermitian = unitary.transpose() * input; - return true; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_MAT_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Mat3.h b/openvdb_3_0_0_library/math/Mat3.h deleted file mode 100755 index 80688be..0000000 --- a/openvdb_3_0_0_library/math/Mat3.h +++ /dev/null @@ -1,821 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_MAT3_H_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_MAT3_H_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include "Vec3.h" -#include "Mat.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Vec3; -template class Mat4; -template class Quat; - -/// @class Mat3 Mat3.h -/// @brief 3x3 matrix class. -template -class Mat3: public Mat<3, T> -{ -public: - /// Data type held by the matrix. - typedef T value_type; - typedef T ValueType; - typedef Mat<3, T> MyBase; - /// Trivial constructor, the matrix is NOT initialized - Mat3() {} - - /// Constructor given the quaternion rotation, e.g. Mat3f m(q); - /// The quaternion is normalized and used to construct the matrix - Mat3(const Quat &q) - { setToRotation(q); } - - - /// Constructor given array of elements, the ordering is in row major form: - /** @verbatim - a b c - d e f - g h i - @endverbatim */ - template - Mat3(Source a, Source b, Source c, - Source d, Source e, Source f, - Source g, Source h, Source i) - { - MyBase::mm[0] = static_cast(a); - MyBase::mm[1] = static_cast(b); - MyBase::mm[2] = static_cast(c); - MyBase::mm[3] = static_cast(d); - MyBase::mm[4] = static_cast(e); - MyBase::mm[5] = static_cast(f); - MyBase::mm[6] = static_cast(g); - MyBase::mm[7] = static_cast(h); - MyBase::mm[8] = static_cast(i); - } // constructor1Test - - /// Construct matrix given basis vectors (columns) - template - Mat3(const Vec3 &v1, const Vec3 &v2, const Vec3 &v3) - { setBasis(v1, v2, v3); } - - /// Constructor given array of elements, the ordering is in row major form:\n - /// a[0] a[1] a[2]\n - /// a[3] a[4] a[5]\n - /// a[6] a[7] a[8]\n - template - Mat3(Source *a) - { - MyBase::mm[0] = a[0]; - MyBase::mm[1] = a[1]; - MyBase::mm[2] = a[2]; - MyBase::mm[3] = a[3]; - MyBase::mm[4] = a[4]; - MyBase::mm[5] = a[5]; - MyBase::mm[6] = a[6]; - MyBase::mm[7] = a[7]; - MyBase::mm[8] = a[8]; - } // constructor1Test - - /// Copy constructor - Mat3(const Mat<3, T> &m) - { - for (int i=0; i<3; ++i) { - for (int j=0; j<3; ++j) { - MyBase::mm[i*3 + j] = m[i][j]; - } - } - } - - /// Conversion constructor - template - explicit Mat3(const Mat3 &m) - { - for (int i=0; i<3; ++i) { - for (int j=0; j<3; ++j) { - MyBase::mm[i*3 + j] = m[i][j]; - } - } - } - - /// Conversion from Mat4 (copies top left) - explicit Mat3(const Mat4 &m) - { - for (int i=0; i<3; ++i) { - for (int j=0; j<3; ++j) { - MyBase::mm[i*3 + j] = m[i][j]; - } - } - } - - /// Predefined constant for identity matrix - static const Mat3& identity() { - return sIdentity; - } - - /// Predefined constant for zero matrix - static const Mat3& zero() { - return sZero; - } - - /// Set ith row to vector v - void setRow(int i, const Vec3 &v) - { - // assert(i>=0 && i<3); - int i3 = i * 3; - - MyBase::mm[i3+0] = v[0]; - MyBase::mm[i3+1] = v[1]; - MyBase::mm[i3+2] = v[2]; - } // rowColumnTest - - /// Get ith row, e.g. Vec3d v = m.row(1); - Vec3 row(int i) const - { - // assert(i>=0 && i<3); - return Vec3((*this)(i,0), (*this)(i,1), (*this)(i,2)); - } // rowColumnTest - - /// Set jth column to vector v - void setCol(int j, const Vec3& v) - { - // assert(j>=0 && j<3); - MyBase::mm[0+j] = v[0]; - MyBase::mm[3+j] = v[1]; - MyBase::mm[6+j] = v[2]; - } // rowColumnTest - - /// Get jth column, e.g. Vec3d v = m.col(0); - Vec3 col(int j) const - { - // assert(j>=0 && j<3); - return Vec3((*this)(0,j), (*this)(1,j), (*this)(2,j)); - } // rowColumnTest - - // NB: The following two methods were changed to - // work around a gccWS5 compiler issue related to strict - // aliasing (see FX-475). - - //@{ - /// Array style reference to ith row - /// e.g. m[1][2] = 4; - T* operator[](int i) { return &(MyBase::mm[i*3]); } - const T* operator[](int i) const { return &(MyBase::mm[i*3]); } - //@} - - T* asPointer() {return MyBase::mm;} - const T* asPointer() const {return MyBase::mm;} - - /// Alternative indexed reference to the elements - /// Note that the indices are row first and column second. - /// e.g. m(0,0) = 1; - T& operator()(int i, int j) - { - // assert(i>=0 && i<3); - // assert(j>=0 && j<3); - return MyBase::mm[3*i+j]; - } // trivial - - /// Alternative indexed constant reference to the elements, - /// Note that the indices are row first and column second. - /// e.g. float f = m(1,0); - T operator()(int i, int j) const - { - // assert(i>=0 && i<3); - // assert(j>=0 && j<3); - return MyBase::mm[3*i+j]; - } // trivial - - /// Set the columns of "this" matrix to the vectors v1, v2, v3 - void setBasis(const Vec3 &v1, const Vec3 &v2, const Vec3 &v3) - { - MyBase::mm[0] = v1[0]; - MyBase::mm[1] = v1[1]; - MyBase::mm[2] = v1[2]; - MyBase::mm[3] = v2[0]; - MyBase::mm[4] = v2[1]; - MyBase::mm[5] = v2[2]; - MyBase::mm[6] = v3[0]; - MyBase::mm[7] = v3[1]; - MyBase::mm[8] = v3[2]; - } // setBasisTest - - /// Set diagonal and symmetric triangular components - void setSymmetric(const Vec3 &vdiag, const Vec3 &vtri) - { - MyBase::mm[0] = vdiag[0]; - MyBase::mm[1] = vtri[0]; - MyBase::mm[2] = vtri[1]; - MyBase::mm[3] = vtri[0]; - MyBase::mm[4] = vdiag[1]; - MyBase::mm[5] = vtri[2]; - MyBase::mm[6] = vtri[1]; - MyBase::mm[7] = vtri[2]; - MyBase::mm[8] = vdiag[2]; - } // setSymmetricTest - - /// Returns matrix with prescribed diagonal and symmetric triangular - /// components - static Mat3 symmetric(const Vec3 &vdiag, const Vec3 &vtri) - { - return Mat3( - vdiag[0], vtri[0], vtri[1], - vtri[0], vdiag[1], vtri[2], - vtri[1], vtri[2], vdiag[2] - ); - } - - /// Set the matrix as cross product of the given vector - void setSkew(const Vec3 &v) - {*this = skew(v);} - - /// @brief Set this matrix to the rotation matrix specified by the quaternion - /// @details The quaternion is normalized and used to construct the matrix. - /// Note that the matrix is transposed to match post-multiplication semantics. - void setToRotation(const Quat &q) - {*this = rotation >(q);} - - /// @brief Set this matrix to the rotation specified by @a axis and @a angle - /// @details The axis must be unit vector - void setToRotation(const Vec3 &axis, T angle) - {*this = rotation >(axis, angle);} - - /// Set this matrix to zero - void setZero() - { - MyBase::mm[0] = 0; - MyBase::mm[1] = 0; - MyBase::mm[2] = 0; - MyBase::mm[3] = 0; - MyBase::mm[4] = 0; - MyBase::mm[5] = 0; - MyBase::mm[6] = 0; - MyBase::mm[7] = 0; - MyBase::mm[8] = 0; - } // trivial - - /// Set "this" matrix to identity - void setIdentity() - { - MyBase::mm[0] = 1; - MyBase::mm[1] = 0; - MyBase::mm[2] = 0; - MyBase::mm[3] = 0; - MyBase::mm[4] = 1; - MyBase::mm[5] = 0; - MyBase::mm[6] = 0; - MyBase::mm[7] = 0; - MyBase::mm[8] = 1; - } // trivial - - /// Assignment operator - template - const Mat3& operator=(const Mat3 &m) - { - const Source *src = m.asPointer(); - - // don't suppress type conversion warnings - std::copy(src, (src + this->numElements()), MyBase::mm); - return *this; - } // opEqualToTest - - /// Test if "this" is equivalent to m with tolerance of eps value - bool eq(const Mat3 &m, T eps=1.0e-8) const - { - return (isApproxEqual(MyBase::mm[0],m.mm[0],eps) && - isApproxEqual(MyBase::mm[1],m.mm[1],eps) && - isApproxEqual(MyBase::mm[2],m.mm[2],eps) && - isApproxEqual(MyBase::mm[3],m.mm[3],eps) && - isApproxEqual(MyBase::mm[4],m.mm[4],eps) && - isApproxEqual(MyBase::mm[5],m.mm[5],eps) && - isApproxEqual(MyBase::mm[6],m.mm[6],eps) && - isApproxEqual(MyBase::mm[7],m.mm[7],eps) && - isApproxEqual(MyBase::mm[8],m.mm[8],eps)); - } // trivial - - /// Negation operator, for e.g. m1 = -m2; - Mat3 operator-() const - { - return Mat3( - -MyBase::mm[0], -MyBase::mm[1], -MyBase::mm[2], - -MyBase::mm[3], -MyBase::mm[4], -MyBase::mm[5], - -MyBase::mm[6], -MyBase::mm[7], -MyBase::mm[8] - ); - } // trivial - - /// Multiplication operator, e.g. M = scalar * M; - // friend Mat3 operator*(T scalar, const Mat3& m) { - // return m*scalar; - // } - - /// @brief Returns m, where \f$m_{i,j} *= scalar\f$ for \f$i, j \in [0, 2]\f$ - template - const Mat3& operator*=(S scalar) - { - MyBase::mm[0] *= scalar; - MyBase::mm[1] *= scalar; - MyBase::mm[2] *= scalar; - MyBase::mm[3] *= scalar; - MyBase::mm[4] *= scalar; - MyBase::mm[5] *= scalar; - MyBase::mm[6] *= scalar; - MyBase::mm[7] *= scalar; - MyBase::mm[8] *= scalar; - return *this; - } - - /// @brief Returns m0, where \f$m0_{i,j} += m1_{i,j}\f$ for \f$i, j \in [0, 2]\f$ - template - const Mat3 &operator+=(const Mat3 &m1) - { - const S *s = m1.asPointer(); - - MyBase::mm[0] += s[0]; - MyBase::mm[1] += s[1]; - MyBase::mm[2] += s[2]; - MyBase::mm[3] += s[3]; - MyBase::mm[4] += s[4]; - MyBase::mm[5] += s[5]; - MyBase::mm[6] += s[6]; - MyBase::mm[7] += s[7]; - MyBase::mm[8] += s[8]; - return *this; - } - - /// @brief Returns m0, where \f$m0_{i,j} -= m1_{i,j}\f$ for \f$i, j \in [0, 2]\f$ - template - const Mat3 &operator-=(const Mat3 &m1) - { - const S *s = m1.asPointer(); - - MyBase::mm[0] -= s[0]; - MyBase::mm[1] -= s[1]; - MyBase::mm[2] -= s[2]; - MyBase::mm[3] -= s[3]; - MyBase::mm[4] -= s[4]; - MyBase::mm[5] -= s[5]; - MyBase::mm[6] -= s[6]; - MyBase::mm[7] -= s[7]; - MyBase::mm[8] -= s[8]; - return *this; - } - - /// @brief Returns m0, where \f$m0_{i,j} *= m1_{i,j}\f$ for \f$i, j \in [0, 2]\f$ - template - const Mat3 &operator*=(const Mat3 &m1) - { - Mat3 m0(*this); - const T* s0 = m0.asPointer(); - const S* s1 = m1.asPointer(); - - MyBase::mm[0] = static_cast(s0[0] * s1[0] + - s0[1] * s1[3] + - s0[2] * s1[6]); - MyBase::mm[1] = static_cast(s0[0] * s1[1] + - s0[1] * s1[4] + - s0[2] * s1[7]); - MyBase::mm[2] = static_cast(s0[0] * s1[2] + - s0[1] * s1[5] + - s0[2] * s1[8]); - - MyBase::mm[3] = static_cast(s0[3] * s1[0] + - s0[4] * s1[3] + - s0[5] * s1[6]); - MyBase::mm[4] = static_cast(s0[3] * s1[1] + - s0[4] * s1[4] + - s0[5] * s1[7]); - MyBase::mm[5] = static_cast(s0[3] * s1[2] + - s0[4] * s1[5] + - s0[5] * s1[8]); - - MyBase::mm[6] = static_cast(s0[6] * s1[0] + - s0[7] * s1[3] + - s0[8] * s1[6]); - MyBase::mm[7] = static_cast(s0[6] * s1[1] + - s0[7] * s1[4] + - s0[8] * s1[7]); - MyBase::mm[8] = static_cast(s0[6] * s1[2] + - s0[7] * s1[5] + - s0[8] * s1[8]); - - return *this; - } - - /// returns adjoint of m - Mat3 adjoint() const - { - return Mat3( - MyBase::mm[4] * MyBase::mm[8] - MyBase::mm[5] * MyBase::mm[7], - MyBase::mm[2] * MyBase::mm[7] - MyBase::mm[1] * MyBase::mm[8], - MyBase::mm[1] * MyBase::mm[5] - MyBase::mm[2] * MyBase::mm[4], - MyBase::mm[5] * MyBase::mm[6] - MyBase::mm[3] * MyBase::mm[8], - MyBase::mm[0] * MyBase::mm[8] - MyBase::mm[2] * MyBase::mm[6], - MyBase::mm[2] * MyBase::mm[3] - MyBase::mm[0] * MyBase::mm[5], - MyBase::mm[3] * MyBase::mm[7] - MyBase::mm[4] * MyBase::mm[6], - MyBase::mm[1] * MyBase::mm[6] - MyBase::mm[0] * MyBase::mm[7], - MyBase::mm[0] * MyBase::mm[4] - MyBase::mm[1] * MyBase::mm[3]); - } // adjointTest - - /// returns transpose of this - Mat3 transpose() const - { - return Mat3( - MyBase::mm[0], MyBase::mm[3], MyBase::mm[6], - MyBase::mm[1], MyBase::mm[4], MyBase::mm[7], - MyBase::mm[2], MyBase::mm[5], MyBase::mm[8]); - - } // transposeTest - - /// returns inverse of this - /// throws FailedOperationException if singular - Mat3 inverse(T tolerance = 0) const - { - Mat3 inv(adjoint()); - - T det = inv.mm[0]*MyBase::mm[0] + inv.mm[1]*MyBase::mm[3] + inv.mm[2]*MyBase::mm[6]; - - // If the determinant is 0, m was singular and "this" will contain junk. - if (isApproxEqual(det,0.0,tolerance)) - { - OPENVDB_THROW(ArithmeticError, "Inversion of singular 3x3 matrix"); - } - return inv * (T(1)/det); - } // invertTest - - /// Determinant of matrix - T det() const - { - T co00 = MyBase::mm[4]*MyBase::mm[8] - MyBase::mm[5]*MyBase::mm[7]; - T co10 = MyBase::mm[5]*MyBase::mm[6] - MyBase::mm[3]*MyBase::mm[8]; - T co20 = MyBase::mm[3]*MyBase::mm[7] - MyBase::mm[4]*MyBase::mm[6]; - T d = MyBase::mm[0]*co00 + MyBase::mm[1]*co10 + MyBase::mm[2]*co20; - return d; - } // determinantTest - - /// Trace of matrix - T trace() const - { - return MyBase::mm[0]+MyBase::mm[4]+MyBase::mm[8]; - } - - /// This function snaps a specific axis to a specific direction, - /// preserving scaling. It does this using minimum energy, thus - /// posing a unique solution if basis & direction arent parralel. - /// Direction need not be unit. - Mat3 snapBasis(Axis axis, const Vec3 &direction) - { - return snapBasis(*this, axis, direction); - } - - /// Return the transformed vector by "this" matrix. - /// This function is equivalent to post-multiplying the matrix. - template - Vec3 transform(const Vec3 &v) const - { - return static_cast< Vec3 >(v * *this); - } // xformVectorTest - - /// Return the transformed vector by transpose of "this" matrix. - /// This function is equivalent to pre-multiplying the matrix. - template - Vec3 pretransform(const Vec3 &v) const - { - return static_cast< Vec3 >(*this * v); - } // xformTVectorTest - - /// This function snaps a specific axis to a specific direction, - /// preserving scaling. It does this using minimum energy, thus - /// posing a unique solution if basis & direction arent parralel. - /// Direction need not be unit. - template - Mat3 snappedBasis(Axis axis, const Vec3& direction) const - { - return snapBasis(*this, axis, direction); - } - -private: - static const Mat3 sIdentity; - static const Mat3 sZero; -}; // class Mat3 - - -template -const Mat3 Mat3::sIdentity = Mat3(1, 0, 0, - 0, 1, 0, - 0, 0, 1); - -template -const Mat3 Mat3::sZero = Mat3(0, 0, 0, - 0, 0, 0, - 0, 0, 0); - -/// @relates Mat3 -/// @brief Equality operator, does exact floating point comparisons -template -bool operator==(const Mat3 &m0, const Mat3 &m1) -{ - const T0 *t0 = m0.asPointer(); - const T1 *t1 = m1.asPointer(); - - for (int i=0; i<9; ++i) { - if (!isExactlyEqual(t0[i], t1[i])) return false; - } - return true; -} - -/// @relates Mat3 -/// @brief Inequality operator, does exact floating point comparisons -template -bool operator!=(const Mat3 &m0, const Mat3 &m1) { return !(m0 == m1); } - -/// @relates Mat3 -/// @brief Returns M, where \f$M_{i,j} = m_{i,j} * scalar\f$ for \f$i, j \in [0, 2]\f$ -template -Mat3::type> operator*(S scalar, const Mat3 &m) -{ return m*scalar; } - -/// @relates Mat3 -/// @brief Returns M, where \f$M_{i,j} = m_{i,j} * scalar\f$ for \f$i, j \in [0, 2]\f$ -template -Mat3::type> operator*(const Mat3 &m, S scalar) -{ - Mat3::type> result(m); - result *= scalar; - return result; -} - -/// @relates Mat3 -/// @brief Returns M, where \f$M_{i,j} = m0_{i,j} + m1_{i,j}\f$ for \f$i, j \in [0, 2]\f$ -template -Mat3::type> operator+(const Mat3 &m0, const Mat3 &m1) -{ - Mat3::type> result(m0); - result += m1; - return result; -} - -/// @relates Mat3 -/// @brief Returns M, where \f$M_{i,j} = m0_{i,j} - m1_{i,j}\f$ for \f$i, j \in [0, 2]\f$ -template -Mat3::type> operator-(const Mat3 &m0, const Mat3 &m1) -{ - Mat3::type> result(m0); - result -= m1; - return result; -} - - -/// @brief Matrix multiplication. -/// -/// Returns M, where -/// \f$M_{ij} = \sum_{n=0}^2\left(m0_{nj} + m1_{in}\right)\f$ for \f$i, j \in [0, 2]\f$ -template -Mat3::type>operator*(const Mat3 &m0, const Mat3 &m1) -{ - Mat3::type> result(m0); - result *= m1; - return result; -} - -/// @relates Mat3 -/// @brief Returns v, where \f$v_{i} = \sum_{n=0}^2 m_{i,n} * v_n\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> -operator*(const Mat3 &_m, const Vec3 &_v) -{ - MT const *m = _m.asPointer(); - return Vec3::type>( - _v[0]*m[0] + _v[1]*m[1] + _v[2]*m[2], - _v[0]*m[3] + _v[1]*m[4] + _v[2]*m[5], - _v[0]*m[6] + _v[1]*m[7] + _v[2]*m[8]); -} - -/// @relates Mat3 -/// @brief Returns v, where \f$v_{i} = \sum_{n=0}^2 m_{n,i} * v_n\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> -operator*(const Vec3 &_v, const Mat3 &_m) -{ - MT const *m = _m.asPointer(); - return Vec3::type>( - _v[0]*m[0] + _v[1]*m[3] + _v[2]*m[6], - _v[0]*m[1] + _v[1]*m[4] + _v[2]*m[7], - _v[0]*m[2] + _v[1]*m[5] + _v[2]*m[8]); -} - -/// @relates Mat3 -/// @brief Returns v, where \f$v_{i} = \sum_{n=0}^2 m_{i,n} * v_n\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3 &operator *= (Vec3 &_v, const Mat3 &_m) -{ - Vec3 mult = _v * _m; - _v = mult; - return _v; -} - -/// this = outer product of v1, v2 -/// e.g. M = Mat3f::outerproduct(v1,v2); -template -Mat3 outerProduct(const Vec3& v1, const Vec3& v2) -{ - Mat3 m; - - m.setBasis(Vec3(v1[0]*v2[0], v1[1]*v2[0], v1[2]*v2[0]), - Vec3(v1[0]*v2[1], v1[1]*v2[1], v1[2]*v2[1]), - Vec3(v1[0]*v2[2], v1[1]*v2[2], v1[2]*v2[2])); - - return m; -} // outerproductTest - -typedef Mat3 Mat3s; -typedef Mat3 Mat3d; - -#if DWREAL_IS_DOUBLE == 1 -typedef Mat3d Mat3f; -#else -typedef Mat3s Mat3f; -#endif // DWREAL_IS_DOUBLE - - -/// Interpolate the rotation between m1 and m2 using Mat::powSolve. -/// Unlike slerp, translation is not treated independently. -/// This results in smoother animation results. -template -Mat3 powLerp(const Mat3 &m1, const Mat3 &m2, T t) -{ - Mat3 x = m1.inverse() * m2; - powSolve(x, x, t); - Mat3 m = m1 * x; - return m; -} - - -namespace { - template - void pivot(int i, int j, Mat3& S, Vec3& D, Mat3& Q) - { - const int& n = Mat3::size; // should be 3 - T temp; - /// scratch variables used in pivoting - double cotan_of_2_theta; - double tan_of_theta; - double cosin_of_theta; - double sin_of_theta; - double z; - - double Sij = S(i,j); - - double Sjj_minus_Sii = D[j] - D[i]; - - if (fabs(Sjj_minus_Sii) * (10*math::Tolerance::value()) > fabs(Sij)) { - tan_of_theta = Sij / Sjj_minus_Sii; - } else { - /// pivot on Sij - cotan_of_2_theta = 0.5*Sjj_minus_Sii / Sij ; - - if (cotan_of_2_theta < 0.) { - tan_of_theta = - -1./(sqrt(1. + cotan_of_2_theta*cotan_of_2_theta) - cotan_of_2_theta); - } else { - tan_of_theta = - 1./(sqrt(1. + cotan_of_2_theta*cotan_of_2_theta) + cotan_of_2_theta); - } - } - - cosin_of_theta = 1./sqrt( 1. + tan_of_theta * tan_of_theta); - sin_of_theta = cosin_of_theta * tan_of_theta; - z = tan_of_theta * Sij; - S(i,j) = 0; - D[i] -= z; - D[j] += z; - for (int k = 0; k < i; ++k) { - temp = S(k,i); - S(k,i) = cosin_of_theta * temp - sin_of_theta * S(k,j); - S(k,j)= sin_of_theta * temp + cosin_of_theta * S(k,j); - } - for (int k = i+1; k < j; ++k) { - temp = S(i,k); - S(i,k) = cosin_of_theta * temp - sin_of_theta * S(k,j); - S(k,j) = sin_of_theta * temp + cosin_of_theta * S(k,j); - } - for (int k = j+1; k < n; ++k) { - temp = S(i,k); - S(i,k) = cosin_of_theta * temp - sin_of_theta * S(j,k); - S(j,k) = sin_of_theta * temp + cosin_of_theta * S(j,k); - } - for (int k = 0; k < n; ++k) - { - temp = Q(k,i); - Q(k,i) = cosin_of_theta * temp - sin_of_theta*Q(k,j); - Q(k,j) = sin_of_theta * temp + cosin_of_theta*Q(k,j); - } - } -} - - -/// @brief Use Jacobi iterations to decompose a symmetric 3x3 matrix -/// (diagonalize and compute eigenvectors) -/// @details This is based on the "Efficient numerical diagonalization of Hermitian 3x3 matrices" -/// Joachim Kopp. arXiv.org preprint: physics/0610206 -/// with the addition of largest pivot -template -bool diagonalizeSymmetricMatrix(const Mat3& input, Mat3& Q, Vec3& D, - unsigned int MAX_ITERATIONS=250) -{ - /// use Givens rotation matrix to eliminate off-diagonal entries. - /// initialize the rotation matrix as idenity - Q = Mat3::identity(); - int n = Mat3::size; // should be 3 - - /// temp matrix. Assumed to be symmetric - Mat3 S(input); - - for (int i = 0; i < n; ++i) { - D[i] = S(i,i); - } - - unsigned int iterations(0); - /// Just iterate over all the non-diagonal enteries - /// using the largest as a pivot. - do { - /// check for absolute convergence - /// are symmetric off diagonals all zero - double er = 0; - for (int i = 0; i < n; ++i) { - for (int j = i+1; j < n; ++j) { - er += fabs(S(i,j)); - } - } - if (std::abs(er) < math::Tolerance::value()) { - return true; - } - iterations++; - - T max_element = 0; - int ip = 0; - int jp = 0; - /// loop over all the off-diagonals above the diagonal - for (int i = 0; i < n; ++i) { - for (int j = i+1; j < n; ++j){ - - if ( fabs(D[i]) * (10*math::Tolerance::value()) > fabs(S(i,j))) { - /// value too small to pivot on - S(i,j) = 0; - } - if (fabs(S(i,j)) > max_element) { - max_element = fabs(S(i,j)); - ip = i; - jp = j; - } - } - } - pivot(ip, jp, S, D, Q); - } while (iterations < MAX_ITERATIONS); - - return false; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_MAT3_H_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Mat4.h b/openvdb_3_0_0_library/math/Mat4.h deleted file mode 100755 index 956f11f..0000000 --- a/openvdb_3_0_0_library/math/Mat4.h +++ /dev/null @@ -1,1368 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_MAT4_H_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_MAT4_H_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "Math.h" -#include "Mat3.h" -#include "Vec3.h" -#include "Vec4.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Vec4; - - -/// @class Mat4 Mat4.h -/// @brief 4x4 -matrix class. -template -class Mat4: public Mat<4, T> -{ -public: - /// Data type held by the matrix. - typedef T value_type; - typedef T ValueType; - typedef Mat<4, T> MyBase; - - /// Trivial constructor, the matrix is NOT initialized - Mat4() {} - - /// Constructor given array of elements, the ordering is in row major form: - /** @verbatim - a[ 0] a[1] a[ 2] a[ 3] - a[ 4] a[5] a[ 6] a[ 7] - a[ 8] a[9] a[10] a[11] - a[12] a[13] a[14] a[15] - @endverbatim */ - template - Mat4(Source *a) - { - for (int i = 0; i < 16; i++) { - MyBase::mm[i] = a[i]; - } - } - - /// Constructor given array of elements, the ordering is in row major form: - /** @verbatim - a b c d - e f g h - i j k l - m n o p - @endverbatim */ - template - Mat4(Source a, Source b, Source c, Source d, - Source e, Source f, Source g, Source h, - Source i, Source j, Source k, Source l, - Source m, Source n, Source o, Source p) - { - MyBase::mm[ 0] = T(a); - MyBase::mm[ 1] = T(b); - MyBase::mm[ 2] = T(c); - MyBase::mm[ 3] = T(d); - - MyBase::mm[ 4] = T(e); - MyBase::mm[ 5] = T(f); - MyBase::mm[ 6] = T(g); - MyBase::mm[ 7] = T(h); - - MyBase::mm[ 8] = T(i); - MyBase::mm[ 9] = T(j); - MyBase::mm[10] = T(k); - MyBase::mm[11] = T(l); - - MyBase::mm[12] = T(m); - MyBase::mm[13] = T(n); - MyBase::mm[14] = T(o); - MyBase::mm[15] = T(p); - } - - /// Construct matrix given basis vectors (columns) - template - Mat4(const Vec4 &v1, const Vec4 &v2, - const Vec4 &v3, const Vec4 &v4) - { - setBasis(v1, v2, v3, v4); - } - - /// Copy constructor - Mat4(const Mat<4, T> &m) - { - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - MyBase::mm[i*4 + j] = m[i][j]; - } - } - } - - /// Conversion constructor - template - explicit Mat4(const Mat4 &m) - { - const Source *src = m.asPointer(); - - for (int i=0; i<16; ++i) { - MyBase::mm[i] = static_cast(src[i]); - } - } - - /// Predefined constant for identity matrix - static const Mat4& identity() { - return sIdentity; - } - - /// Predefined constant for zero matrix - static const Mat4& zero() { - return sZero; - } - - /// Set ith row to vector v - void setRow(int i, const Vec4 &v) - { - // assert(i>=0 && i<4); - int i4 = i * 4; - MyBase::mm[i4+0] = v[0]; - MyBase::mm[i4+1] = v[1]; - MyBase::mm[i4+2] = v[2]; - MyBase::mm[i4+3] = v[3]; - } - - /// Get ith row, e.g. Vec4f v = m.row(1); - Vec4 row(int i) const - { - // assert(i>=0 && i<3); - return Vec4((*this)(i,0), (*this)(i,1), (*this)(i,2), (*this)(i,3)); - } - - /// Set jth column to vector v - void setCol(int j, const Vec4& v) - { - // assert(j>=0 && j<4); - MyBase::mm[ 0+j] = v[0]; - MyBase::mm[ 4+j] = v[1]; - MyBase::mm[ 8+j] = v[2]; - MyBase::mm[12+j] = v[3]; - } - - /// Get jth column, e.g. Vec4f v = m.col(0); - Vec4 col(int j) const - { - // assert(j>=0 && j<4); - return Vec4((*this)(0,j), (*this)(1,j), (*this)(2,j), (*this)(3,j)); - } - - //@{ - /// Array style reference to ith row - /// e.g. m[1][3] = 4; - T* operator[](int i) { return &(MyBase::mm[i<<2]); } - const T* operator[](int i) const { return &(MyBase::mm[i<<2]); } - //@} - - /// Direct access to the internal data - T* asPointer() {return MyBase::mm;} - const T* asPointer() const {return MyBase::mm;} - - /// Alternative indexed reference to the elements - /// Note that the indices are row first and column second. - /// e.g. m(0,0) = 1; - T& operator()(int i, int j) - { - // assert(i>=0 && i<4); - // assert(j>=0 && j<4); - return MyBase::mm[4*i+j]; - } - - /// Alternative indexed constant reference to the elements, - /// Note that the indices are row first and column second. - /// e.g. float f = m(1,0); - T operator()(int i, int j) const - { - // assert(i>=0 && i<4); - // assert(j>=0 && j<4); - return MyBase::mm[4*i+j]; - } - - /// Set the columns of "this" matrix to the vectors v1, v2, v3, v4 - void setBasis(const Vec4 &v1, const Vec4 &v2, - const Vec4 &v3, const Vec4 &v4) - { - MyBase::mm[ 0] = v1[0]; - MyBase::mm[ 1] = v1[1]; - MyBase::mm[ 2] = v1[2]; - MyBase::mm[ 3] = v1[3]; - - MyBase::mm[ 4] = v2[0]; - MyBase::mm[ 5] = v2[1]; - MyBase::mm[ 6] = v2[2]; - MyBase::mm[ 7] = v2[3]; - - MyBase::mm[ 8] = v3[0]; - MyBase::mm[ 9] = v3[1]; - MyBase::mm[10] = v3[2]; - MyBase::mm[11] = v3[3]; - - MyBase::mm[12] = v4[0]; - MyBase::mm[13] = v4[1]; - MyBase::mm[14] = v4[2]; - MyBase::mm[15] = v4[3]; - } - - - // Set "this" matrix to zero - void setZero() - { - MyBase::mm[ 0] = 0; - MyBase::mm[ 1] = 0; - MyBase::mm[ 2] = 0; - MyBase::mm[ 3] = 0; - MyBase::mm[ 4] = 0; - MyBase::mm[ 5] = 0; - MyBase::mm[ 6] = 0; - MyBase::mm[ 7] = 0; - MyBase::mm[ 8] = 0; - MyBase::mm[ 9] = 0; - MyBase::mm[10] = 0; - MyBase::mm[11] = 0; - MyBase::mm[12] = 0; - MyBase::mm[13] = 0; - MyBase::mm[14] = 0; - MyBase::mm[15] = 0; - } - - /// Set "this" matrix to identity - void setIdentity() - { - MyBase::mm[ 0] = 1; - MyBase::mm[ 1] = 0; - MyBase::mm[ 2] = 0; - MyBase::mm[ 3] = 0; - - MyBase::mm[ 4] = 0; - MyBase::mm[ 5] = 1; - MyBase::mm[ 6] = 0; - MyBase::mm[ 7] = 0; - - MyBase::mm[ 8] = 0; - MyBase::mm[ 9] = 0; - MyBase::mm[10] = 1; - MyBase::mm[11] = 0; - - MyBase::mm[12] = 0; - MyBase::mm[13] = 0; - MyBase::mm[14] = 0; - MyBase::mm[15] = 1; - } - - - /// Set upper left to a Mat3 - void setMat3(const Mat3 &m) - { - for (int i = 0; i < 3; i++) - for (int j=0; j < 3; j++) - MyBase::mm[i*4+j] = m[i][j]; - } - - Mat3 getMat3() const - { - Mat3 m; - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m[i][j] = MyBase::mm[i*4+j]; - - return m; - } - - /// Return the translation component - Vec3 getTranslation() const - { - return Vec3(MyBase::mm[12], MyBase::mm[13], MyBase::mm[14]); - } - - void setTranslation(const Vec3 &t) - { - MyBase::mm[12] = t[0]; - MyBase::mm[13] = t[1]; - MyBase::mm[14] = t[2]; - } - - /// Assignment operator - template - const Mat4& operator=(const Mat4 &m) - { - const Source *src = m.asPointer(); - - // don't suppress warnings when assigning from different numerical types - std::copy(src, (src + this->numElements()), MyBase::mm); - return *this; - } - - /// Test if "this" is equivalent to m with tolerance of eps value - bool eq(const Mat4 &m, T eps=1.0e-8) const - { - for (int i = 0; i < 16; i++) { - if (!isApproxEqual(MyBase::mm[i], m.mm[i], eps)) - return false; - } - return true; - } - - /// Negation operator, for e.g. m1 = -m2; - Mat4 operator-() const - { - return Mat4( - -MyBase::mm[ 0], -MyBase::mm[ 1], -MyBase::mm[ 2], -MyBase::mm[ 3], - -MyBase::mm[ 4], -MyBase::mm[ 5], -MyBase::mm[ 6], -MyBase::mm[ 7], - -MyBase::mm[ 8], -MyBase::mm[ 9], -MyBase::mm[10], -MyBase::mm[11], - -MyBase::mm[12], -MyBase::mm[13], -MyBase::mm[14], -MyBase::mm[15] - ); - } // trivial - - /// Return m, where \f$m_{i,j} *= scalar\f$ for \f$i, j \in [0, 3]\f$ - template - const Mat4& operator*=(S scalar) - { - MyBase::mm[ 0] *= scalar; - MyBase::mm[ 1] *= scalar; - MyBase::mm[ 2] *= scalar; - MyBase::mm[ 3] *= scalar; - - MyBase::mm[ 4] *= scalar; - MyBase::mm[ 5] *= scalar; - MyBase::mm[ 6] *= scalar; - MyBase::mm[ 7] *= scalar; - - MyBase::mm[ 8] *= scalar; - MyBase::mm[ 9] *= scalar; - MyBase::mm[10] *= scalar; - MyBase::mm[11] *= scalar; - - MyBase::mm[12] *= scalar; - MyBase::mm[13] *= scalar; - MyBase::mm[14] *= scalar; - MyBase::mm[15] *= scalar; - return *this; - } - - /// @brief Returns m0, where \f$m0_{i,j} += m1_{i,j}\f$ for \f$i, j \in [0, 3]\f$ - template - const Mat4 &operator+=(const Mat4 &m1) - { - const S* s = m1.asPointer(); - - MyBase::mm[ 0] += s[ 0]; - MyBase::mm[ 1] += s[ 1]; - MyBase::mm[ 2] += s[ 2]; - MyBase::mm[ 3] += s[ 3]; - - MyBase::mm[ 4] += s[ 4]; - MyBase::mm[ 5] += s[ 5]; - MyBase::mm[ 6] += s[ 6]; - MyBase::mm[ 7] += s[ 7]; - - MyBase::mm[ 8] += s[ 8]; - MyBase::mm[ 9] += s[ 9]; - MyBase::mm[10] += s[10]; - MyBase::mm[11] += s[11]; - - MyBase::mm[12] += s[12]; - MyBase::mm[13] += s[13]; - MyBase::mm[14] += s[14]; - MyBase::mm[15] += s[15]; - - return *this; - } - - /// @brief Returns m0, where \f$m0_{i,j} -= m1_{i,j}\f$ for \f$i, j \in [0, 3]\f$ - template - const Mat4 &operator-=(const Mat4 &m1) - { - const S* s = m1.asPointer(); - - MyBase::mm[ 0] -= s[ 0]; - MyBase::mm[ 1] -= s[ 1]; - MyBase::mm[ 2] -= s[ 2]; - MyBase::mm[ 3] -= s[ 3]; - - MyBase::mm[ 4] -= s[ 4]; - MyBase::mm[ 5] -= s[ 5]; - MyBase::mm[ 6] -= s[ 6]; - MyBase::mm[ 7] -= s[ 7]; - - MyBase::mm[ 8] -= s[ 8]; - MyBase::mm[ 9] -= s[ 9]; - MyBase::mm[10] -= s[10]; - MyBase::mm[11] -= s[11]; - - MyBase::mm[12] -= s[12]; - MyBase::mm[13] -= s[13]; - MyBase::mm[14] -= s[14]; - MyBase::mm[15] -= s[15]; - - return *this; - } - - /// Return m, where \f$m_{i,j} = \sum_{k} m0_{i,k}*m1_{k,j}\f$ for \f$i, j \in [0, 3]\f$ - template - const Mat4 &operator*=(const Mat4 &m1) - { - Mat4 m0(*this); - - const T* s0 = m0.asPointer(); - const S* s1 = m1.asPointer(); - - for (int i = 0; i < 4; i++) { - int i4 = 4 * i; - MyBase::mm[i4+0] = static_cast(s0[i4+0] * s1[ 0] + - s0[i4+1] * s1[ 4] + - s0[i4+2] * s1[ 8] + - s0[i4+3] * s1[12]); - - MyBase::mm[i4+1] = static_cast(s0[i4+0] * s1[ 1] + - s0[i4+1] * s1[ 5] + - s0[i4+2] * s1[ 9] + - s0[i4+3] * s1[13]); - - MyBase::mm[i4+2] = static_cast(s0[i4+0] * s1[ 2] + - s0[i4+1] * s1[ 6] + - s0[i4+2] * s1[10] + - s0[i4+3] * s1[14]); - - MyBase::mm[i4+3] = static_cast(s0[i4+0] * s1[ 3] + - s0[i4+1] * s1[ 7] + - s0[i4+2] * s1[11] + - s0[i4+3] * s1[15]); - } - return *this; - } - - /// @return transpose of this - Mat4 transpose() const - { - return Mat4( - MyBase::mm[ 0], MyBase::mm[ 4], MyBase::mm[ 8], MyBase::mm[12], - MyBase::mm[ 1], MyBase::mm[ 5], MyBase::mm[ 9], MyBase::mm[13], - MyBase::mm[ 2], MyBase::mm[ 6], MyBase::mm[10], MyBase::mm[14], - MyBase::mm[ 3], MyBase::mm[ 7], MyBase::mm[11], MyBase::mm[15] - ); - } - - - /// @return inverse of this - /// @throw ArithmeticError if singular - Mat4 inverse(T tolerance = 0) const - { - // - // inv [ A | b ] = [ E | f ] A: 3x3, b: 3x1, c': 1x3 d: 1x1 - // [ c' | d ] [ g' | h ] - // - // If A is invertible use - // - // E = A^-1 + p*h*r - // p = A^-1 * b - // f = -p * h - // g' = -h * c' - // h = 1 / (d - c'*p) - // r' = c'*A^-1 - // - // Otherwise use gauss-jordan elimination - // - - // - // We create this alias to ourself so we can easily use own subscript - // operator. - const Mat4& m(*this); - - T m0011 = m[0][0] * m[1][1]; - T m0012 = m[0][0] * m[1][2]; - T m0110 = m[0][1] * m[1][0]; - T m0210 = m[0][2] * m[1][0]; - T m0120 = m[0][1] * m[2][0]; - T m0220 = m[0][2] * m[2][0]; - - T detA = m0011 * m[2][2] - m0012 * m[2][1] - m0110 * m[2][2] - + m0210 * m[2][1] + m0120 * m[1][2] - m0220 * m[1][1]; - - bool hasPerspective = - (!isExactlyEqual(m[0][3], T(0.0)) || - !isExactlyEqual(m[1][3], T(0.0)) || - !isExactlyEqual(m[2][3], T(0.0)) || - !isExactlyEqual(m[3][3], T(1.0))); - - T det; - if (hasPerspective) { - det = m[0][3] * det3(m, 1,2,3, 0,2,1) - + m[1][3] * det3(m, 2,0,3, 0,2,1) - + m[2][3] * det3(m, 3,0,1, 0,2,1) - + m[3][3] * detA; - } else { - det = detA * m[3][3]; - } - - Mat4 inv; - bool invertible; - - if (isApproxEqual(det,T(0.0),tolerance)) { - invertible = false; - - } else if (isApproxEqual(detA,T(0.0),T(1e-8))) { - // det is too small to rely on inversion by subblocks - invertible = m.invert(inv, tolerance); - - } else { - invertible = true; - detA = 1.0 / detA; - - // - // Calculate A^-1 - // - inv[0][0] = detA * ( m[1][1] * m[2][2] - m[1][2] * m[2][1]); - inv[0][1] = detA * (-m[0][1] * m[2][2] + m[0][2] * m[2][1]); - inv[0][2] = detA * ( m[0][1] * m[1][2] - m[0][2] * m[1][1]); - - inv[1][0] = detA * (-m[1][0] * m[2][2] + m[1][2] * m[2][0]); - inv[1][1] = detA * ( m[0][0] * m[2][2] - m0220); - inv[1][2] = detA * ( m0210 - m0012); - - inv[2][0] = detA * ( m[1][0] * m[2][1] - m[1][1] * m[2][0]); - inv[2][1] = detA * ( m0120 - m[0][0] * m[2][1]); - inv[2][2] = detA * ( m0011 - m0110); - - if (hasPerspective) { - // - // Calculate r, p, and h - // - Vec3 r; - r[0] = m[3][0] * inv[0][0] + m[3][1] * inv[1][0] - + m[3][2] * inv[2][0]; - r[1] = m[3][0] * inv[0][1] + m[3][1] * inv[1][1] - + m[3][2] * inv[2][1]; - r[2] = m[3][0] * inv[0][2] + m[3][1] * inv[1][2] - + m[3][2] * inv[2][2]; - - Vec3 p; - p[0] = inv[0][0] * m[0][3] + inv[0][1] * m[1][3] - + inv[0][2] * m[2][3]; - p[1] = inv[1][0] * m[0][3] + inv[1][1] * m[1][3] - + inv[1][2] * m[2][3]; - p[2] = inv[2][0] * m[0][3] + inv[2][1] * m[1][3] - + inv[2][2] * m[2][3]; - - T h = m[3][3] - p.dot(Vec3(m[3][0],m[3][1],m[3][2])); - if (isApproxEqual(h,T(0.0),tolerance)) { - invertible = false; - - } else { - h = 1.0 / h; - - // - // Calculate h, g, and f - // - inv[3][3] = h; - inv[3][0] = -h * r[0]; - inv[3][1] = -h * r[1]; - inv[3][2] = -h * r[2]; - - inv[0][3] = -h * p[0]; - inv[1][3] = -h * p[1]; - inv[2][3] = -h * p[2]; - - // - // Calculate E - // - p *= h; - inv[0][0] += p[0] * r[0]; - inv[0][1] += p[0] * r[1]; - inv[0][2] += p[0] * r[2]; - inv[1][0] += p[1] * r[0]; - inv[1][1] += p[1] * r[1]; - inv[1][2] += p[1] * r[2]; - inv[2][0] += p[2] * r[0]; - inv[2][1] += p[2] * r[1]; - inv[2][2] += p[2] * r[2]; - } - } else { - // Equations are much simpler in the non-perspective case - inv[3][0] = - (m[3][0] * inv[0][0] + m[3][1] * inv[1][0] - + m[3][2] * inv[2][0]); - inv[3][1] = - (m[3][0] * inv[0][1] + m[3][1] * inv[1][1] - + m[3][2] * inv[2][1]); - inv[3][2] = - (m[3][0] * inv[0][2] + m[3][1] * inv[1][2] - + m[3][2] * inv[2][2]); - inv[0][3] = 0.0; - inv[1][3] = 0.0; - inv[2][3] = 0.0; - inv[3][3] = 1.0; - } - } - - if (!invertible) OPENVDB_THROW(ArithmeticError, "Inversion of singular 4x4 matrix"); - return inv; - } - - - /// Determinant of matrix - T det() const - { - const T *ap; - Mat3 submat; - T det; - T *sp; - int i, j, k, sign; - - det = 0; - sign = 1; - for (i = 0; i < 4; i++) { - ap = &MyBase::mm[ 0]; - sp = submat.asPointer(); - for (j = 0; j < 4; j++) { - for (k = 0; k < 4; k++) { - if ((k != i) && (j != 0)) { - *sp++ = *ap; - } - ap++; - } - } - - det += sign * MyBase::mm[i] * submat.det(); - sign = -sign; - } - - return det; - } - - /// This function snaps a specific axis to a specific direction, - /// preserving scaling. It does this using minimum energy, thus - /// posing a unique solution if basis & direction arent parralel. - /// Direction need not be unit. - Mat4 snapBasis(Axis axis, const Vec3 &direction) - {return snapBasis(*this, axis, direction);} - - /// Sets the matrix to a matrix that translates by v - static Mat4 translation(const Vec3d& v) - { - return Mat4( - T(1), T(0), T(0), T(0), - T(0), T(1), T(0), T(0), - T(0), T(0), T(1), T(0), - T(v.x()), T(v.y()),T(v.z()), T(1)); - } - - /// Sets the matrix to a matrix that translates by v - template - void setToTranslation(const Vec3& v) - { - MyBase::mm[ 0] = 1; - MyBase::mm[ 1] = 0; - MyBase::mm[ 2] = 0; - MyBase::mm[ 3] = 0; - - MyBase::mm[ 4] = 0; - MyBase::mm[ 5] = 1; - MyBase::mm[ 6] = 0; - MyBase::mm[ 7] = 0; - - MyBase::mm[ 8] = 0; - MyBase::mm[ 9] = 0; - MyBase::mm[10] = 1; - MyBase::mm[11] = 0; - - MyBase::mm[12] = v.x(); - MyBase::mm[13] = v.y(); - MyBase::mm[14] = v.z(); - MyBase::mm[15] = 1; - } - - /// Left multiples by the specified translation, i.e. Trans * (*this) - template - void preTranslate(const Vec3& tr) - { - Vec3 tmp(tr.x(), tr.y(), tr.z()); - Mat4 Tr = Mat4::translation(tmp); - - *this = Tr * (*this); - - } - - /// Right multiplies by the specified translation matrix, i.e. (*this) * Trans - template - void postTranslate(const Vec3& tr) - { - Vec3 tmp(tr.x(), tr.y(), tr.z()); - Mat4 Tr = Mat4::translation(tmp); - - *this = (*this) * Tr; - - } - - - /// Sets the matrix to a matrix that scales by v - template - void setToScale(const Vec3& v) - { - this->setIdentity(); - MyBase::mm[ 0] = v.x(); - MyBase::mm[ 5] = v.y(); - MyBase::mm[10] = v.z(); - } - - // Left multiples by the specified scale matrix, i.e. Sc * (*this) - template - void preScale(const Vec3& v) - { - MyBase::mm[ 0] *= v.x(); - MyBase::mm[ 1] *= v.x(); - MyBase::mm[ 2] *= v.x(); - MyBase::mm[ 3] *= v.x(); - - MyBase::mm[ 4] *= v.y(); - MyBase::mm[ 5] *= v.y(); - MyBase::mm[ 6] *= v.y(); - MyBase::mm[ 7] *= v.y(); - - MyBase::mm[ 8] *= v.z(); - MyBase::mm[ 9] *= v.z(); - MyBase::mm[10] *= v.z(); - MyBase::mm[11] *= v.z(); - } - - - - // Right multiples by the specified scale matrix, i.e. (*this) * Sc - template - void postScale(const Vec3& v) - { - - MyBase::mm[ 0] *= v.x(); - MyBase::mm[ 1] *= v.y(); - MyBase::mm[ 2] *= v.z(); - - MyBase::mm[ 4] *= v.x(); - MyBase::mm[ 5] *= v.y(); - MyBase::mm[ 6] *= v.z(); - - MyBase::mm[ 8] *= v.x(); - MyBase::mm[ 9] *= v.y(); - MyBase::mm[10] *= v.z(); - - MyBase::mm[12] *= v.x(); - MyBase::mm[13] *= v.y(); - MyBase::mm[14] *= v.z(); - - } - - - /// @brief Sets the matrix to a rotation about the given axis. - /// @param axis The axis (one of X, Y, Z) to rotate about. - /// @param angle The rotation angle, in radians. - void setToRotation(Axis axis, T angle) {*this = rotation >(axis, angle);} - - /// @brief Sets the matrix to a rotation about an arbitrary axis - /// @param axis The axis of rotation (cannot be zero-length) - /// @param angle The rotation angle, in radians. - void setToRotation(const Vec3& axis, T angle) {*this = rotation >(axis, angle);} - - /// @brief Sets the matrix to a rotation that maps v1 onto v2 about the cross - /// product of v1 and v2. - void setToRotation(const Vec3& v1, const Vec3& v2) {*this = rotation >(v1, v2);} - - - /// @brief Left multiplies by a rotation clock-wiseabout the given axis into this matrix. - /// @param axis The axis (one of X, Y, Z) of rotation. - /// @param angle The clock-wise rotation angle, in radians. - void preRotate(Axis axis, T angle) - { - T c = static_cast(cos(angle)); - T s = -static_cast(sin(angle)); // the "-" makes it clockwise - - switch (axis) { - case X_AXIS: - { - T a4, a5, a6, a7; - - a4 = c * MyBase::mm[ 4] - s * MyBase::mm[ 8]; - a5 = c * MyBase::mm[ 5] - s * MyBase::mm[ 9]; - a6 = c * MyBase::mm[ 6] - s * MyBase::mm[10]; - a7 = c * MyBase::mm[ 7] - s * MyBase::mm[11]; - - - MyBase::mm[ 8] = s * MyBase::mm[ 4] + c * MyBase::mm[ 8]; - MyBase::mm[ 9] = s * MyBase::mm[ 5] + c * MyBase::mm[ 9]; - MyBase::mm[10] = s * MyBase::mm[ 6] + c * MyBase::mm[10]; - MyBase::mm[11] = s * MyBase::mm[ 7] + c * MyBase::mm[11]; - - MyBase::mm[ 4] = a4; - MyBase::mm[ 5] = a5; - MyBase::mm[ 6] = a6; - MyBase::mm[ 7] = a7; - } - break; - - case Y_AXIS: - { - T a0, a1, a2, a3; - - a0 = c * MyBase::mm[ 0] + s * MyBase::mm[ 8]; - a1 = c * MyBase::mm[ 1] + s * MyBase::mm[ 9]; - a2 = c * MyBase::mm[ 2] + s * MyBase::mm[10]; - a3 = c * MyBase::mm[ 3] + s * MyBase::mm[11]; - - MyBase::mm[ 8] = -s * MyBase::mm[ 0] + c * MyBase::mm[ 8]; - MyBase::mm[ 9] = -s * MyBase::mm[ 1] + c * MyBase::mm[ 9]; - MyBase::mm[10] = -s * MyBase::mm[ 2] + c * MyBase::mm[10]; - MyBase::mm[11] = -s * MyBase::mm[ 3] + c * MyBase::mm[11]; - - - MyBase::mm[ 0] = a0; - MyBase::mm[ 1] = a1; - MyBase::mm[ 2] = a2; - MyBase::mm[ 3] = a3; - } - break; - - case Z_AXIS: - { - T a0, a1, a2, a3; - - a0 = c * MyBase::mm[ 0] - s * MyBase::mm[ 4]; - a1 = c * MyBase::mm[ 1] - s * MyBase::mm[ 5]; - a2 = c * MyBase::mm[ 2] - s * MyBase::mm[ 6]; - a3 = c * MyBase::mm[ 3] - s * MyBase::mm[ 7]; - - MyBase::mm[ 4] = s * MyBase::mm[ 0] + c * MyBase::mm[ 4]; - MyBase::mm[ 5] = s * MyBase::mm[ 1] + c * MyBase::mm[ 5]; - MyBase::mm[ 6] = s * MyBase::mm[ 2] + c * MyBase::mm[ 6]; - MyBase::mm[ 7] = s * MyBase::mm[ 3] + c * MyBase::mm[ 7]; - - MyBase::mm[ 0] = a0; - MyBase::mm[ 1] = a1; - MyBase::mm[ 2] = a2; - MyBase::mm[ 3] = a3; - } - break; - - default: - assert(axis==X_AXIS || axis==Y_AXIS || axis==Z_AXIS); - } - } - - - /// @brief Right multiplies by a rotation clock-wiseabout the given axis into this matrix. - /// @param axis The axis (one of X, Y, Z) of rotation. - /// @param angle The clock-wise rotation angle, in radians. - void postRotate(Axis axis, T angle) - { - T c = static_cast(cos(angle)); - T s = -static_cast(sin(angle)); // the "-" makes it clockwise - - - - switch (axis) { - case X_AXIS: - { - T a2, a6, a10, a14; - - a2 = c * MyBase::mm[ 2] - s * MyBase::mm[ 1]; - a6 = c * MyBase::mm[ 6] - s * MyBase::mm[ 5]; - a10 = c * MyBase::mm[10] - s * MyBase::mm[ 9]; - a14 = c * MyBase::mm[14] - s * MyBase::mm[13]; - - - MyBase::mm[ 1] = c * MyBase::mm[ 1] + s * MyBase::mm[ 2]; - MyBase::mm[ 5] = c * MyBase::mm[ 5] + s * MyBase::mm[ 6]; - MyBase::mm[ 9] = c * MyBase::mm[ 9] + s * MyBase::mm[10]; - MyBase::mm[13] = c * MyBase::mm[13] + s * MyBase::mm[14]; - - MyBase::mm[ 2] = a2; - MyBase::mm[ 6] = a6; - MyBase::mm[10] = a10; - MyBase::mm[14] = a14; - } - break; - - case Y_AXIS: - { - T a2, a6, a10, a14; - - a2 = c * MyBase::mm[ 2] + s * MyBase::mm[ 0]; - a6 = c * MyBase::mm[ 6] + s * MyBase::mm[ 4]; - a10 = c * MyBase::mm[10] + s * MyBase::mm[ 8]; - a14 = c * MyBase::mm[14] + s * MyBase::mm[12]; - - MyBase::mm[ 0] = c * MyBase::mm[ 0] - s * MyBase::mm[ 2]; - MyBase::mm[ 4] = c * MyBase::mm[ 4] - s * MyBase::mm[ 6]; - MyBase::mm[ 8] = c * MyBase::mm[ 8] - s * MyBase::mm[10]; - MyBase::mm[12] = c * MyBase::mm[12] - s * MyBase::mm[14]; - - MyBase::mm[ 2] = a2; - MyBase::mm[ 6] = a6; - MyBase::mm[10] = a10; - MyBase::mm[14] = a14; - } - break; - - case Z_AXIS: - { - T a1, a5, a9, a13; - - a1 = c * MyBase::mm[ 1] - s * MyBase::mm[ 0]; - a5 = c * MyBase::mm[ 5] - s * MyBase::mm[ 4]; - a9 = c * MyBase::mm[ 9] - s * MyBase::mm[ 8]; - a13 = c * MyBase::mm[13] - s * MyBase::mm[12]; - - MyBase::mm[ 0] = c * MyBase::mm[ 0] + s * MyBase::mm[ 1]; - MyBase::mm[ 4] = c * MyBase::mm[ 4] + s * MyBase::mm[ 5]; - MyBase::mm[ 8] = c * MyBase::mm[ 8] + s * MyBase::mm[ 9]; - MyBase::mm[12] = c * MyBase::mm[12] + s * MyBase::mm[13]; - - MyBase::mm[ 1] = a1; - MyBase::mm[ 5] = a5; - MyBase::mm[ 9] = a9; - MyBase::mm[13] = a13; - - } - break; - - default: - assert(axis==X_AXIS || axis==Y_AXIS || axis==Z_AXIS); - } - } - - /// @brief Sets the matrix to a shear along axis0 by a fraction of axis1. - /// @param axis0 The fixed axis of the shear. - /// @param axis1 The shear axis. - /// @param shearby The shear factor. - void setToShear(Axis axis0, Axis axis1, T shearby) - { - *this = shear >(axis0, axis1, shearby); - } - - - /// @brief Left multiplies a shearing transformation into the matrix. - /// @see setToShear - void preShear(Axis axis0, Axis axis1, T shear) - { - int index0 = static_cast(axis0); - int index1 = static_cast(axis1); - - // to row "index1" add a multiple of the index0 row - MyBase::mm[index1 * 4 + 0] += shear * MyBase::mm[index0 * 4 + 0]; - MyBase::mm[index1 * 4 + 1] += shear * MyBase::mm[index0 * 4 + 1]; - MyBase::mm[index1 * 4 + 2] += shear * MyBase::mm[index0 * 4 + 2]; - MyBase::mm[index1 * 4 + 3] += shear * MyBase::mm[index0 * 4 + 3]; - } - - - /// @brief Right multiplies a shearing transformation into the matrix. - /// @see setToShear - void postShear(Axis axis0, Axis axis1, T shear) - { - int index0 = static_cast(axis0); - int index1 = static_cast(axis1); - - // to collumn "index0" add a multiple of the index1 row - MyBase::mm[index0 + 0] += shear * MyBase::mm[index1 + 0]; - MyBase::mm[index0 + 4] += shear * MyBase::mm[index1 + 4]; - MyBase::mm[index0 + 8] += shear * MyBase::mm[index1 + 8]; - MyBase::mm[index0 + 12] += shear * MyBase::mm[index1 + 12]; - - } - - /// Transform a Vec4 by post-multiplication. - template - Vec4 transform(const Vec4 &v) const - { - return static_cast< Vec4 >(v * *this); - } - - /// Transform a Vec3 by post-multiplication, without homogenous division. - template - Vec3 transform(const Vec3 &v) const - { - return static_cast< Vec3 >(v * *this); - } - - /// Transform a Vec4 by pre-multiplication. - template - Vec4 pretransform(const Vec4 &v) const - { - return static_cast< Vec4 >(*this * v); - } - - /// Transform a Vec3 by pre-multiplication, without homogenous division. - template - Vec3 pretransform(const Vec3 &v) const - { - return static_cast< Vec3 >(*this * v); - } - - /// Transform a Vec3 by post-multiplication, doing homogenous divison. - template - Vec3 transformH(const Vec3 &p) const - { - T0 w; - - // w = p * (*this).col(3); - w = static_cast(p[0] * MyBase::mm[ 3] + p[1] * MyBase::mm[ 7] - + p[2] * MyBase::mm[11] + MyBase::mm[15]); - - if ( !isExactlyEqual(w , 0.0) ) { - return Vec3(static_cast((p[0] * MyBase::mm[ 0] + p[1] * MyBase::mm[ 4] + - p[2] * MyBase::mm[ 8] + MyBase::mm[12]) / w), - static_cast((p[0] * MyBase::mm[ 1] + p[1] * MyBase::mm[ 5] + - p[2] * MyBase::mm[ 9] + MyBase::mm[13]) / w), - static_cast((p[0] * MyBase::mm[ 2] + p[1] * MyBase::mm[ 6] + - p[2] * MyBase::mm[10] + MyBase::mm[14]) / w)); - } - - return Vec3(0, 0, 0); - } - - /// Transform a Vec3 by pre-multiplication, doing homogenous division. - template - Vec3 pretransformH(const Vec3 &p) const - { - T0 w; - - // w = p * (*this).col(3); - w = p[0] * MyBase::mm[12] + p[1] * MyBase::mm[13] + p[2] * MyBase::mm[14] + MyBase::mm[15]; - - if ( !isExactlyEqual(w , 0.0) ) { - return Vec3(static_cast((p[0] * MyBase::mm[ 0] + p[1] * MyBase::mm[ 1] + - p[2] * MyBase::mm[ 2] + MyBase::mm[ 3]) / w), - static_cast((p[0] * MyBase::mm[ 4] + p[1] * MyBase::mm[ 5] + - p[2] * MyBase::mm[ 6] + MyBase::mm[ 7]) / w), - static_cast((p[0] * MyBase::mm[ 8] + p[1] * MyBase::mm[ 9] + - p[2] * MyBase::mm[10] + MyBase::mm[11]) / w)); - } - - return Vec3(0, 0, 0); - } - - /// Transform a Vec3 by post-multiplication, without translation. - template - Vec3 transform3x3(const Vec3 &v) const - { - return Vec3( - static_cast(v[0] * MyBase::mm[ 0] + v[1] * MyBase::mm[ 4] + v[2] * MyBase::mm[ 8]), - static_cast(v[0] * MyBase::mm[ 1] + v[1] * MyBase::mm[ 5] + v[2] * MyBase::mm[ 9]), - static_cast(v[0] * MyBase::mm[ 2] + v[1] * MyBase::mm[ 6] + v[2] * MyBase::mm[10])); - } - - -private: - bool invert(Mat4 &inverse, T tolerance) const; - - T det2(const Mat4 &a, int i0, int i1, int j0, int j1) const { - int i0row = i0 * 4; - int i1row = i1 * 4; - return a.mm[i0row+j0]*a.mm[i1row+j1] - a.mm[i0row+j1]*a.mm[i1row+j0]; - } - - T det3(const Mat4 &a, int i0, int i1, int i2, - int j0, int j1, int j2) const { - int i0row = i0 * 4; - return a.mm[i0row+j0]*det2(a, i1,i2, j1,j2) + - a.mm[i0row+j1]*det2(a, i1,i2, j2,j0) + - a.mm[i0row+j2]*det2(a, i1,i2, j0,j1); - } - - static const Mat4 sIdentity; - static const Mat4 sZero; -}; // class Mat4 - - -template -const Mat4 Mat4::sIdentity = Mat4(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - -template -const Mat4 Mat4::sZero = Mat4(0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0); - -/// @relates Mat4 -/// @brief Equality operator, does exact floating point comparisons -template -bool operator==(const Mat4 &m0, const Mat4 &m1) -{ - const T0 *t0 = m0.asPointer(); - const T1 *t1 = m1.asPointer(); - - for (int i=0; i<16; ++i) if (!isExactlyEqual(t0[i], t1[i])) return false; - return true; -} - -/// @relates Mat4 -/// @brief Inequality operator, does exact floating point comparisons -template -bool operator!=(const Mat4 &m0, const Mat4 &m1) { return !(m0 == m1); } - -/// @relates Mat4 -/// @brief Returns M, where \f$M_{i,j} = m_{i,j} * scalar\f$ for \f$i, j \in [0, 3]\f$ -template -Mat4::type> operator*(S scalar, const Mat4 &m) -{ - return m*scalar; -} - -/// @relates Mat4 -/// @brief Returns M, where \f$M_{i,j} = m_{i,j} * scalar\f$ for \f$i, j \in [0, 3]\f$ -template -Mat4::type> operator*(const Mat4 &m, S scalar) -{ - Mat4::type> result(m); - result *= scalar; - return result; -} - -/// @relates Mat4 -/// @brief Returns v, where \f$v_{i} = \sum_{n=0}^3 m_{i,n} * v_n \f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> -operator*(const Mat4 &_m, - const Vec4 &_v) -{ - MT const *m = _m.asPointer(); - return Vec4::type>( - _v[0]*m[0] + _v[1]*m[1] + _v[2]*m[2] + _v[3]*m[3], - _v[0]*m[4] + _v[1]*m[5] + _v[2]*m[6] + _v[3]*m[7], - _v[0]*m[8] + _v[1]*m[9] + _v[2]*m[10] + _v[3]*m[11], - _v[0]*m[12] + _v[1]*m[13] + _v[2]*m[14] + _v[3]*m[15]); -} - -/// @relates Mat4 -/// @brief Returns v, where \f$v_{i} = \sum_{n=0}^3 m_{n,i} * v_n \f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> -operator*(const Vec4 &_v, - const Mat4 &_m) -{ - MT const *m = _m.asPointer(); - return Vec4::type>( - _v[0]*m[0] + _v[1]*m[4] + _v[2]*m[8] + _v[3]*m[12], - _v[0]*m[1] + _v[1]*m[5] + _v[2]*m[9] + _v[3]*m[13], - _v[0]*m[2] + _v[1]*m[6] + _v[2]*m[10] + _v[3]*m[14], - _v[0]*m[3] + _v[1]*m[7] + _v[2]*m[11] + _v[3]*m[15]); -} - -/// @relates Mat4 -/// @brief Returns v, where -/// \f$v_{i} = \sum_{n=0}^3\left(m_{i,n} * v_n + m_{i,3}\right)\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> -operator*(const Mat4 &_m, - const Vec3 &_v) -{ - MT const *m = _m.asPointer(); - return Vec3::type>( - _v[0]*m[0] + _v[1]*m[1] + _v[2]*m[2] + m[3], - _v[0]*m[4] + _v[1]*m[5] + _v[2]*m[6] + m[7], - _v[0]*m[8] + _v[1]*m[9] + _v[2]*m[10] + m[11]); -} - -/// @relates Mat4 -/// @brief Returns v, where -/// \f$v_{i} = \sum_{n=0}^3\left(m_{n,i} * v_n + m_{3,i}\right)\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> -operator*(const Vec3 &_v, - const Mat4 &_m) -{ - MT const *m = _m.asPointer(); - return Vec3::type>( - _v[0]*m[0] + _v[1]*m[4] + _v[2]*m[8] + m[12], - _v[0]*m[1] + _v[1]*m[5] + _v[2]*m[9] + m[13], - _v[0]*m[2] + _v[1]*m[6] + _v[2]*m[10] + m[14]); -} - -/// @relates Mat4 -/// @brief Returns M, where \f$M_{i,j} = m0_{i,j} + m1_{i,j}\f$ for \f$i, j \in [0, 3]\f$ -template -Mat4::type> -operator+(const Mat4 &m0, const Mat4 &m1) -{ - Mat4::type> result(m0); - result += m1; - return result; -} - -/// @relates Mat4 -/// @brief Returns M, where \f$M_{i,j} = m0_{i,j} - m1_{i,j}\f$ for \f$i, j \in [0, 3]\f$ -template -Mat4::type> -operator-(const Mat4 &m0, const Mat4 &m1) -{ - Mat4::type> result(m0); - result -= m1; - return result; -} - -/// @relates Mat4 -/// @brief Returns M, where -/// \f$M_{ij} = \sum_{n=0}^3\left(m0_{nj} + m1_{in}\right)\f$ for \f$i, j \in [0, 3]\f$ -template -Mat4::type> -operator*(const Mat4 &m0, const Mat4 &m1) -{ - Mat4::type> result(m0); - result *= m1; - return result; -} - - -/// Transform a Vec3 by pre-multiplication, without translation. -/// Presumes this matrix is inverse of coordinate transform -/// Synonymous to "pretransform3x3" -template -Vec3 transformNormal(const Mat4 &m, const Vec3 &n) -{ - return Vec3( - static_cast(m[0][0]*n[0] + m[0][1]*n[1] + m[0][2]*n[2]), - static_cast(m[1][0]*n[0] + m[1][1]*n[1] + m[1][2]*n[2]), - static_cast(m[2][0]*n[0] + m[2][1]*n[1] + m[2][2]*n[2])); -} - - -/// Invert via gauss-jordan elimination. Modified from dreamworks internal mx library -template -bool Mat4::invert(Mat4 &inverse, T tolerance) const -{ - Mat4 temp(*this); - inverse.setIdentity(); - - // Forward elimination step - double det = 1.0; - for (int i = 0; i < 4; ++i) { - int row = i; - double max = fabs(temp[i][i]); - - for (int k = i+1; k < 4; ++k) { - if (fabs(temp[k][i]) > max) { - row = k; - max = fabs(temp[k][i]); - } - } - - if (isExactlyEqual(max, 0.0)) return false; - - // must move pivot to row i - if (row != i) { - det = -det; - for (int k = 0; k < 4; ++k) { - std::swap(temp[row][k], temp[i][k]); - std::swap(inverse[row][k], inverse[i][k]); - } - } - - double pivot = temp[i][i]; - det *= pivot; - - // scale row i - for (int k = 0; k < 4; ++k) { - temp[i][k] /= pivot; - inverse[i][k] /= pivot; - } - - // eliminate in rows below i - for (int j = i+1; j < 4; ++j) { - double t = temp[j][i]; - if (!isExactlyEqual(t, 0.0)) { - // subtract scaled row i from row j - for (int k = 0; k < 4; ++k) { - temp[j][k] -= temp[i][k] * t; - inverse[j][k] -= inverse[i][k] * t; - } - } - } - } - - // Backward elimination step - for (int i = 3; i > 0; --i) { - for (int j = 0; j < i; ++j) { - double t = temp[j][i]; - - if (!isExactlyEqual(t, 0.0)) { - for (int k = 0; k < 4; ++k) { - inverse[j][k] -= inverse[i][k]*t; - } - } - } - } - return det*det >= tolerance*tolerance; -} - -template -inline bool isAffine(const Mat4& m) { - return (m.col(3) == Vec4(0, 0, 0, 1)); -} - -template -inline bool hasTranslation(const Mat4& m) { - return (m.row(3) != Vec4(0, 0, 0, 1)); -} - - -typedef Mat4 Mat4s; -typedef Mat4 Mat4d; - -#if DWREAL_IS_DOUBLE == 1 -typedef Mat4d Mat4f; -#else -typedef Mat4s Mat4f; -#endif // DWREAL_IS_DOUBLE - -} // namespace math - - -template<> inline math::Mat4s zeroVal() { return math::Mat4s::identity(); } -template<> inline math::Mat4d zeroVal() { return math::Mat4d::identity(); } - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_MAT4_H_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Math.h b/openvdb_3_0_0_library/math/Math.h deleted file mode 100755 index 0897aa3..0000000 --- a/openvdb_3_0_0_library/math/Math.h +++ /dev/null @@ -1,896 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Math.h -/// @brief General-purpose arithmetic and comparison routines, most of which -/// accept arbitrary value types (or at least arbitrary numeric value types) - -#ifndef OPENVDB_MATH_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_HAS_BEEN_INCLUDED - -#include -#include // for std::max() -#include // for floor(), ceil() and sqrt() -#include // for pow(), fabs() etc -#include // for srand(), abs(int) -#include // for std::numeric_limits::max() -#include -#include -#include -#include // for boost::random::mt19937 -#include -#include -#include // for BOOST_VERSION -#include -#include - - -// Compile pragmas - -// Intel(r) compiler fires remark #1572: floating-point equality and inequality -// comparisons are unrealiable when == or != is used with floating point operands. -#if defined(__INTEL_COMPILER) - #define OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN \ - _Pragma("warning (push)") \ - _Pragma("warning (disable:1572)") - #define OPENVDB_NO_FP_EQUALITY_WARNING_END \ - _Pragma("warning (pop)") -#else - // For GCC, #pragma GCC diagnostic ignored "-Wfloat-equal" - // isn't working until gcc 4.2+, - // Trying - // #pragma GCC system_header - // creates other problems, most notably "warning: will never be executed" - // in from templates, unsure of how to work around. - // If necessary, could use integer based comparisons for equality - #define OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - #define OPENVDB_NO_FP_EQUALITY_WARNING_END -#endif - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// @brief Return the value of type T that corresponds to zero. -/// @note A zeroVal() specialization must be defined for each @c ValueType T -/// that cannot be constructed using the form @c T(0). For example, @c std::string(0) -/// treats 0 as @c NULL and throws a @c std::logic_error. -template inline T zeroVal() { return T(0); } -/// Return the @c std::string value that corresponds to zero. -template<> inline std::string zeroVal() { return ""; } -/// Return the @c bool value that corresponds to zero. -template<> inline bool zeroVal() { return false; } - -/// @todo These won't be needed if we eliminate StringGrids. -//@{ -/// @brief Needed to support the (zeroVal() + val) idiom -/// when @c ValueType is @c std::string -inline std::string operator+(const std::string& s, bool) { return s; } -inline std::string operator+(const std::string& s, int) { return s; } -inline std::string operator+(const std::string& s, float) { return s; } -inline std::string operator+(const std::string& s, double) { return s; } -//@} - - -namespace math { - -/// @brief Return the unary negation of the given value. -/// @note A negative() specialization must be defined for each ValueType T -/// for which unary negation is not defined. -template inline T negative(const T& val) { return T(-val); } -/// Return the negation of the given boolean. -template<> inline bool negative(const bool& val) { return !val; } -/// Return the "negation" of the given string. -template<> inline std::string negative(const std::string& val) { return val; } - - -//@{ -/// Tolerance for floating-point comparison -template struct Tolerance { static T value() { return zeroVal(); } }; -template<> struct Tolerance { static float value() { return 1e-8f; } }; -template<> struct Tolerance { static double value() { return 1e-15; } }; -//@} - -//@{ -/// Delta for small floating-point offsets -template struct Delta { static T value() { return zeroVal(); } }; -template<> struct Delta { static float value() { return 1e-5f; } }; -template<> struct Delta { static double value() { return 1e-9; } }; -//@} - - -// ==========> Random Values <================== - -/// @brief Simple generator of random numbers over the range [0, 1) -/// @details Thread-safe as long as each thread has its own Rand01 instance -template -class Rand01 -{ -private: - EngineType mEngine; - boost::uniform_01 mRand; - -public: - typedef FloatType ValueType; - - /// @brief Initialize the generator. - /// @param engine random number generator - Rand01(const EngineType& engine): mEngine(engine) {} - - /// @brief Initialize the generator. - /// @param seed seed value for the random number generator - Rand01(unsigned int seed): mEngine(static_cast(seed)) {} - - /// Set the seed value for the random number generator - void setSeed(unsigned int seed) - { - mEngine.seed(static_cast(seed)); - } - - /// Return a const reference to the random number generator. - const EngineType& engine() const { return mEngine; } - - /// Return a uniformly distributed random number in the range [0, 1). - FloatType operator()() { return mRand(mEngine); } -}; - -typedef Rand01 Random01; - - -/// @brief Simple random integer generator -/// @details Thread-safe as long as each thread has its own RandInt instance -template -class RandInt -{ -private: -#if BOOST_VERSION >= 104700 - typedef boost::random::uniform_int_distribution Distr; -#else - typedef boost::uniform_int Distr; -#endif - EngineType mEngine; - Distr mRand; - -public: - /// @brief Initialize the generator. - /// @param engine random number generator - /// @param imin,imax generate integers that are uniformly distributed over [imin, imax] - RandInt(const EngineType& engine, IntType imin, IntType imax): - mEngine(engine), - mRand(std::min(imin, imax), std::max(imin, imax)) - {} - - /// @brief Initialize the generator. - /// @param seed seed value for the random number generator - /// @param imin,imax generate integers that are uniformly distributed over [imin, imax] - RandInt(unsigned int seed, IntType imin, IntType imax): - mEngine(static_cast(seed)), - mRand(std::min(imin, imax), std::max(imin, imax)) - {} - - /// Change the range over which integers are distributed to [imin, imax]. - void setRange(IntType imin, IntType imax) - { - mRand = Distr(std::min(imin, imax), std::max(imin, imax)); - } - - /// Set the seed value for the random number generator - void setSeed(unsigned int seed) - { - mEngine.seed(static_cast(seed)); - } - - /// Return a const reference to the random number generator. - const EngineType& engine() const { return mEngine; } - - /// Return a randomly-generated integer in the current range. - IntType operator()() { return mRand(mEngine); } - - /// @brief Return a randomly-generated integer in the new range [imin, imax], - /// without changing the current range. - IntType operator()(IntType imin, IntType imax) - { - const IntType lo = std::min(imin, imax), hi = std::max(imin, imax); -#if BOOST_VERSION >= 104700 - return mRand(mEngine, typename Distr::param_type(lo, hi)); -#else - return Distr(lo, hi)(mEngine); -#endif - } -}; - -typedef RandInt RandomInt; - - -// ==========> Clamp <================== - -/// Return @a x clamped to [@a min, @a max] -template -inline Type -Clamp(Type x, Type min, Type max) -{ - assert(min min ? x < max ? x : max : min; -} - - -/// Return @a x clamped to [0, 1] -template -inline Type -Clamp01(Type x) { return x > Type(0) ? x < Type(1) ? x : Type(1) : Type(0); } - - -/// Return @c true if @a x is outside [0,1] -template -inline bool -ClampTest01(Type &x) -{ - if (x >= Type(0) && x <= Type(1)) return false; - x = x < Type(0) ? Type(0) : Type(1); - return true; -} - -/// @brief Return 0 if @a x < @a 0, 1 if @a x > 1 or else @f$(3-2x)x^2@f$. -template -inline Type -SmoothUnitStep(Type x) -{ - return x > 0 ? x < 1 ? (3-2*x)*x*x : Type(1) : Type(0); -} - -/// @brief Return 0 if @a x < @a min, 1 if @a x > @a max or else @f$(3-2t)t^2@f$, -/// where @f$t = (x-min)/(max-min)@f$. -template -inline Type -SmoothUnitStep(Type x, Type min, Type max) -{ - assert(min < max); - return SmoothUnitStep((x-min)/(max-min)); -} - - -// ==========> Absolute Value <================== - - -//@{ -/// Return the absolute value of the given quantity. -inline int32_t Abs(int32_t i) { return abs(i); } -inline int64_t Abs(int64_t i) -{ -#ifdef _MSC_VER - return (i < int64_t(0) ? -i : i); -#else - return labs(i); -#endif -} -inline float Abs(float x) { return fabsf(x); } -inline double Abs(double x) { return fabs(x); } -inline long double Abs(long double x) { return fabsl(x); } -inline uint32_t Abs(uint32_t i) { return i; } -inline uint64_t Abs(uint64_t i) { return i; } -// On OSX size_t and uint64_t are different types -#if defined(__APPLE__) || defined(MACOSX) -inline size_t Abs(size_t i) { return i; } -#endif -//@} - - -//////////////////////////////////////// - - -// ==========> Value Comparison <================== - - -/// Return @c true if @a x is exactly equal to zero. -template -inline bool -isZero(const Type& x) -{ - OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - return x == zeroVal(); - OPENVDB_NO_FP_EQUALITY_WARNING_END -} - - -/// @brief Return @c true if @a x is equal to zero to within -/// the default floating-point comparison tolerance. -template -inline bool -isApproxZero(const Type& x) -{ - const Type tolerance = Type(zeroVal() + Tolerance::value()); - return x < tolerance && x > -tolerance; -} - -/// Return @c true if @a x is equal to zero to within the given tolerance. -template -inline bool -isApproxZero(const Type& x, const Type& tolerance) -{ - return x < tolerance && x > -tolerance; -} - - -/// Return @c true if @a x is less than zero. -template -inline bool -isNegative(const Type& x) { return x < zeroVal(); } - -/// Return @c false, since @c bool values are never less than zero. -template<> inline bool isNegative(const bool&) { return false; } - - -/// @brief Return @c true if @a a is equal to @a b to within -/// the default floating-point comparison tolerance. -template -inline bool -isApproxEqual(const Type& a, const Type& b) -{ - const Type tolerance = Type(zeroVal() + Tolerance::value()); - return !(Abs(a - b) > tolerance); -} - - -/// Return @c true if @a a is equal to @a b to within the given tolerance. -template -inline bool -isApproxEqual(const Type& a, const Type& b, const Type& tolerance) -{ - return !(Abs(a - b) > tolerance); -} - -#define OPENVDB_EXACT_IS_APPROX_EQUAL(T) \ - template<> inline bool isApproxEqual(const T& a, const T& b) { return a == b; } \ - template<> inline bool isApproxEqual(const T& a, const T& b, const T&) { return a == b; } \ - /**/ - -OPENVDB_EXACT_IS_APPROX_EQUAL(bool) -OPENVDB_EXACT_IS_APPROX_EQUAL(std::string) - - -/// @brief Return @c true if @a a is larger than @a b to within -/// the given tolerance, i.e., if @a b - @a a < @a tolerance. -template -inline bool -isApproxLarger(const Type& a, const Type& b, const Type& tolerance) -{ - return (b - a < tolerance); -} - - -/// @brief Return @c true if @a a is exactly equal to @a b. -template -inline bool -isExactlyEqual(const T0& a, const T1& b) -{ - OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - return a == b; - OPENVDB_NO_FP_EQUALITY_WARNING_END -} - - -template -inline bool -isRelOrApproxEqual(const Type& a, const Type& b, const Type& absTol, const Type& relTol) -{ - // First check to see if we are inside the absolute tolerance - // Necessary for numbers close to 0 - if (!(Abs(a - b) > absTol)) return true; - - // Next check to see if we are inside the relative tolerance - // to handle large numbers that aren't within the abs tolerance - // but could be the closest floating point representation - double relError; - if (Abs(b) > Abs(a)) { - relError = Abs((a - b) / b); - } else { - relError = Abs((a - b) / a); - } - return (relError <= relTol); -} - -template<> -inline bool -isRelOrApproxEqual(const bool& a, const bool& b, const bool&, const bool&) -{ - return (a == b); -} - - -// Avoid strict aliasing issues by using type punning -// http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html -// Using "casting through a union(2)" -inline int32_t -floatToInt32(const float aFloatValue) -{ - union FloatOrInt32 { float floatValue; int32_t int32Value; }; - const FloatOrInt32* foi = reinterpret_cast(&aFloatValue); - return foi->int32Value; -} - - -inline int64_t -doubleToInt64(const double aDoubleValue) -{ - union DoubleOrInt64 { double doubleValue; int64_t int64Value; }; - const DoubleOrInt64* dol = reinterpret_cast(&aDoubleValue); - return dol->int64Value; -} - - -// aUnitsInLastPlace is the allowed difference between the least significant digits -// of the numbers' floating point representation -// Please read refernce paper before trying to use isUlpsEqual -// http://www.cygnus-software.com/papers/comparingFloats/comparingFloats.htm -inline bool -isUlpsEqual(const double aLeft, const double aRight, const int64_t aUnitsInLastPlace) -{ - int64_t longLeft = doubleToInt64(aLeft); - // Because of 2's complement, must restore lexicographical order - if (longLeft < 0) { - longLeft = INT64_C(0x8000000000000000) - longLeft; - } - - int64_t longRight = doubleToInt64(aRight); - // Because of 2's complement, must restore lexicographical order - if (longRight < 0) { - longRight = INT64_C(0x8000000000000000) - longRight; - } - - int64_t difference = labs(longLeft - longRight); - return (difference <= aUnitsInLastPlace); -} - -inline bool -isUlpsEqual(const float aLeft, const float aRight, const int32_t aUnitsInLastPlace) -{ - int32_t intLeft = floatToInt32(aLeft); - // Because of 2's complement, must restore lexicographical order - if (intLeft < 0) { - intLeft = 0x80000000 - intLeft; - } - - int32_t intRight = floatToInt32(aRight); - // Because of 2's complement, must restore lexicographical order - if (intRight < 0) { - intRight = 0x80000000 - intRight; - } - - int32_t difference = abs(intLeft - intRight); - return (difference <= aUnitsInLastPlace); -} - - -//////////////////////////////////////// - - -// ==========> Pow <================== - -/// Return @f$ x^2 @f$. -template -inline Type Pow2(Type x) { return x*x; } - -/// Return @f$ x^3 @f$. -template -inline Type Pow3(Type x) { return x*x*x; } - -/// Return @f$ x^4 @f$. -template -inline Type Pow4(Type x) { return Pow2(Pow2(x)); } - -/// Return @f$ x^n @f$. -template -Type -Pow(Type x, int n) -{ - Type ans = 1; - if (n < 0) { - n = -n; - x = Type(1)/x; - } - while (n--) ans *= x; - return ans; -} - -//@{ -/// Return @f$ b^e @f$. -inline float -Pow(float b, float e) -{ - assert( b >= 0.0f && "Pow(float,float): base is negative" ); - return powf(b,e); -} - -inline double -Pow(double b, double e) -{ - assert( b >= 0.0 && "Pow(double,double): base is negative" ); - return pow(b,e); -} -//@} - - -// ==========> Max <================== - -/// Return the maximum of two values -template -inline const Type& -Max(const Type& a, const Type& b) -{ - return std::max(a,b) ; -} - -/// Return the maximum of three values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c) -{ - return std::max( std::max(a,b), c ) ; -} - -/// Return the maximum of four values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c, const Type& d) -{ - return std::max(std::max(a,b), std::max(c,d)); -} - -/// Return the maximum of five values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c, const Type& d, const Type& e) -{ - return std::max(std::max(a,b), Max(c,d,e)); -} - -/// Return the maximum of six values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c, const Type& d, const Type& e, const Type& f) -{ - return std::max(Max(a,b,c), Max(d,e,f)); -} - -/// Return the maximum of seven values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c, const Type& d, - const Type& e, const Type& f, const Type& g) -{ - return std::max(Max(a,b,c,d), Max(e,f,g)); -} - -/// Return the maximum of eight values -template -inline const Type& -Max(const Type& a, const Type& b, const Type& c, const Type& d, - const Type& e, const Type& f, const Type& g, const Type& h) -{ - return std::max(Max(a,b,c,d), Max(e,f,g,h)); -} - - -// ==========> Min <================== - -/// Return the minimum of two values -template -inline const Type& -Min(const Type& a, const Type& b) { return std::min(a, b); } - -/// Return the minimum of three values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c) { return std::min(std::min(a, b), c); } - -/// Return the minimum of four values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c, const Type& d) -{ - return std::min(std::min(a, b), std::min(c, d)); -} - -/// Return the minimum of five values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c, const Type& d, const Type& e) -{ - return std::min(std::min(a,b), Min(c,d,e)); -} - -/// Return the minimum of six values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c, const Type& d, const Type& e, const Type& f) -{ - return std::min(Min(a,b,c), Min(d,e,f)); -} - -/// Return the minimum of seven values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c, const Type& d, - const Type& e, const Type& f, const Type& g) -{ - return std::min(Min(a,b,c,d), Min(e,f,g)); -} - -/// Return the minimum of eight values -template -inline const Type& -Min(const Type& a, const Type& b, const Type& c, const Type& d, - const Type& e, const Type& f, const Type& g, const Type& h) -{ - return std::min(Min(a,b,c,d), Min(e,f,g,h)); -} - - -// ============> Exp <================== - -/// Return @f$ e^x @f$. -template -inline Type Exp(const Type& x) { return std::exp(x); } - - -//////////////////////////////////////// - - -/// Return the sign of the given value as an integer (either -1, 0 or 1). -template -inline int Sign(const Type &x) { return (zeroVal() < x) - (x < zeroVal()); } - - -/// @brief Return @c true if @a a and @a b have different signs. -/// @note Zero is considered a positive number. -template -inline bool -SignChange(const Type& a, const Type& b) -{ - return ( (a()) ^ (b()) ); -} - - -/// @brief Return @c true if the interval [@a a, @a b] includes zero, -/// i.e., if either @a a or @a b is zero or if they have different signs. -template -inline bool -ZeroCrossing(const Type& a, const Type& b) -{ - return a * b <= zeroVal(); -} - - -//@{ -/// Return the square root of a floating-point value. -inline float Sqrt(float x) { return sqrtf(x); } -inline double Sqrt(double x) { return sqrt(x); } -inline long double Sqrt(long double x) { return sqrtl(x); } -//@} - - -//@{ -/// Return the cube root of a floating-point value. -inline float Cbrt(float x) { return boost::math::cbrt(x); } -inline double Cbrt(double x) { return boost::math::cbrt(x); } -inline long double Cbrt(long double x) { return boost::math::cbrt(x); } -//@} - - -//@{ -/// Return the remainder of @a x / @a y. -inline int Mod(int x, int y) { return (x % y); } -inline float Mod(float x, float y) { return fmodf(x,y); } -inline double Mod(double x, double y) { return fmod(x,y); } -inline long double Mod(long double x, long double y) { return fmodl(x,y); } -template inline Type Remainder(Type x, Type y) { return Mod(x,y); } -//@} - - -//@{ -/// Return @a x rounded up to the nearest integer. -inline float RoundUp(float x) { return ceilf(x); } -inline double RoundUp(double x) { return ceil(x); } -inline long double RoundUp(long double x) { return ceill(x); } -//@} -/// Return @a x rounded up to the nearest multiple of @a base. -template -inline Type -RoundUp(Type x, Type base) -{ - Type remainder = Remainder(x, base); - return remainder ? x-remainder+base : x; -} - - -//@{ -/// Return @a x rounded down to the nearest integer. -inline float RoundDown(float x) { return floorf(x); } -inline double RoundDown(double x) { return floor(x); } -inline long double RoundDown(long double x) { return floorl(x); } -//@} -/// Return @a x rounded down to the nearest multiple of @a base. -template -inline Type -RoundDown(Type x, Type base) -{ - Type remainder = Remainder(x, base); - return remainder ? x-remainder : x; -} - - -//@{ -/// Return @a x rounded to the nearest integer. -inline float Round(float x) { return RoundDown(x + 0.5f); } -inline double Round(double x) { return RoundDown(x + 0.5); } -inline long double Round(long double x) { return RoundDown(x + 0.5l); } -//@} - - -/// Return the euclidean remainder of @a x. -/// Note unlike % operator this will always return a positive result -template -inline Type -EuclideanRemainder(Type x) { return x - RoundDown(x); } - - -/// Return the integer part of @a x. -template -inline Type -IntegerPart(Type x) -{ - return (x > 0 ? RoundDown(x) : RoundUp(x)); -} - -/// Return the fractional part of @a x. -template -inline Type -FractionalPart(Type x) { return Mod(x,Type(1)); } - - -//@{ -/// Return the floor of @a x. -inline int Floor(float x) { return int(RoundDown(x)); } -inline int Floor(double x) { return int(RoundDown(x)); } -inline int Floor(long double x) { return int(RoundDown(x)); } -//@} - - -//@{ -/// Return the ceiling of @a x. -inline int Ceil(float x) { return int(RoundUp(x)); } -inline int Ceil(double x) { return int(RoundUp(x)); } -inline int Ceil(long double x) { return int(RoundUp(x)); } -//@} - - -/// Return @a x if it is greater in magnitude than @a delta. Otherwise, return zero. -template -inline Type Chop(Type x, Type delta) { return (Abs(x) < delta ? zeroVal() : x); } - - -/// Return @a x truncated to the given number of decimal digits. -template -inline Type -Truncate(Type x, unsigned int digits) -{ - Type tenth = Pow(10,digits); - return RoundDown(x*tenth+0.5)/tenth; -} - - -//////////////////////////////////////// - - -/// Return the inverse of @a x. -template -inline Type -Inv(Type x) -{ - assert(x); - return Type(1)/x; -} - - -enum Axis { - X_AXIS = 0, - Y_AXIS = 1, - Z_AXIS = 2 -}; - -// enum values are consistent with their historical mx analogs. -enum RotationOrder { - XYZ_ROTATION = 0, - XZY_ROTATION, - YXZ_ROTATION, - YZX_ROTATION, - ZXY_ROTATION, - ZYX_ROTATION, - XZX_ROTATION, - ZXZ_ROTATION -}; - - -template -struct promote { - typedef typename boost::numeric::conversion_traits::supertype type; -}; - - -/// @brief Return the index [0,1,2] of the smallest value in a 3D vector. -/// @note This methods assumes operator[] exists and avoids branching. -/// @details If two components of the input vector are equal and smaller then the -/// third component, the largest index of the two is always returned. -/// If all three vector components are equal the largest index, i.e. 2, is -/// returned. In other words the return value corresponds to the largest index -/// of the of the smallest vector components. -template -size_t -MinIndex(const Vec3T& v) -{ -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const size_t hashTable[8] = { 2, 1, 9, 1, 2, 9, 0, 0 };//9 is a dummy value - const size_t hashKey = - ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]);// ?*4+?*2+?*1 - return hashTable[hashKey]; -} - - -/// @brief Return the index [0,1,2] of the largest value in a 3D vector. -/// @note This methods assumes operator[] exists and avoids branching. -/// @details If two components of the input vector are equal and larger then the -/// third component, the largest index of the two is always returned. -/// If all three vector components are equal the largest index, i.e. 2, is -/// returned. In other words the return value corresponds to the largest index -/// of the of the largest vector components. -template -size_t -MaxIndex(const Vec3T& v) -{ -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const size_t hashTable[8] = { 2, 1, 9, 1, 2, 9, 0, 0 };//9 is a dummy value - const size_t hashKey = - ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]);// ?*4+?*2+?*1 - return hashTable[hashKey]; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_MATH_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Operators.h b/openvdb_3_0_0_library/math/Operators.h deleted file mode 100755 index 01343ff..0000000 --- a/openvdb_3_0_0_library/math/Operators.h +++ /dev/null @@ -1,2123 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Operators.h - -#ifndef OPENVDB_MATH_OPERATORS_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_OPERATORS_HAS_BEEN_INCLUDED - -#include "FiniteDifference.h" -#include "Stencils.h" -#include "Maps.h" -#include "Transform.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -// Simple tools to help determine when type conversions are needed -template struct is_vec3d { static const bool value = false; }; -template<> struct is_vec3d { static const bool value = true; }; - -template struct is_double { static const bool value = false; }; -template<> struct is_double { static const bool value = true; }; - - -/// @brief Adapter to associate a map with a world-space operator, -/// giving it the same call signature as an index-space operator -/// @todo For now, the operator's result type must be specified explicitly, -/// but eventually it should be possible, via traits, to derive the result type -/// from the operator type. -template -struct MapAdapter { - MapAdapter(const MapType& m): map(m) {} - - template - inline ResultType - result(const AccessorType& grid, const Coord& ijk) { return OpType::result(map, grid, ijk); } - - template - inline ResultType - result(const StencilType& stencil) { return OpType::result(map, stencil); } - - const MapType map; -}; - - -/// Adapter for vector-valued index-space operators to return the vector magnitude -template -struct ISOpMagnitude { - template - static inline double result(const AccessorType& grid, const Coord& ijk) { - return double(OpType::result(grid, ijk).length()); - } - - template - static inline double result(const StencilType& stencil) { - return double(OpType::result(stencil).length()); - } -}; - -/// Adapter for vector-valued world-space operators to return the vector magnitude -template -struct OpMagnitude { - template - static inline double result(const MapT& map, const AccessorType& grid, const Coord& ijk) { - return double(OpType::result(map, grid, ijk).length()); - } - - template - static inline double result(const MapT& map, const StencilType& stencil) { - return double(OpType::result(map, stencil).length()); - } -}; - - -namespace internal { - -// This additional layer is necessary for Visual C++ to compile. -template -struct ReturnValue { - typedef typename T::ValueType ValueType; - typedef math::Vec3 Vec3Type; -}; - -} // namespace internal - -// ---- Operators defined in index space - - -//@{ -/// @brief Gradient operators defined in index space of various orders -template -struct ISGradient -{ - // random access version - template static Vec3 - result(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typedef Vec3 Vec3Type; - return Vec3Type( D1::inX(grid, ijk), - D1::inY(grid, ijk), - D1::inZ(grid, ijk) ); - } - - // stencil access version - template static Vec3 - result(const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - typedef Vec3 Vec3Type; - return Vec3Type( D1::inX(stencil), - D1::inY(stencil), - D1::inZ(stencil) ); - } -}; -//@} - -/// struct that relates the BiasedGradientScheme to the -/// forward and backward difference methods used, as well as to -/// the correct stencil type for index space use -template -struct BIAS_SCHEME { - static const DScheme FD = FD_1ST; - static const DScheme BD = BD_1ST; - - template - struct ISStencil { - typedef SevenPointStencil StencilType; - }; -}; - -template<> struct BIAS_SCHEME -{ - static const DScheme FD = FD_1ST; - static const DScheme BD = BD_1ST; - - template - struct ISStencil { - typedef SevenPointStencil StencilType; - }; -}; - -template<> struct BIAS_SCHEME -{ - static const DScheme FD = FD_2ND; - static const DScheme BD = BD_2ND; - - template - struct ISStencil { - typedef ThirteenPointStencil StencilType; - }; -}; -template<> struct BIAS_SCHEME -{ - static const DScheme FD = FD_3RD; - static const DScheme BD = BD_3RD; - - template - struct ISStencil { - typedef NineteenPointStencil StencilType; - }; -}; -template<> struct BIAS_SCHEME -{ - static const DScheme FD = FD_WENO5; - static const DScheme BD = BD_WENO5; - - template - struct ISStencil { - typedef NineteenPointStencil StencilType; - }; -}; -template<> struct BIAS_SCHEME -{ - static const DScheme FD = FD_HJWENO5; - static const DScheme BD = BD_HJWENO5; - - template - struct ISStencil { - typedef NineteenPointStencil StencilType; - }; -}; - - -//@{ -/// @brief Biased Gradient Operators, using upwinding defined by the @c Vec3Bias input - -template -struct ISGradientBiased -{ - static const DScheme FD = BIAS_SCHEME::FD; - static const DScheme BD = BIAS_SCHEME::BD; - - // random access version - template static Vec3 - result(const Accessor& grid, const Coord& ijk, const Vec3Bias& V) - { - typedef typename Accessor::ValueType ValueType; - typedef Vec3 Vec3Type; - - return Vec3Type(V[0]<0 ? D1::inX(grid,ijk) : D1::inX(grid,ijk), - V[1]<0 ? D1::inY(grid,ijk) : D1::inY(grid,ijk), - V[2]<0 ? D1::inZ(grid,ijk) : D1::inZ(grid,ijk) ); - } - - // stencil access version - template static Vec3 - result(const StencilT& stencil, const Vec3Bias& V) - { - typedef typename StencilT::ValueType ValueType; - typedef Vec3 Vec3Type; - - return Vec3Type(V[0]<0 ? D1::inX(stencil) : D1::inX(stencil), - V[1]<0 ? D1::inY(stencil) : D1::inY(stencil), - V[2]<0 ? D1::inZ(stencil) : D1::inZ(stencil) ); - } -}; - - -template -struct ISGradientNormSqrd -{ - static const DScheme FD = BIAS_SCHEME::FD; - static const DScheme BD = BIAS_SCHEME::BD; - - - // random access version - template - static typename Accessor::ValueType - result(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3Type up = ISGradient::result(grid, ijk); - Vec3Type down = ISGradient::result(grid, ijk); - return math::GudonovsNormSqrd(grid.getValue(ijk)>0, down, up); - } - - // stencil access version - template - static typename StencilT::ValueType - result(const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3Type up = ISGradient::result(stencil); - Vec3Type down = ISGradient::result(stencil); - return math::GudonovsNormSqrd(stencil.template getValue<0, 0, 0>()>0, down, up); - } -}; - -#ifdef DWA_OPENVDB // for SIMD - note will do the computations in float -template<> -struct ISGradientNormSqrd -{ - // random access version - template - static typename Accessor::ValueType - result(const Accessor& grid, const Coord& ijk) - { - struct GetValue - { - const Accessor& acc; - GetValue(const Accessor& acc_): acc(acc_) {} - // Return the grid value at ijk converted to simd::Float4::value_type (= float). - inline simd::Float4::value_type operator()(const Coord& ijk) { - return static_cast(acc.getValue(ijk)); - } - } - valueAt(grid); - - // SSE optimized - const simd::Float4 - v1(valueAt(ijk.offsetBy(-2, 0, 0)) - valueAt(ijk.offsetBy(-3, 0, 0)), - valueAt(ijk.offsetBy( 0,-2, 0)) - valueAt(ijk.offsetBy( 0,-3, 0)), - valueAt(ijk.offsetBy( 0, 0,-2)) - valueAt(ijk.offsetBy( 0, 0,-3)), 0), - v2(valueAt(ijk.offsetBy(-1, 0, 0)) - valueAt(ijk.offsetBy(-2, 0, 0)), - valueAt(ijk.offsetBy( 0,-1, 0)) - valueAt(ijk.offsetBy( 0,-2, 0)), - valueAt(ijk.offsetBy( 0, 0,-1)) - valueAt(ijk.offsetBy( 0, 0,-2)), 0), - v3(valueAt(ijk ) - valueAt(ijk.offsetBy(-1, 0, 0)), - valueAt(ijk ) - valueAt(ijk.offsetBy( 0,-1, 0)), - valueAt(ijk ) - valueAt(ijk.offsetBy( 0, 0,-1)), 0), - v4(valueAt(ijk.offsetBy( 1, 0, 0)) - valueAt(ijk ), - valueAt(ijk.offsetBy( 0, 1, 0)) - valueAt(ijk ), - valueAt(ijk.offsetBy( 0, 0, 1)) - valueAt(ijk ), 0), - v5(valueAt(ijk.offsetBy( 2, 0, 0)) - valueAt(ijk.offsetBy( 1, 0, 0)), - valueAt(ijk.offsetBy( 0, 2, 0)) - valueAt(ijk.offsetBy( 0, 1, 0)), - valueAt(ijk.offsetBy( 0, 0, 2)) - valueAt(ijk.offsetBy( 0, 0, 1)), 0), - v6(valueAt(ijk.offsetBy( 3, 0, 0)) - valueAt(ijk.offsetBy( 2, 0, 0)), - valueAt(ijk.offsetBy( 0, 3, 0)) - valueAt(ijk.offsetBy( 0, 2, 0)), - valueAt(ijk.offsetBy( 0, 0, 3)) - valueAt(ijk.offsetBy( 0, 0, 2)), 0), - down = math::WENO5(v1, v2, v3, v4, v5), - up = math::WENO5(v6, v5, v4, v3, v2); - - return math::GudonovsNormSqrd(grid.getValue(ijk)>0, down, up); - } - - // stencil access version - template - static typename StencilT::ValueType - result(const StencilT& s) - { - typedef simd::Float4::value_type F4Val; - - // SSE optimized - const simd::Float4 - v1(F4Val(s.template getValue<-2, 0, 0>()) - F4Val(s.template getValue<-3, 0, 0>()), - F4Val(s.template getValue< 0,-2, 0>()) - F4Val(s.template getValue< 0,-3, 0>()), - F4Val(s.template getValue< 0, 0,-2>()) - F4Val(s.template getValue< 0, 0,-3>()), 0), - v2(F4Val(s.template getValue<-1, 0, 0>()) - F4Val(s.template getValue<-2, 0, 0>()), - F4Val(s.template getValue< 0,-1, 0>()) - F4Val(s.template getValue< 0,-2, 0>()), - F4Val(s.template getValue< 0, 0,-1>()) - F4Val(s.template getValue< 0, 0,-2>()), 0), - v3(F4Val(s.template getValue< 0, 0, 0>()) - F4Val(s.template getValue<-1, 0, 0>()), - F4Val(s.template getValue< 0, 0, 0>()) - F4Val(s.template getValue< 0,-1, 0>()), - F4Val(s.template getValue< 0, 0, 0>()) - F4Val(s.template getValue< 0, 0,-1>()), 0), - v4(F4Val(s.template getValue< 1, 0, 0>()) - F4Val(s.template getValue< 0, 0, 0>()), - F4Val(s.template getValue< 0, 1, 0>()) - F4Val(s.template getValue< 0, 0, 0>()), - F4Val(s.template getValue< 0, 0, 1>()) - F4Val(s.template getValue< 0, 0, 0>()), 0), - v5(F4Val(s.template getValue< 2, 0, 0>()) - F4Val(s.template getValue< 1, 0, 0>()), - F4Val(s.template getValue< 0, 2, 0>()) - F4Val(s.template getValue< 0, 1, 0>()), - F4Val(s.template getValue< 0, 0, 2>()) - F4Val(s.template getValue< 0, 0, 1>()), 0), - v6(F4Val(s.template getValue< 3, 0, 0>()) - F4Val(s.template getValue< 2, 0, 0>()), - F4Val(s.template getValue< 0, 3, 0>()) - F4Val(s.template getValue< 0, 2, 0>()), - F4Val(s.template getValue< 0, 0, 3>()) - F4Val(s.template getValue< 0, 0, 2>()), 0), - down = math::WENO5(v1, v2, v3, v4, v5), - up = math::WENO5(v6, v5, v4, v3, v2); - - return math::GudonovsNormSqrd(s.template getValue<0, 0, 0>()>0, down, up); - } -}; -#endif //DWA_OPENVDB // for SIMD - note will do the computations in float -//@} - - -//@{ -/// @brief Laplacian defined in index space, using various center-difference stencils -template -struct ISLaplacian -{ - // random access version - template - static typename Accessor::ValueType result(const Accessor& grid, const Coord& ijk); - - // stencil access version - template - static typename StencilT::ValueType result(const StencilT& stencil); -}; - - -template<> -struct ISLaplacian -{ - // random access version - template - static typename Accessor::ValueType result(const Accessor& grid, const Coord& ijk) - { - return grid.getValue(ijk.offsetBy(1,0,0)) + grid.getValue(ijk.offsetBy(-1, 0, 0)) + - grid.getValue(ijk.offsetBy(0,1,0)) + grid.getValue(ijk.offsetBy(0, -1, 0)) + - grid.getValue(ijk.offsetBy(0,0,1)) + grid.getValue(ijk.offsetBy(0, 0,-1)) - - 6*grid.getValue(ijk); - } - - // stencil access version - template - static typename StencilT::ValueType result(const StencilT& stencil) - { - return stencil.template getValue< 1, 0, 0>() + stencil.template getValue<-1, 0, 0>() + - stencil.template getValue< 0, 1, 0>() + stencil.template getValue< 0,-1, 0>() + - stencil.template getValue< 0, 0, 1>() + stencil.template getValue< 0, 0,-1>() - - 6*stencil.template getValue< 0, 0, 0>(); - } -}; - -template<> -struct ISLaplacian -{ - // random access version - template - static typename Accessor::ValueType result(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueT; - return static_cast( - (-1./12.)*( - grid.getValue(ijk.offsetBy(2,0,0)) + grid.getValue(ijk.offsetBy(-2, 0, 0)) + - grid.getValue(ijk.offsetBy(0,2,0)) + grid.getValue(ijk.offsetBy( 0,-2, 0)) + - grid.getValue(ijk.offsetBy(0,0,2)) + grid.getValue(ijk.offsetBy( 0, 0,-2)) ) - + (4./3.)*( - grid.getValue(ijk.offsetBy(1,0,0)) + grid.getValue(ijk.offsetBy(-1, 0, 0)) + - grid.getValue(ijk.offsetBy(0,1,0)) + grid.getValue(ijk.offsetBy( 0,-1, 0)) + - grid.getValue(ijk.offsetBy(0,0,1)) + grid.getValue(ijk.offsetBy( 0, 0,-1)) ) - - 7.5*grid.getValue(ijk)); - } - - // stencil access version - template - static typename StencilT::ValueType result(const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueT; - return static_cast( - (-1./12.)*( - stencil.template getValue< 2, 0, 0>() + stencil.template getValue<-2, 0, 0>() + - stencil.template getValue< 0, 2, 0>() + stencil.template getValue< 0,-2, 0>() + - stencil.template getValue< 0, 0, 2>() + stencil.template getValue< 0, 0,-2>() ) - + (4./3.)*( - stencil.template getValue< 1, 0, 0>() + stencil.template getValue<-1, 0, 0>() + - stencil.template getValue< 0, 1, 0>() + stencil.template getValue< 0,-1, 0>() + - stencil.template getValue< 0, 0, 1>() + stencil.template getValue< 0, 0,-1>() ) - - 7.5*stencil.template getValue< 0, 0, 0>()); - } -}; - -template<> -struct ISLaplacian -{ - // random access version - template - static typename Accessor::ValueType result(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueT; - return static_cast( - (1./90.)*( - grid.getValue(ijk.offsetBy(3,0,0)) + grid.getValue(ijk.offsetBy(-3, 0, 0)) + - grid.getValue(ijk.offsetBy(0,3,0)) + grid.getValue(ijk.offsetBy( 0,-3, 0)) + - grid.getValue(ijk.offsetBy(0,0,3)) + grid.getValue(ijk.offsetBy( 0, 0,-3)) ) - - (3./20.)*( - grid.getValue(ijk.offsetBy(2,0,0)) + grid.getValue(ijk.offsetBy(-2, 0, 0)) + - grid.getValue(ijk.offsetBy(0,2,0)) + grid.getValue(ijk.offsetBy( 0,-2, 0)) + - grid.getValue(ijk.offsetBy(0,0,2)) + grid.getValue(ijk.offsetBy( 0, 0,-2)) ) - + 1.5 *( - grid.getValue(ijk.offsetBy(1,0,0)) + grid.getValue(ijk.offsetBy(-1, 0, 0)) + - grid.getValue(ijk.offsetBy(0,1,0)) + grid.getValue(ijk.offsetBy( 0,-1, 0)) + - grid.getValue(ijk.offsetBy(0,0,1)) + grid.getValue(ijk.offsetBy( 0, 0,-1)) ) - - (3*49/18.)*grid.getValue(ijk)); - } - - // stencil access version - template - static typename StencilT::ValueType result(const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueT; - return static_cast( - (1./90.)*( - stencil.template getValue< 3, 0, 0>() + stencil.template getValue<-3, 0, 0>() + - stencil.template getValue< 0, 3, 0>() + stencil.template getValue< 0,-3, 0>() + - stencil.template getValue< 0, 0, 3>() + stencil.template getValue< 0, 0,-3>() ) - - (3./20.)*( - stencil.template getValue< 2, 0, 0>() + stencil.template getValue<-2, 0, 0>() + - stencil.template getValue< 0, 2, 0>() + stencil.template getValue< 0,-2, 0>() + - stencil.template getValue< 0, 0, 2>() + stencil.template getValue< 0, 0,-2>() ) - + 1.5 *( - stencil.template getValue< 1, 0, 0>() + stencil.template getValue<-1, 0, 0>() + - stencil.template getValue< 0, 1, 0>() + stencil.template getValue< 0,-1, 0>() + - stencil.template getValue< 0, 0, 1>() + stencil.template getValue< 0, 0,-1>() ) - - (3*49/18.)*stencil.template getValue< 0, 0, 0>()); - } -}; -//@} - - -//@{ -/// Divergence operator defined in index space using various first derivative schemes -template -struct ISDivergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const Accessor& grid, const Coord& ijk) - { - return D1Vec::inX(grid, ijk, 0) + - D1Vec::inY(grid, ijk, 1) + - D1Vec::inZ(grid, ijk, 2); - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const StencilT& stencil) - { - return D1Vec::inX(stencil, 0) + - D1Vec::inY(stencil, 1) + - D1Vec::inZ(stencil, 2); - } -}; -//@} - - -//@{ -/// Curl operator defined in index space using various first derivative schemes -template -struct ISCurl -{ - // random access version - template - static typename Accessor::ValueType result(const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - return Vec3Type( D1Vec::inY(grid, ijk, 2) - //dw/dy - dv/dz - D1Vec::inZ(grid, ijk, 1), - D1Vec::inZ(grid, ijk, 0) - //du/dz - dw/dx - D1Vec::inX(grid, ijk, 2), - D1Vec::inX(grid, ijk, 1) - //dv/dx - du/dy - D1Vec::inY(grid, ijk, 0) ); - } - - // stencil access version - template - static typename StencilT::ValueType result(const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - return Vec3Type( D1Vec::inY(stencil, 2) - //dw/dy - dv/dz - D1Vec::inZ(stencil, 1), - D1Vec::inZ(stencil, 0) - //du/dz - dw/dx - D1Vec::inX(stencil, 2), - D1Vec::inX(stencil, 1) - //dv/dx - du/dy - D1Vec::inY(stencil, 0) ); - } -}; -//@} - - -//@{ -/// Compute the mean curvature in index space -template -struct ISMeanCurvature -{ - /// @brief random access version - /// @return true if the gradient is none-zero, in which case the - /// mean curvature is computed as two parts: @c alpha is the numerator in - /// @f$\nabla \cdot (\nabla \phi / |\nabla \phi|)@f$, and @c beta is @f$|\nabla \phi|@f$. - template - static bool result(const Accessor& grid, const Coord& ijk, - typename Accessor::ValueType& alpha, - typename Accessor::ValueType& beta) - { - typedef typename Accessor::ValueType ValueType; - - const ValueType Dx = D1::inX(grid, ijk); - const ValueType Dy = D1::inY(grid, ijk); - const ValueType Dz = D1::inZ(grid, ijk); - - const ValueType Dx2 = Dx*Dx; - const ValueType Dy2 = Dy*Dy; - const ValueType Dz2 = Dz*Dz; - const ValueType normGrad = Dx2 + Dy2 + Dz2; - if (normGrad <= math::Tolerance::value()) { - alpha = beta = 0; - return false; - } - - const ValueType Dxx = D2::inX(grid, ijk); - const ValueType Dyy = D2::inY(grid, ijk); - const ValueType Dzz = D2::inZ(grid, ijk); - - const ValueType Dxy = D2::inXandY(grid, ijk); - const ValueType Dyz = D2::inYandZ(grid, ijk); - const ValueType Dxz = D2::inXandZ(grid, ijk); - - // for return - alpha = (Dx2*(Dyy+Dzz)+Dy2*(Dxx+Dzz)+Dz2*(Dxx+Dyy)-2*(Dx*(Dy*Dxy+Dz*Dxz)+Dy*Dz*Dyz)); - beta = ValueType(std::sqrt(double(normGrad))); // * 1/dx - return true; - } - - /// @brief stencil access version - /// @return true if the gradient is none-zero, in which case the - /// mean curvature is computed as two parts: @c alpha is the numerator in - /// @f$\nabla \cdot (\nabla \phi / |\nabla \phi|)@f$, and @c beta is @f$|\nabla \phi|@f$. - template - static bool result(const StencilT& stencil, - typename StencilT::ValueType& alpha, - typename StencilT::ValueType& beta) - { - typedef typename StencilT::ValueType ValueType; - const ValueType Dx = D1::inX(stencil); - const ValueType Dy = D1::inY(stencil); - const ValueType Dz = D1::inZ(stencil); - - const ValueType Dx2 = Dx*Dx; - const ValueType Dy2 = Dy*Dy; - const ValueType Dz2 = Dz*Dz; - const ValueType normGrad = Dx2 + Dy2 + Dz2; - if (normGrad <= math::Tolerance::value()) { - alpha = beta = 0; - return false; - } - - const ValueType Dxx = D2::inX(stencil); - const ValueType Dyy = D2::inY(stencil); - const ValueType Dzz = D2::inZ(stencil); - - const ValueType Dxy = D2::inXandY(stencil); - const ValueType Dyz = D2::inYandZ(stencil); - const ValueType Dxz = D2::inXandZ(stencil); - - // for return - alpha = (Dx2*(Dyy+Dzz)+Dy2*(Dxx+Dzz)+Dz2*(Dxx+Dyy)-2*(Dx*(Dy*Dxy+Dz*Dxz)+Dy*Dz*Dyz)); - beta = ValueType(std::sqrt(double(normGrad))); // * 1/dx - return true; - } -}; - -//////////////////////////////////////////////////////// - -// --- Operators defined in the Range of a given map - -//@{ -/// @brief Center difference gradient operators, defined with respect to -/// the range-space of the @c map -/// @note This will need to be divided by two in the case of CD_2NDT -template -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3d iGradient( ISGradient::result(grid, ijk) ); - return Vec3Type(map.applyIJT(iGradient, ijk.asVec3d())); - } - - // stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const MapType& map, const StencilT& stencil) - { - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3d iGradient( ISGradient::result(stencil) ); - return Vec3Type(map.applyIJT(iGradient, stencil.getCenterCoord().asVec3d())); - } -}; - -// Partial template specialization of Gradient -// translation, any order -template -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const TranslationMap&, const Accessor& grid, const Coord& ijk) - { - return ISGradient::result(grid, ijk); - } - - // stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const TranslationMap&, const StencilT& stencil) - { - return ISGradient::result(stencil); - } -}; - -/// Full template specialization of Gradient -/// uniform scale, 2nd order -template<> -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(grid, ijk) ); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return iGradient * inv2dx; - } - - // stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(stencil) ); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return iGradient * inv2dx; - } -}; - -/// Full template specialization of Gradient -/// uniform scale translate, 2nd order -template<> -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(grid, ijk) ); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return iGradient * inv2dx; - } - - // stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(stencil) ); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return iGradient * inv2dx; - } -}; - -/// Full template specialization of Gradient -/// scale, 2nd order -template<> -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const ScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(grid, ijk) ); - return Vec3Type(ValueType(iGradient[0] * map.getInvTwiceScale()[0]), - ValueType(iGradient[1] * map.getInvTwiceScale()[1]), - ValueType(iGradient[2] * map.getInvTwiceScale()[2]) ); - } - - // stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const ScaleMap& map, const StencilT& stencil) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(stencil) ); - return Vec3Type(ValueType(iGradient[0] * map.getInvTwiceScale()[0]), - ValueType(iGradient[1] * map.getInvTwiceScale()[1]), - ValueType(iGradient[2] * map.getInvTwiceScale()[2]) ); - } -}; - -/// Full template specialization of Gradient -/// scale translate, 2nd order -template<> -struct Gradient -{ - // random access version - template - static typename internal::ReturnValue::Vec3Type - result(const ScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(grid, ijk) ); - return Vec3Type(ValueType(iGradient[0] * map.getInvTwiceScale()[0]), - ValueType(iGradient[1] * map.getInvTwiceScale()[1]), - ValueType(iGradient[2] * map.getInvTwiceScale()[2]) ); - } - - // Stencil access version - template - static typename internal::ReturnValue::Vec3Type - result(const ScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename internal::ReturnValue::ValueType ValueType; - typedef typename internal::ReturnValue::Vec3Type Vec3Type; - - Vec3Type iGradient( ISGradient::result(stencil) ); - return Vec3Type(ValueType(iGradient[0] * map.getInvTwiceScale()[0]), - ValueType(iGradient[1] * map.getInvTwiceScale()[1]), - ValueType(iGradient[2] * map.getInvTwiceScale()[2]) ); - } -}; -//@} - - -//@{ -/// @brief Biased gradient operators, defined with respect to the range-space of the map -/// @note This will need to be divided by two in the case of CD_2NDT -template -struct GradientBiased -{ - // random access version - template static math::Vec3 - result(const MapType& map, const Accessor& grid, const Coord& ijk, - const Vec3& V) - { - typedef typename Accessor::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3d iGradient( ISGradientBiased::result(grid, ijk, V) ); - return Vec3Type(map.applyIJT(iGradient, ijk.asVec3d())); - } - - // stencil access version - template static math::Vec3 - result(const MapType& map, const StencilT& stencil, - const Vec3& V) - { - typedef typename StencilT::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3d iGradient( ISGradientBiased::result(stencil, V) ); - return Vec3Type(map.applyIJT(iGradient, stencil.getCenterCoord().asVec3d())); - } -}; -//@} - - -//////////////////////////////////////////////////////// - -// Computes |Grad[Phi]| using upwinding -template -struct GradientNormSqrd -{ - static const DScheme FD = BIAS_SCHEME::FD; - static const DScheme BD = BIAS_SCHEME::BD; - - - // random access version - template - static typename Accessor::ValueType - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3Type up = Gradient::result(map, grid, ijk); - Vec3Type down = Gradient::result(map, grid, ijk); - return math::GudonovsNormSqrd(grid.getValue(ijk)>0, down, up); - } - - // stencil access version - template - static typename StencilT::ValueType - result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - Vec3Type up = Gradient::result(map, stencil); - Vec3Type down = Gradient::result(map, stencil); - return math::GudonovsNormSqrd(stencil.template getValue<0, 0, 0>()>0, down, up); - } -}; - -/// Partial template specialization of GradientNormSqrd -template -struct GradientNormSqrd -{ - // random access version - template - static typename Accessor::ValueType - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return invdxdx * ISGradientNormSqrd::result(grid, ijk); - } - - // stencil access version - template - static typename StencilT::ValueType - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return invdxdx * ISGradientNormSqrd::result(stencil); - } -}; - -/// Partial template specialization of GradientNormSqrd -template -struct GradientNormSqrd -{ - // random access version - template - static typename Accessor::ValueType - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return invdxdx * ISGradientNormSqrd::result(grid, ijk); - } - - // stencil access version - template - static typename StencilT::ValueType - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return invdxdx * ISGradientNormSqrd::result(stencil); - } -}; - - -//@{ -/// @brief Compute the divergence of a vector-valued grid using differencing -/// of various orders, the result defined with respect to the range-space of the map. -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - for (int i=0; i < 3; i++) { - Vec3d vec( D1Vec::inX(grid, ijk, i), - D1Vec::inY(grid, ijk, i), - D1Vec::inZ(grid, ijk, i) ); - div += ValueType(map.applyIJT(vec, ijk.asVec3d())[i]); - } - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - for (int i=0; i < 3; i++) { - Vec3d vec( D1Vec::inX(stencil, i), - D1Vec::inY(stencil, i), - D1Vec::inZ(stencil, i) ); - div += ValueType(map.applyIJT(vec, stencil.getCenterCoord().asVec3d())[i]); - } - return div; - } -}; - -/// Partial template specialization of Divergence -/// translation, any scheme -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const TranslationMap&, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - div =ISDivergence::result(grid, ijk); - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const TranslationMap&, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - div =ISDivergence::result(stencil); - return div; - } -}; - -/// Partial template specialization of Divergence -/// uniform scale, any scheme -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(grid, ijk); - ValueType invdx = ValueType(map.getInvScale()[0]); - return div * invdx; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(stencil); - ValueType invdx = ValueType(map.getInvScale()[0]); - return div * invdx; - } -}; - -/// Partial template specialization of Divergence -/// uniform scale and translation, any scheme -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(grid, ijk); - ValueType invdx = ValueType(map.getInvScale()[0]); - return div * invdx; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(stencil); - ValueType invdx = ValueType(map.getInvScale()[0]); - return div * invdx; - } -}; - -/// Full template specialization of Divergence -/// uniform scale 2nd order -template<> -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - div =ISDivergence::result(grid, ijk); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return div * inv2dx; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - div =ISDivergence::result(stencil); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return div * inv2dx; - } -}; - -/// Full template specialization of Divergence -/// uniform scale translate 2nd order -template<> -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(grid, ijk); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return div * inv2dx; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - - div =ISDivergence::result(stencil); - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return div * inv2dx; - } -}; - -/// Partial template specialization of Divergence -/// scale, any scheme -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const ScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(grid, ijk, 0) * (map.getInvScale()[0]) + - D1Vec::inY(grid, ijk, 1) * (map.getInvScale()[1]) + - D1Vec::inZ(grid, ijk, 2) * (map.getInvScale()[2])); - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const ScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - div = ValueType( - D1Vec::inX(stencil, 0) * (map.getInvScale()[0]) + - D1Vec::inY(stencil, 1) * (map.getInvScale()[1]) + - D1Vec::inZ(stencil, 2) * (map.getInvScale()[2]) ); - return div; - } -}; - -/// Partial template specialization of Divergence -/// scale translate, any scheme -template -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const ScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(grid, ijk, 0) * (map.getInvScale()[0]) + - D1Vec::inY(grid, ijk, 1) * (map.getInvScale()[1]) + - D1Vec::inZ(grid, ijk, 2) * (map.getInvScale()[2])); - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const ScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div(0); - div = ValueType( - D1Vec::inX(stencil, 0) * (map.getInvScale()[0]) + - D1Vec::inY(stencil, 1) * (map.getInvScale()[1]) + - D1Vec::inZ(stencil, 2) * (map.getInvScale()[2]) ); - return div; - } -}; - -/// Full template specialization Divergence -/// scale 2nd order -template<> -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const ScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(grid, ijk, 0) * (map.getInvTwiceScale()[0]) + - D1Vec::inY(grid, ijk, 1) * (map.getInvTwiceScale()[1]) + - D1Vec::inZ(grid, ijk, 2) * (map.getInvTwiceScale()[2]) ); - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const ScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(stencil, 0) * (map.getInvTwiceScale()[0]) + - D1Vec::inY(stencil, 1) * (map.getInvTwiceScale()[1]) + - D1Vec::inZ(stencil, 2) * (map.getInvTwiceScale()[2]) ); - return div; - } -}; - -/// Full template specialization of Divergence -/// scale and translate, 2nd order -template<> -struct Divergence -{ - // random access version - template static typename Accessor::ValueType::value_type - result(const ScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(grid, ijk, 0) * (map.getInvTwiceScale()[0]) + - D1Vec::inY(grid, ijk, 1) * (map.getInvTwiceScale()[1]) + - D1Vec::inZ(grid, ijk, 2) * (map.getInvTwiceScale()[2]) ); - return div; - } - - // stencil access version - template static typename StencilT::ValueType::value_type - result(const ScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType::value_type ValueType; - - ValueType div = ValueType( - D1Vec::inX(stencil, 0) * (map.getInvTwiceScale()[0]) + - D1Vec::inY(stencil, 1) * (map.getInvTwiceScale()[1]) + - D1Vec::inZ(stencil, 2) * (map.getInvTwiceScale()[2]) ); - return div; - } -}; -//@} - - -//@{ -/// @brief Compute the curl of a vector-valued grid using differencing -/// of various orders in the space defined by the range of the map. -template -struct Curl -{ - // random access version - template static typename Accessor::ValueType - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - Vec3Type mat[3]; - for (int i = 0; i < 3; i++) { - Vec3d vec( - D1Vec::inX(grid, ijk, i), - D1Vec::inY(grid, ijk, i), - D1Vec::inZ(grid, ijk, i)); - // dF_i/dx_j (x_1 = x, x_2 = y, x_3 = z) - mat[i] = Vec3Type(map.applyIJT(vec, ijk.asVec3d())); - } - return Vec3Type(mat[2][1] - mat[1][2], // dF_3/dx_2 - dF_2/dx_3 - mat[0][2] - mat[2][0], // dF_1/dx_3 - dF_3/dx_1 - mat[1][0] - mat[0][1]); // dF_2/dx_1 - dF_1/dx_2 - } - - // stencil access version - template static typename StencilT::ValueType - result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - Vec3Type mat[3]; - for (int i = 0; i < 3; i++) { - Vec3d vec( - D1Vec::inX(stencil, i), - D1Vec::inY(stencil, i), - D1Vec::inZ(stencil, i)); - // dF_i/dx_j (x_1 = x, x_2 = y, x_3 = z) - mat[i] = Vec3Type(map.applyIJT(vec, stencil.getCenterCoord().asVec3d())); - } - return Vec3Type(mat[2][1] - mat[1][2], // dF_3/dx_2 - dF_2/dx_3 - mat[0][2] - mat[2][0], // dF_1/dx_3 - dF_3/dx_1 - mat[1][0] - mat[0][1]); // dF_2/dx_1 - dF_1/dx_2 - } -}; - -/// Partial template specialization of Curl -template -struct Curl -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - return ISCurl::result(grid, ijk) * ValueType(map.getInvScale()[0]); - } - - // Stencil access version - template static typename StencilT::ValueType - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - return ISCurl::result(stencil) * ValueType(map.getInvScale()[0]); - } -}; - -/// Partial template specialization of Curl -template -struct Curl -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(grid, ijk) * ValueType(map.getInvScale()[0]); - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(stencil) * ValueType(map.getInvScale()[0]); - } -}; - -/// Full template specialization of Curl -template<> -struct Curl -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(grid, ijk) * ValueType(map.getInvTwiceScale()[0]); - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(stencil) * ValueType(map.getInvTwiceScale()[0]); - } -}; - -/// Full template specialization of Curl -template<> -struct Curl -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(grid, ijk) * ValueType(map.getInvTwiceScale()[0]); - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType Vec3Type; - typedef typename Vec3Type::value_type ValueType; - - return ISCurl::result(stencil) * ValueType(map.getInvTwiceScale()[0]); - } -}; -//@} - - -//@{ -/// @brief Compute the Laplacian at a given location in a grid using finite differencing -/// of various orders. The result is defined in the range of the map. -template -struct Laplacian -{ - // random access version - template - static typename Accessor::ValueType result(const MapType& map, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - // all the second derivatives in index space - ValueType iddx = D2::inX(grid, ijk); - ValueType iddy = D2::inY(grid, ijk); - ValueType iddz = D2::inZ(grid, ijk); - - ValueType iddxy = D2::inXandY(grid, ijk); - ValueType iddyz = D2::inYandZ(grid, ijk); - ValueType iddxz = D2::inXandZ(grid, ijk); - - // second derivatives in index space - Mat3d d2_is(iddx, iddxy, iddxz, - iddxy, iddy, iddyz, - iddxz, iddyz, iddz); - - Mat3d d2_rs; // to hold the second derivative matrix in range space - if (is_linear::value) { - d2_rs = map.applyIJC(d2_is); - } else { - // compute the first derivatives with 2nd order accuracy. - Vec3d d1_is(static_cast(D1::inX(grid, ijk)), - static_cast(D1::inY(grid, ijk)), - static_cast(D1::inZ(grid, ijk))); - - d2_rs = map.applyIJC(d2_is, d1_is, ijk.asVec3d()); - } - - // the trace of the second derivative (range space) matrix is laplacian - return ValueType(d2_rs(0,0) + d2_rs(1,1) + d2_rs(2,2)); - } - - // stencil access version - template - static typename StencilT::ValueType result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - // all the second derivatives in index space - ValueType iddx = D2::inX(stencil); - ValueType iddy = D2::inY(stencil); - ValueType iddz = D2::inZ(stencil); - - ValueType iddxy = D2::inXandY(stencil); - ValueType iddyz = D2::inYandZ(stencil); - ValueType iddxz = D2::inXandZ(stencil); - - // second derivatives in index space - Mat3d d2_is(iddx, iddxy, iddxz, - iddxy, iddy, iddyz, - iddxz, iddyz, iddz); - - Mat3d d2_rs; // to hold the second derivative matrix in range space - if (is_linear::value) { - d2_rs = map.applyIJC(d2_is); - } else { - // compute the first derivatives with 2nd order accuracy. - Vec3d d1_is(D1::inX(stencil), - D1::inY(stencil), - D1::inZ(stencil) ); - - d2_rs = map.applyIJC(d2_is, d1_is, stencil.getCenterCoord().asVec3d()); - } - - // the trace of the second derivative (range space) matrix is laplacian - return ValueType(d2_rs(0,0) + d2_rs(1,1) + d2_rs(2,2)); - } -}; - - -template -struct Laplacian -{ - // random access version - template - static typename Accessor::ValueType result(const TranslationMap&, - const Accessor& grid, const Coord& ijk) - { - return ISLaplacian::result(grid, ijk); - } - - // stencil access version - template - static typename StencilT::ValueType result(const TranslationMap&, const StencilT& stencil) - { - return ISLaplacian::result(stencil); - } -}; - - -// The Laplacian is invariant to rotation or reflection. -template -struct Laplacian -{ - // random access version - template - static typename Accessor::ValueType result(const UnitaryMap&, - const Accessor& grid, const Coord& ijk) - { - return ISLaplacian::result(grid, ijk); - } - - // stencil access version - template - static typename StencilT::ValueType result(const UnitaryMap&, const StencilT& stencil) - { - return ISLaplacian::result(stencil); - } -}; - - -template -struct Laplacian -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ISLaplacian::result(grid, ijk) * invdxdx; - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ISLaplacian::result(stencil) * invdxdx; - } -}; - - -template -struct Laplacian -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ISLaplacian::result(grid, ijk) * invdxdx; - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ISLaplacian::result(stencil) * invdxdx; - } -}; - - -template -struct Laplacian -{ - // random access version - template static typename Accessor::ValueType - result(const ScaleMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - // compute the second derivatives in index space - ValueType iddx = D2::inX(grid, ijk); - ValueType iddy = D2::inY(grid, ijk); - ValueType iddz = D2::inZ(grid, ijk); - const Vec3d& invScaleSqr = map.getInvScaleSqr(); - // scale them by the appropriate 1/dx^2, 1/dy^2, 1/dz^2 and sum - return ValueType(iddx * invScaleSqr[0] + iddy * invScaleSqr[1] + iddz * invScaleSqr[2]); - } - - // stencil access version - template static typename StencilT::ValueType - result(const ScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - // compute the second derivatives in index space - ValueType iddx = D2::inX(stencil); - ValueType iddy = D2::inY(stencil); - ValueType iddz = D2::inZ(stencil); - const Vec3d& invScaleSqr = map.getInvScaleSqr(); - // scale them by the appropriate 1/dx^2, 1/dy^2, 1/dz^2 and sum - return ValueType(iddx * invScaleSqr[0] + iddy * invScaleSqr[1] + iddz * invScaleSqr[2]); - } -}; - - -template -struct Laplacian -{ - // random access version - template static typename Accessor::ValueType - result(const ScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - // compute the second derivatives in index space - ValueType iddx = D2::inX(grid, ijk); - ValueType iddy = D2::inY(grid, ijk); - ValueType iddz = D2::inZ(grid, ijk); - const Vec3d& invScaleSqr = map.getInvScaleSqr(); - // scale them by the appropriate 1/dx^2, 1/dy^2, 1/dz^2 and sum - return ValueType(iddx * invScaleSqr[0] + iddy * invScaleSqr[1] + iddz * invScaleSqr[2]); - } - - // stencil access version - template static typename StencilT::ValueType - result(const ScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - // compute the second derivatives in index space - ValueType iddx = D2::inX(stencil); - ValueType iddy = D2::inY(stencil); - ValueType iddz = D2::inZ(stencil); - const Vec3d& invScaleSqr = map.getInvScaleSqr(); - // scale them by the appropriate 1/dx^2, 1/dy^2, 1/dz^2 and sum - return ValueType(iddx * invScaleSqr[0] + iddy * invScaleSqr[1] + iddz * invScaleSqr[2]); - } -}; - - -/// @brief Compute the closest-point transform to a level set. -/// @return the closest point to the surface from which the level set was derived, -/// in the domain space of the map (e.g., voxel space). -template -struct CPT -{ - // random access version - template static math::Vec3 - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typedef Vec3 Vec3Type; - - // current distance - ValueType d = grid.getValue(ijk); - // compute gradient in physical space where it is a unit normal - // since the grid holds a distance level set. - Vec3d vectorFromSurface(d*Gradient::result(map, grid, ijk)); - if (is_linear::value) { - Vec3d result = ijk.asVec3d() - map.applyInverseMap(vectorFromSurface); - return Vec3Type(result); - } else { - Vec3d location = map.applyMap(ijk.asVec3d()); - Vec3d result = map.applyInverseMap(location - vectorFromSurface); - return Vec3Type(result); - } - } - - // stencil access version - template static math::Vec3 - result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - typedef Vec3 Vec3Type; - - // current distance - ValueType d = stencil.template getValue<0, 0, 0>(); - // compute gradient in physical space where it is a unit normal - // since the grid holds a distance level set. - Vec3d vectorFromSurface(d*Gradient::result(map, stencil)); - if (is_linear::value) { - Vec3d result = stencil.getCenterCoord().asVec3d() - - map.applyInverseMap(vectorFromSurface); - return Vec3Type(result); - } else { - Vec3d location = map.applyMap(stencil.getCenterCoord().asVec3d()); - Vec3d result = map.applyInverseMap(location - vectorFromSurface); - return Vec3Type(result); - } - } -}; - - -/// @brief Compute the closest-point transform to a level set. -/// @return the closest point to the surface from which the level set was derived, -/// in the range space of the map (e.g., in world space) -template -struct CPT_RANGE -{ - // random access version - template static Vec3 - result(const MapType& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - typedef Vec3 Vec3Type; - // current distance - ValueType d = grid.getValue(ijk); - // compute gradient in physical space where it is a unit normal - // since the grid holds a distance level set. - Vec3Type vectorFromSurface = - d*Gradient::result(map, grid, ijk); - Vec3d result = map.applyMap(ijk.asVec3d()) - vectorFromSurface; - - return Vec3Type(result); - } - - // stencil access version - template static Vec3 - result(const MapType& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - typedef Vec3 Vec3Type; - // current distance - ValueType d = stencil.template getValue<0, 0, 0>(); - // compute gradient in physical space where it is a unit normal - // since the grid holds a distance level set. - Vec3Type vectorFromSurface = - d*Gradient::result(map, stencil); - Vec3d result = map.applyMap(stencil.getCenterCoord().asVec3d()) - vectorFromSurface; - - return Vec3Type(result); - } -}; - - -/// @brief Compute the mean curvature. -/// @return the mean curvature in two parts: @c alpha is the numerator in -/// @f$\nabla \cdot (\nabla \phi / |\nabla \phi|)@f$, and @c beta is @f$|\nabla \phi|@f$. -template -struct MeanCurvature -{ - /// @brief random access version - /// @return true if the gradient is none-zero, in which case the - /// mean curvature is computed as two parts: @c alpha is the numerator in - /// @f$\nabla \cdot (\nabla \phi / |\nabla \phi|)@f$, and @c beta is @f$|\nabla \phi|@f$. - template - static bool compute(const MapType& map, const Accessor& grid, const Coord& ijk, - double& alpha, double& beta) - { - typedef typename Accessor::ValueType ValueType; - - // compute the gradient in index and world space - Vec3d d1_is(static_cast(D1::inX(grid, ijk)), - static_cast(D1::inY(grid, ijk)), - static_cast(D1::inZ(grid, ijk))), d1_ws; - if (is_linear::value) {//resolved at compiletime - d1_ws = map.applyIJT(d1_is); - } else { - d1_ws = map.applyIJT(d1_is, ijk.asVec3d()); - } - const double Dx2 = d1_ws(0)*d1_ws(0); - const double Dy2 = d1_ws(1)*d1_ws(1); - const double Dz2 = d1_ws(2)*d1_ws(2); - const double normGrad = Dx2 + Dy2 + Dz2; - if (normGrad <= math::Tolerance::value()) { - alpha = beta = 0; - return false; - } - - // all the second derivatives in index space - ValueType iddx = D2::inX(grid, ijk); - ValueType iddy = D2::inY(grid, ijk); - ValueType iddz = D2::inZ(grid, ijk); - - ValueType iddxy = D2::inXandY(grid, ijk); - ValueType iddyz = D2::inYandZ(grid, ijk); - ValueType iddxz = D2::inXandZ(grid, ijk); - - // second derivatives in index space - Mat3d d2_is(iddx, iddxy, iddxz, - iddxy, iddy, iddyz, - iddxz, iddyz, iddz); - - // convert second derivatives to world space - Mat3d d2_ws; - if (is_linear::value) {//resolved at compiletime - d2_ws = map.applyIJC(d2_is); - } else { - d2_ws = map.applyIJC(d2_is, d1_is, ijk.asVec3d()); - } - - // assemble the nominator and denominator for mean curvature - alpha = (Dx2*(d2_ws(1,1)+d2_ws(2,2))+Dy2*(d2_ws(0,0)+d2_ws(2,2)) - +Dz2*(d2_ws(0,0)+d2_ws(1,1)) - -2*(d1_ws(0)*(d1_ws(1)*d2_ws(0,1)+d1_ws(2)*d2_ws(0,2)) - +d1_ws(1)*d1_ws(2)*d2_ws(1,2))); - beta = std::sqrt(normGrad); // * 1/dx - return true; - } - - template - static typename Accessor::ValueType result(const MapType& map, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - double alpha, beta; - return compute(map, grid, ijk, alpha, beta) ? - ValueType(alpha/(2. *math::Pow3(beta))) : 0; - } - - template - static typename Accessor::ValueType normGrad(const MapType& map, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - double alpha, beta; - return compute(map, grid, ijk, alpha, beta) ? - ValueType(alpha/(2. *math::Pow2(beta))) : 0; - } - - /// @brief stencil access version - /// @return true if the gradient is none-zero, in which case the - /// mean curvature is computed as two parts: @c alpha is the numerator in - /// @f$\nabla \cdot (\nabla \phi / |\nabla \phi|)@f$, and @c beta is @f$|\nabla \phi|@f$. - template - static bool compute(const MapType& map, const StencilT& stencil, - double& alpha, double& beta) - { - typedef typename StencilT::ValueType ValueType; - - // compute the gradient in index and world space - Vec3d d1_is(D1::inX(stencil), - D1::inY(stencil), - D1::inZ(stencil) ), d1_ws; - if (is_linear::value) {//resolved at compiletime - d1_ws = map.applyIJT(d1_is); - } else { - d1_ws = map.applyIJT(d1_is, stencil.getCenterCoord().asVec3d()); - } - const double Dx2 = d1_ws(0)*d1_ws(0); - const double Dy2 = d1_ws(1)*d1_ws(1); - const double Dz2 = d1_ws(2)*d1_ws(2); - const double normGrad = Dx2 + Dy2 + Dz2; - if (normGrad <= math::Tolerance::value()) { - alpha = beta = 0; - return false; - } - - // all the second derivatives in index space - ValueType iddx = D2::inX(stencil); - ValueType iddy = D2::inY(stencil); - ValueType iddz = D2::inZ(stencil); - - ValueType iddxy = D2::inXandY(stencil); - ValueType iddyz = D2::inYandZ(stencil); - ValueType iddxz = D2::inXandZ(stencil); - - // second derivatives in index space - Mat3d d2_is(iddx, iddxy, iddxz, - iddxy, iddy, iddyz, - iddxz, iddyz, iddz); - - // convert second derivatives to world space - Mat3d d2_ws; - if (is_linear::value) {//resolved at compiletime - d2_ws = map.applyIJC(d2_is); - } else { - d2_ws = map.applyIJC(d2_is, d1_is, stencil.getCenterCoord().asVec3d()); - } - - // for return - alpha = (Dx2*(d2_ws(1,1)+d2_ws(2,2))+Dy2*(d2_ws(0,0)+d2_ws(2,2)) - +Dz2*(d2_ws(0,0)+d2_ws(1,1)) - -2*(d1_ws(0)*(d1_ws(1)*d2_ws(0,1)+d1_ws(2)*d2_ws(0,2)) - +d1_ws(1)*d1_ws(2)*d2_ws(1,2))); - beta = std::sqrt(normGrad); // * 1/dx - return true; - } - - template - static typename StencilT::ValueType - result(const MapType& map, const StencilT stencil) - { - typedef typename StencilT::ValueType ValueType; - double alpha, beta; - return compute(map, stencil, alpha, beta) ? - ValueType(alpha/(2*math::Pow3(beta))) : 0; - } - - template - static typename StencilT::ValueType normGrad(const MapType& map, const StencilT stencil) - { - typedef typename StencilT::ValueType ValueType; - double alpha, beta; - return compute(map, stencil, alpha, beta) ? - ValueType(alpha/(2*math::Pow2(beta))) : 0; - } -}; - - -template -struct MeanCurvature -{ - // random access version - template - static typename Accessor::ValueType result(const TranslationMap&, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - return ISMeanCurvature::result(grid, ijk, alpha, beta) ? - ValueType(alpha /(2*math::Pow3(beta))) : 0; - } - - template - static typename Accessor::ValueType normGrad(const TranslationMap&, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - return ISMeanCurvature::result(grid, ijk, alpha, beta) ? - ValueType(alpha/(2*math::Pow2(beta))) : 0; - } - - // stencil access version - template - static typename StencilT::ValueType result(const TranslationMap&, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - return ISMeanCurvature::result(stencil, alpha, beta) ? - ValueType(alpha /(2*math::Pow3(beta))) : 0; - } - - template - static typename StencilT::ValueType normGrad(const TranslationMap&, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - return ISMeanCurvature::result(stencil, alpha, beta) ? - ValueType(alpha/(2*math::Pow2(beta))) : 0; - } -}; - - -template -struct MeanCurvature -{ - // random access version - template - static typename Accessor::ValueType result(const UniformScaleMap& map, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(grid, ijk, alpha, beta)) { - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return ValueType(alpha*inv2dx/math::Pow3(beta)); - } - return 0; - } - - template - static typename Accessor::ValueType normGrad(const UniformScaleMap& map, - const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(grid, ijk, alpha, beta)) { - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ValueType(alpha*invdxdx/(2*math::Pow2(beta))); - } - return 0; - } - - // stencil access version - template - static typename StencilT::ValueType result(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(stencil, alpha, beta)) { - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return ValueType(alpha*inv2dx/math::Pow3(beta)); - } - return 0; - } - - template - static typename StencilT::ValueType normGrad(const UniformScaleMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(stencil, alpha, beta)) { - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ValueType(alpha*invdxdx/(2*math::Pow2(beta))); - } - return 0; - } -}; - - -template -struct MeanCurvature -{ - // random access version - template static typename Accessor::ValueType - result(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(grid, ijk, alpha, beta)) { - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return ValueType(alpha*inv2dx/math::Pow3(beta)); - } - return 0; - } - - template static typename Accessor::ValueType - normGrad(const UniformScaleTranslateMap& map, const Accessor& grid, const Coord& ijk) - { - typedef typename Accessor::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(grid, ijk, alpha, beta)) { - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ValueType(alpha*invdxdx/(2*math::Pow2(beta))); - } - return 0; - } - - // stencil access version - template static typename StencilT::ValueType - result(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(stencil, alpha, beta)) { - ValueType inv2dx = ValueType(map.getInvTwiceScale()[0]); - return ValueType(alpha*inv2dx/math::Pow3(beta)); - } - return 0; - } - - template static typename StencilT::ValueType - normGrad(const UniformScaleTranslateMap& map, const StencilT& stencil) - { - typedef typename StencilT::ValueType ValueType; - - ValueType alpha, beta; - if (ISMeanCurvature::result(stencil, alpha, beta)) { - ValueType invdxdx = ValueType(map.getInvScaleSqr()[0]); - return ValueType(alpha*invdxdx/(2*math::Pow2(beta))); - } - return 0; - } -}; - - -/// @brief A wrapper that holds a MapBase::ConstPtr and exposes a reduced set -/// of functionality needed by the mathematical operators -/// @details This may be used in some Map-templated code, when the overhead of -/// actually resolving the @c Map type is large compared to the map work to be done. -class GenericMap -{ -public: - template - GenericMap(const GridType& g): mMap(g.transform().baseMap()) {} - - GenericMap(const Transform& t): mMap(t.baseMap()) {} - GenericMap(MapBase::Ptr map): mMap(boost::const_pointer_cast(map)) {} - GenericMap(MapBase::ConstPtr map): mMap(map) {} - ~GenericMap() {} - - Vec3d applyMap(const Vec3d& in) const { return mMap->applyMap(in); } - Vec3d applyInverseMap(const Vec3d& in) const { return mMap->applyInverseMap(in); } - - Vec3d applyIJT(const Vec3d& in) const { return mMap->applyIJT(in); } - Vec3d applyIJT(const Vec3d& in, const Vec3d& pos) const { return mMap->applyIJT(in, pos); } - Mat3d applyIJC(const Mat3d& m) const { return mMap->applyIJC(m); } - Mat3d applyIJC(const Mat3d& m, const Vec3d& v, const Vec3d& pos) const - { return mMap->applyIJC(m,v,pos); } - - double determinant() const { return mMap->determinant(); } - double determinant(const Vec3d& in) const { return mMap->determinant(in); } - - Vec3d voxelSize() const { return mMap->voxelSize(); } - Vec3d voxelSize(const Vec3d&v) const { return mMap->voxelSize(v); } - -private: - MapBase::ConstPtr mMap; -}; - -} // end math namespace -} // namespace OPENVDB_VERSION_NAME -} // end openvdb namespace - -#endif // OPENVDB_MATH_OPERATORS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Proximity.cc b/openvdb_3_0_0_library/math/Proximity.cc deleted file mode 100755 index 8af2779..0000000 --- a/openvdb_3_0_0_library/math/Proximity.cc +++ /dev/null @@ -1,162 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Proximity.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -OPENVDB_API Vec3d -closestPointOnTriangleToPoint( - const Vec3d& a, const Vec3d& b, const Vec3d& c, const Vec3d& p, Vec3d& uvw) -{ - uvw.setZero(); - - // degenerate triangle, singular - if ((isApproxEqual(a, b) && isApproxEqual(a, c))) { - uvw[0] = 1.0; - return a; - } - - Vec3d ab = b - a, ac = c - a, ap = p - a; - double d1 = ab.dot(ap), d2 = ac.dot(ap); - - // degenerate triangle edges - if (isApproxEqual(a, b)) { - - double t = 0.0; - Vec3d cp = closestPointOnSegmentToPoint(a, c, p, t); - - uvw[0] = 1.0 - t; - uvw[2] = t; - - return cp; - - } else if (isApproxEqual(a, c) || isApproxEqual(b, c)) { - - double t = 0.0; - Vec3d cp = closestPointOnSegmentToPoint(a, b, p, t); - uvw[0] = 1.0 - t; - uvw[1] = t; - return cp; - } - - if (d1 <= 0.0 && d2 <= 0.0) { - uvw[0] = 1.0; - return a; // barycentric coordinates (1,0,0) - } - - // Check if P in vertex region outside B - Vec3d bp = p - b; - double d3 = ab.dot(bp), d4 = ac.dot(bp); - if (d3 >= 0.0 && d4 <= d3) { - uvw[1] = 1.0; - return b; // barycentric coordinates (0,1,0) - } - - // Check if P in edge region of AB, if so return projection of P onto AB - double vc = d1 * d4 - d3 * d2; - if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) { - uvw[1] = d1 / (d1 - d3); - uvw[0] = 1.0 - uvw[1]; - return a + uvw[1] * ab; // barycentric coordinates (1-v,v,0) - } - - // Check if P in vertex region outside C - Vec3d cp = p - c; - double d5 = ab.dot(cp), d6 = ac.dot(cp); - if (d6 >= 0.0 && d5 <= d6) { - uvw[2] = 1.0; - return c; // barycentric coordinates (0,0,1) - } - - // Check if P in edge region of AC, if so return projection of P onto AC - double vb = d5 * d2 - d1 * d6; - if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) { - uvw[2] = d2 / (d2 - d6); - uvw[0] = 1.0 - uvw[2]; - return a + uvw[2] * ac; // barycentric coordinates (1-w,0,w) - } - - // Check if P in edge region of BC, if so return projection of P onto BC - double va = d3*d6 - d5*d4; - if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) { - uvw[2] = (d4 - d3) / ((d4 - d3) + (d5 - d6)); - uvw[1] = 1.0 - uvw[2]; - return b + uvw[2] * (c - b); // barycentric coordinates (0,1-w,w) - } - - // P inside face region. Compute Q through its barycentric coordinates (u,v,w) - double denom = 1.0 / (va + vb + vc); - uvw[2] = vc * denom; - uvw[1] = vb * denom; - uvw[0] = 1.0 - uvw[1] - uvw[2]; - - return a + ab*uvw[1] + ac*uvw[2]; // = u*a + v*b + w*c , u= va*denom = 1.0-v-w -} - - -OPENVDB_API Vec3d -closestPointOnSegmentToPoint(const Vec3d& a, const Vec3d& b, const Vec3d& p, double& t) -{ - Vec3d ab = b - a; - t = (p - a).dot(ab); - - if (t <= 0.0) { - // c projects outside the [a,b] interval, on the a side. - t = 0.0; - return a; - } else { - - // always nonnegative since denom = ||ab||^2 - double denom = ab.dot(ab); - - if (t >= denom) { - // c projects outside the [a,b] interval, on the b side. - t = 1.0; - return b; - } else { - // c projects inside the [a,b] interval. - t = t / denom; - return a + (ab * t); - } - } -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Proximity.h b/openvdb_3_0_0_library/math/Proximity.h deleted file mode 100755 index 939d236..0000000 --- a/openvdb_3_0_0_library/math/Proximity.h +++ /dev/null @@ -1,79 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_PROXIMITY_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_PROXIMITY_HAS_BEEN_INCLUDED - -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @brief Closest Point on Triangle to Point. Given a triangle @c abc and a point @c p, -/// return the point on @c abc closest to @c p and the corresponding barycentric coordinates. -/// -/// @details Algorithms from "Real-Time Collision Detection" pg 136 to 142 by Christer Ericson. -/// The closest point is obtained by first determining which of the triangles' -/// Voronoi feature regions @c p is in and then computing the orthogonal projection -/// of @c p onto the corresponding feature. -/// -/// @param a The triangle's first vertex point. -/// @param b The triangle's second vertex point. -/// @param c The triangle's third vertex point. -/// @param p Point to compute the closest point on @c abc for. -/// @param uvw Barycentric coordinates, computed and returned. -OPENVDB_API Vec3d -closestPointOnTriangleToPoint( - const Vec3d& a, const Vec3d& b, const Vec3d& c, const Vec3d& p, Vec3d& uvw); - - -/// @brief Closest Point on Line Segment to Point. Given segment @c ab and point @c p, -/// return the point on @c ab closest to @c p and @c t the parametric distance to @c b. -/// -/// @param a The segment's first vertex point. -/// @param b The segment's second vertex point. -/// @param p Point to compute the closest point on @c ab for. -/// @param t Parametric distance to @c b. -OPENVDB_API Vec3d -closestPointOnSegmentToPoint( - const Vec3d& a, const Vec3d& b, const Vec3d& p, double& t); - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_MESH_TO_VOLUME_UTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/QuantizedUnitVec.cc b/openvdb_3_0_0_library/math/QuantizedUnitVec.cc deleted file mode 100755 index a2a8f52..0000000 --- a/openvdb_3_0_0_library/math/QuantizedUnitVec.cc +++ /dev/null @@ -1,97 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "QuantizedUnitVec.h" -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - - -bool QuantizedUnitVec::sInitialized = false; -float QuantizedUnitVec::sNormalizationWeights[MASK_SLOTS + 1]; - -// Declare this at file scope to ensure thread-safe initialization. -tbb::mutex sInitMutex; - - -//////////////////////////////////////// - - -void -QuantizedUnitVec::init() -{ - tbb::mutex::scoped_lock lock(sInitMutex); - - if (!sInitialized) { - - OPENVDB_START_THREADSAFE_STATIC_WRITE - - sInitialized = true; - - uint16_t xbits, ybits; - double x, y, z, w; - - for (uint16_t b = 0; b < 8192; ++b) { - - xbits = uint16_t((b & MASK_XSLOT) >> 7); - ybits = b & MASK_YSLOT; - - if ((xbits + ybits) > 126) { - xbits = uint16_t(127 - xbits); - ybits = uint16_t(127 - ybits); - } - - x = double(xbits); - y = double(ybits); - z = double(126 - xbits - ybits); - w = 1.0 / std::sqrt(x*x + y*y + z*z); - - sNormalizationWeights[b] = float(w); - } - - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - } -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/QuantizedUnitVec.h b/openvdb_3_0_0_library/math/QuantizedUnitVec.h deleted file mode 100755 index 575cc0b..0000000 --- a/openvdb_3_0_0_library/math/QuantizedUnitVec.h +++ /dev/null @@ -1,164 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED - -#include -#include -#include "Vec3.h" -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -// Bit compression method that effciently represents a unit vector using -// 2 bytes i.e. 16 bits of data by only storing two quantized components. -// Based on "Higher Accuracy Quantized Normals" article from GameDev.Net LLC, 2000 - -class OPENVDB_API QuantizedUnitVec -{ -public: - - template - static uint16_t pack(const Vec3& vec); - static Vec3s unpack(const uint16_t data); - - static void flipSignBits(uint16_t&); - -private: - QuantizedUnitVec() {} - - // threadsafe initialization function for the normalization weights. - static void init(); - - // bit masks - static const uint16_t MASK_SLOTS = 0x1FFF; // 0001111111111111 - static const uint16_t MASK_XSLOT = 0x1F80; // 0001111110000000 - static const uint16_t MASK_YSLOT = 0x007F; // 0000000001111111 - static const uint16_t MASK_XSIGN = 0x8000; // 1000000000000000 - static const uint16_t MASK_YSIGN = 0x4000; // 0100000000000000 - static const uint16_t MASK_ZSIGN = 0x2000; // 0010000000000000 - - // initialization flag. - static bool sInitialized; - - // normalization weights, 32 kilobytes. - static float sNormalizationWeights[MASK_SLOTS + 1]; -}; // class QuantizedUnitVec - - -//////////////////////////////////////// - - -template -inline uint16_t -QuantizedUnitVec::pack(const Vec3& vec) -{ - uint16_t data = 0; - T x(vec[0]), y(vec[1]), z(vec[2]); - - // The sign of the three components are first stored using - // 3-bits and can then safely be discarded. - if (x < T(0.0)) { data |= MASK_XSIGN; x = -x; } - if (y < T(0.0)) { data |= MASK_YSIGN; y = -y; } - if (z < T(0.0)) { data |= MASK_ZSIGN; z = -z; } - - // The z component is discarded and x & y are quantized in - // the 0 to 126 range. - T w = T(126.0) / (x + y + z); - uint16_t xbits = static_cast((x * w)); - uint16_t ybits = static_cast((y * w)); - - // The remaining 13 bits in our 16 bit word are dividied into a - // 6-bit x-slot and a 7-bit y-slot. Both the xbits and the ybits - // can still be represented using (2^7 - 1) quantization levels. - - // If the xbits requre more than 6-bits, store the complement. - // (xbits + ybits < 127, thus if xbits > 63 => ybits <= 63) - if(xbits > 63) { - xbits = static_cast(127 - xbits); - ybits = static_cast(127 - ybits); - } - - // Pack components into their respective slots. - data = static_cast(data | (xbits << 7)); - data = static_cast(data | ybits); - return data; -} - - -inline Vec3s -QuantizedUnitVec::unpack(const uint16_t data) -{ - if (!sInitialized) init(); - - const float w = sNormalizationWeights[data & MASK_SLOTS]; - - uint16_t xbits = static_cast((data & MASK_XSLOT) >> 7); - uint16_t ybits = static_cast(data & MASK_YSLOT); - - // Check if the complement components where stored and revert. - if ((xbits + ybits) > 126) { - xbits = static_cast(127 - xbits); - ybits = static_cast(127 - ybits); - } - - Vec3s vec(float(xbits) * w, float(ybits) * w, float(126 - xbits - ybits) * w); - - if (data & MASK_XSIGN) vec[0] = -vec[0]; - if (data & MASK_YSIGN) vec[1] = -vec[1]; - if (data & MASK_ZSIGN) vec[2] = -vec[2]; - return vec; -} - - -//////////////////////////////////////// - - -inline void -QuantizedUnitVec::flipSignBits(uint16_t& v) -{ - v = static_cast((v & MASK_SLOTS) | (~v & ~MASK_SLOTS)); -} - - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Quat.h b/openvdb_3_0_0_library/math/Quat.h deleted file mode 100755 index d9365c7..0000000 --- a/openvdb_3_0_0_library/math/Quat.h +++ /dev/null @@ -1,658 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED - -#include -#include - -#include "Mat.h" -#include "Mat3.h" -#include "Math.h" -#include "Vec3.h" -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Quat; - -/// Linear interpolation between the two quaternions -template -Quat slerp(const Quat &q1, const Quat &q2, T t, T tolerance=0.00001) -{ - T qdot, angle, sineAngle; - - qdot = q1.dot(q2); - - if (fabs(qdot) >= 1.0) { - angle = 0; // not necessary but suppresses compiler warning - sineAngle = 0; - } else { - angle = acos(qdot); - sineAngle = sin(angle); - } - - // - // Denominator close to 0 corresponds to the case where the - // two quaternions are close to the same rotation. In this - // case linear interpolation is used but we normalize to - // guarantee unit length - // - if (sineAngle <= tolerance) { - T s = 1.0 - t; - - Quat qtemp(s * q1[0] + t * q2[0], s * q1[1] + t * q2[1], - s * q1[2] + t * q2[2], s * q1[3] + t * q2[3]); - // - // Check the case where two close to antipodal quaternions were - // blended resulting in a nearly zero result which can happen, - // for example, if t is close to 0.5. In this case it is not safe - // to project back onto the sphere. - // - double lengthSquared = qtemp.dot(qtemp); - - if (lengthSquared <= tolerance * tolerance) { - qtemp = (t < 0.5) ? q1 : q2; - } else { - qtemp *= 1.0 / sqrt(lengthSquared); - } - return qtemp; - } else { - - T sine = 1.0 / sineAngle; - T a = sin((1.0 - t) * angle) * sine; - T b = sin(t * angle) * sine; - return Quat(a * q1[0] + b * q2[0], a * q1[1] + b * q2[1], - a * q1[2] + b * q2[2], a * q1[3] + b * q2[3]); - } - -} - -template -class Quat -{ -public: - /// Trivial constructor, the quaternion is NOT initialized - Quat() {} - - /// Constructor with four arguments, e.g. Quatf q(1,2,3,4); - Quat(T x, T y, T z, T w) - { - mm[0] = x; - mm[1] = y; - mm[2] = z; - mm[3] = w; - - } - - /// Constructor with array argument, e.g. float a[4]; Quatf q(a); - Quat(T *a) - { - mm[0] = a[0]; - mm[1] = a[1]; - mm[2] = a[2]; - mm[3] = a[3]; - - } - - /// Constructor given rotation as axis and angle, the axis must be - /// unit vector - Quat(const Vec3 &axis, T angle) - { - // assert( REL_EQ(axis.length(), 1.) ); - - T s = T(sin(angle*T(0.5))); - - mm[0] = axis.x() * s; - mm[1] = axis.y() * s; - mm[2] = axis.z() * s; - - mm[3] = T(cos(angle*T(0.5))); - - } - - /// Constructor given rotation as axis and angle - Quat(math::Axis axis, T angle) - { - T s = T(sin(angle*T(0.5))); - - mm[0] = (axis==math::X_AXIS) * s; - mm[1] = (axis==math::Y_AXIS) * s; - mm[2] = (axis==math::Z_AXIS) * s; - - mm[3] = T(cos(angle*T(0.5))); - } - - /// Constructor given a rotation matrix - template - Quat(const Mat3 &rot) { - - // verify that the matrix is really a rotation - if(!isUnitary(rot)) { // unitary is reflection or rotation - OPENVDB_THROW(ArithmeticError, - "A non-rotation matrix can not be used to construct a quaternion"); - } - if (!isApproxEqual(rot.det(), (T1)1)) { // rule out reflection - OPENVDB_THROW(ArithmeticError, - "A reflection matrix can not be used to construct a quaternion"); - } - - T trace = (T)rot.trace(); - if (trace > 0) { - - T q_w = 0.5 * std::sqrt(trace+1); - T factor = 0.25 / q_w; - - mm[0] = factor * (rot(1,2) - rot(2,1)); - mm[1] = factor * (rot(2,0) - rot(0,2)); - mm[2] = factor * (rot(0,1) - rot(1,0)); - mm[3] = q_w; - } else if (rot(0,0) > rot(1,1) && rot(0,0) > rot(2,2)) { - - T q_x = 0.5 * sqrt(rot(0,0)- rot(1,1)-rot(2,2)+1); - T factor = 0.25 / q_x; - - mm[0] = q_x; - mm[1] = factor * (rot(0,1) + rot(1,0)); - mm[2] = factor * (rot(2,0) + rot(0,2)); - mm[3] = factor * (rot(1,2) - rot(2,1)); - } else if (rot(1,1) > rot(2,2)) { - - T q_y = 0.5 * sqrt(rot(1,1)-rot(0,0)-rot(2,2)+1); - T factor = 0.25 / q_y; - - mm[0] = factor * (rot(0,1) + rot(1,0)); - mm[1] = q_y; - mm[2] = factor * (rot(1,2) + rot(2,1)); - mm[3] = factor * (rot(2,0) - rot(0,2)); - } else { - - T q_z = 0.5 * sqrt(rot(2,2)-rot(0,0)-rot(1,1)+1); - T factor = 0.25 / q_z; - - mm[0] = factor * (rot(2,0) + rot(0,2)); - mm[1] = factor * (rot(1,2) + rot(2,1)); - mm[2] = q_z; - mm[3] = factor * (rot(0,1) - rot(1,0)); - } - } - - /// Copy constructor - Quat(const Quat &q) - { - mm[0] = q.mm[0]; - mm[1] = q.mm[1]; - mm[2] = q.mm[2]; - mm[3] = q.mm[3]; - - } - - /// Reference to the component, e.g. q.x() = 4.5f; - T& x() { return mm[0]; } - T& y() { return mm[1]; } - T& z() { return mm[2]; } - T& w() { return mm[3]; } - - /// Get the component, e.g. float f = q.w(); - T x() const { return mm[0]; } - T y() const { return mm[1]; } - T z() const { return mm[2]; } - T w() const { return mm[3]; } - - // Number of elements - static unsigned numElements() { return 4; } - - /// Array style reference to the components, e.g. q[3] = 1.34f; - T& operator[](int i) { return mm[i]; } - - /// Array style constant reference to the components, e.g. float f = q[1]; - T operator[](int i) const { return mm[i]; } - - /// Cast to T* - operator T*() { return mm; } - operator const T*() const { return mm; } - - /// Alternative indexed reference to the elements - T& operator()(int i) { return mm[i]; } - - /// Alternative indexed constant reference to the elements, - T operator()(int i) const { return mm[i]; } - - /// Return angle of rotation - T angle() const - { - T sqrLength = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2]; - - if ( sqrLength > 1.0e-8 ) { - - return T(T(2.0) * acos(mm[3])); - - } else { - - return T(0.0); - } - } - - /// Return axis of rotation - Vec3 axis() const - { - T sqrLength = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2]; - - if ( sqrLength > 1.0e-8 ) { - - T invLength = T(T(1)/sqrt(sqrLength)); - - return Vec3( mm[0]*invLength, mm[1]*invLength, mm[2]*invLength ); - } else { - - return Vec3(1,0,0); - } - } - - - /// "this" quaternion gets initialized to [x, y, z, w] - Quat& init(T x, T y, T z, T w) - { - mm[0] = x; mm[1] = y; mm[2] = z; mm[3] = w; - return *this; - } - - /// "this" quaternion gets initialized to identity, same as setIdentity() - Quat& init() { return setIdentity(); } - - /// Set "this" quaternion to rotation specified by axis and angle, - /// the axis must be unit vector - Quat& setAxisAngle(const Vec3& axis, T angle) - { - - T s = T(sin(angle*T(0.5))); - - mm[0] = axis.x() * s; - mm[1] = axis.y() * s; - mm[2] = axis.z() * s; - - mm[3] = T(cos(angle*T(0.5))); - - return *this; - } // axisAngleTest - - /// Set "this" vector to zero - Quat& setZero() - { - mm[0] = mm[1] = mm[2] = mm[3] = 0; - return *this; - } - - /// Set "this" vector to identity - Quat& setIdentity() - { - mm[0] = mm[1] = mm[2] = 0; - mm[3] = 1; - return *this; - } - - /// Returns vector of x,y,z rotational components - Vec3 eulerAngles(RotationOrder rotationOrder) const - { return math::eulerAngles(Mat3(*this), rotationOrder); } - - /// Assignment operator - Quat& operator=(const Quat &q) - { - mm[0] = q.mm[0]; - mm[1] = q.mm[1]; - mm[2] = q.mm[2]; - mm[3] = q.mm[3]; - - return *this; - } - - /// Equality operator, does exact floating point comparisons - bool operator==(const Quat &q) const - { - return (isExactlyEqual(mm[0],q.mm[0]) && - isExactlyEqual(mm[1],q.mm[1]) && - isExactlyEqual(mm[2],q.mm[2]) && - isExactlyEqual(mm[3],q.mm[3]) ); - } - - /// Test if "this" is equivalent to q with tolerance of eps value - bool eq(const Quat &q, T eps=1.0e-7) const - { - return isApproxEqual(mm[0],q.mm[0],eps) && isApproxEqual(mm[1],q.mm[1],eps) && - isApproxEqual(mm[2],q.mm[2],eps) && isApproxEqual(mm[3],q.mm[3],eps) ; - } // trivial - - /// Add quaternion q to "this" quaternion, e.g. q += q1; - Quat& operator+=(const Quat &q) - { - mm[0] += q.mm[0]; - mm[1] += q.mm[1]; - mm[2] += q.mm[2]; - mm[3] += q.mm[3]; - - return *this; - } - - /// Subtract quaternion q from "this" quaternion, e.g. q -= q1; - Quat& operator-=(const Quat &q) - { - mm[0] -= q.mm[0]; - mm[1] -= q.mm[1]; - mm[2] -= q.mm[2]; - mm[3] -= q.mm[3]; - - return *this; - } - - /// Scale "this" quaternion by scalar, e.g. q *= scalar; - Quat& operator*=(T scalar) - { - mm[0] *= scalar; - mm[1] *= scalar; - mm[2] *= scalar; - mm[3] *= scalar; - - return *this; - } - - /// Return (this+q), e.g. q = q1 + q2; - Quat operator+(const Quat &q) const - { - return Quat(mm[0]+q.mm[0], mm[1]+q.mm[1], mm[2]+q.mm[2], mm[3]+q.mm[3]); - } - - /// Return (this-q), e.g. q = q1 - q2; - Quat operator-(const Quat &q) const - { - return Quat(mm[0]-q.mm[0], mm[1]-q.mm[1], mm[2]-q.mm[2], mm[3]-q.mm[3]); - } - - /// Return (this*q), e.g. q = q1 * q2; - Quat operator*(const Quat &q) const - { - Quat prod; - - prod.mm[0] = mm[3]*q.mm[0] + mm[0]*q.mm[3] + mm[1]*q.mm[2] - mm[2]*q.mm[1]; - prod.mm[1] = mm[3]*q.mm[1] + mm[1]*q.mm[3] + mm[2]*q.mm[0] - mm[0]*q.mm[2]; - prod.mm[2] = mm[3]*q.mm[2] + mm[2]*q.mm[3] + mm[0]*q.mm[1] - mm[1]*q.mm[0]; - prod.mm[3] = mm[3]*q.mm[3] - mm[0]*q.mm[0] - mm[1]*q.mm[1] - mm[2]*q.mm[2]; - - return prod; - - } - - /// Assigns this to (this*q), e.g. q *= q1; - Quat operator*=(const Quat &q) - { - *this = *this * q; - return *this; - } - - /// Return (this*scalar), e.g. q = q1 * scalar; - Quat operator*(T scalar) const - { - return Quat(mm[0]*scalar, mm[1]*scalar, mm[2]*scalar, mm[3]*scalar); - } - - /// Return (this/scalar), e.g. q = q1 / scalar; - Quat operator/(T scalar) const - { - return Quat(mm[0]/scalar, mm[1]/scalar, mm[2]/scalar, mm[3]/scalar); - } - - /// Negation operator, e.g. q = -q; - Quat operator-() const - { return Quat(-mm[0], -mm[1], -mm[2], -mm[3]); } - - /// this = q1 + q2 - /// "this", q1 and q2 need not be distinct objects, e.g. q.add(q1,q); - Quat& add(const Quat &q1, const Quat &q2) - { - mm[0] = q1.mm[0] + q2.mm[0]; - mm[1] = q1.mm[1] + q2.mm[1]; - mm[2] = q1.mm[2] + q2.mm[2]; - mm[3] = q1.mm[3] + q2.mm[3]; - - return *this; - } - - /// this = q1 - q2 - /// "this", q1 and q2 need not be distinct objects, e.g. q.sub(q1,q); - Quat& sub(const Quat &q1, const Quat &q2) - { - mm[0] = q1.mm[0] - q2.mm[0]; - mm[1] = q1.mm[1] - q2.mm[1]; - mm[2] = q1.mm[2] - q2.mm[2]; - mm[3] = q1.mm[3] - q2.mm[3]; - - return *this; - } - - /// this = q1 * q2 - /// q1 and q2 must be distinct objects than "this", e.g. q.mult(q1,q2); - Quat& mult(const Quat &q1, const Quat &q2) - { - mm[0] = q1.mm[3]*q2.mm[0] + q1.mm[0]*q2.mm[3] + - q1.mm[1]*q2.mm[2] - q1.mm[2]*q2.mm[1]; - mm[1] = q1.mm[3]*q2.mm[1] + q1.mm[1]*q2.mm[3] + - q1.mm[2]*q2.mm[0] - q1.mm[0]*q2.mm[2]; - mm[2] = q1.mm[3]*q2.mm[2] + q1.mm[2]*q2.mm[3] + - q1.mm[0]*q2.mm[1] - q1.mm[1]*q2.mm[0]; - mm[3] = q1.mm[3]*q2.mm[3] - q1.mm[0]*q2.mm[0] - - q1.mm[1]*q2.mm[1] - q1.mm[2]*q2.mm[2]; - - return *this; - } - - /// this = scalar*q, q need not be distinct object than "this", - /// e.g. q.scale(1.5,q1); - Quat& scale(T scale, const Quat &q) - { - mm[0] = scale * q.mm[0]; - mm[1] = scale * q.mm[1]; - mm[2] = scale * q.mm[2]; - mm[3] = scale * q.mm[3]; - - return *this; - } - - /// Dot product - T dot(const Quat &q) const - { - return (mm[0]*q.mm[0] + mm[1]*q.mm[1] + mm[2]*q.mm[2] + mm[3]*q.mm[3]); - } - - /// Return the quaternion rate corrsponding to the angular velocity omega - /// and "this" current rotation - Quat derivative(const Vec3& omega) const - { - return Quat( +w()*omega.x() -z()*omega.y() +y()*omega.z() , - +z()*omega.x() +w()*omega.y() -x()*omega.z() , - -y()*omega.x() +x()*omega.y() +w()*omega.z() , - -x()*omega.x() -y()*omega.y() -z()*omega.z() ); - } - - /// this = normalized this - bool normalize(T eps = T(1.0e-8)) - { - T d = T(sqrt(mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3])); - if( isApproxEqual(d, T(0.0), eps) ) return false; - *this *= ( T(1)/d ); - return true; - } - - /// this = normalized this - Quat unit() const - { - T d = sqrt(mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3]); - if( isExactlyEqual(d , T(0.0) ) ) - OPENVDB_THROW(ArithmeticError, - "Normalizing degenerate quaternion"); - return *this / d; - } - - /// returns inverse of this - Quat inverse(T tolerance = T(0)) - { - T d = mm[0]*mm[0] + mm[1]*mm[1] + mm[2]*mm[2] + mm[3]*mm[3]; - if( isApproxEqual(d, T(0.0), tolerance) ) - OPENVDB_THROW(ArithmeticError, - "Cannot invert degenerate quaternion"); - Quat result = *this/-d; - result.mm[3] = -result.mm[3]; - return result; - } - - - /// Return the conjugate of "this", same as invert without - /// unit quaternion test - Quat conjugate() const - { - return Quat(-mm[0], -mm[1], -mm[2], mm[3]); - } - - /// Return rotated vector by "this" quaternion - Vec3 rotateVector(const Vec3 &v) const - { - Mat3 m(*this); - return m.transform(v); - } - - /// Predefined constants, e.g. Quat q = Quat::identity(); - static Quat zero() { return Quat(0,0,0,0); } - static Quat identity() { return Quat(0,0,0,1); } - - /// @return string representation of Classname - std::string - str() const { - std::ostringstream buffer; - - buffer << "["; - - // For each column - for (unsigned j(0); j < 4; j++) { - if (j) buffer << ", "; - buffer << mm[j]; - } - - buffer << "]"; - - return buffer.str(); - } - - /// Output to the stream, e.g. std::cout << q << std::endl; - friend std::ostream& operator<<(std::ostream &stream, const Quat &q) - { - stream << q.str(); - return stream; - } - - friend Quat slerp<>(const Quat &q1, const Quat &q2, T t, T tolerance); - - - void write(std::ostream& os) const { - os.write((char*)&mm, sizeof(T)*4); - } - void read(std::istream& is) { - is.read((char*)&mm, sizeof(T)*4); - } - -protected: - T mm[4]; -}; - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 3]\f$ -template -Quat operator*(S scalar, const Quat &q) { return q*scalar; } - - -/// @brief Interpolate between m1 and m2. -/// Converts to quaternion form and uses slerp -/// m1 and m2 must be rotation matrices! -template -Mat3 slerp(const Mat3 &m1, const Mat3 &m2, T t) -{ - typedef Mat3 MatType; - - Quat q1(m1); - Quat q2(m2); - - if (q1.dot(q2) < 0) q2 *= -1; - - Quat qslerp = slerp(q1, q2, static_cast(t)); - MatType m = rotation(qslerp); - return m; -} - - - -/// Interpolate between m1 and m4 by converting m1 ... m4 into -/// quaternions and treating them as control points of a Bezier -/// curve using slerp in place of lerp in the De Castlejeau evaluation -/// algorithm. Just like a cubic Bezier curve, this will interpolate -/// m1 at t = 0 and m4 at t = 1 but in general will not pass through -/// m2 and m3. Unlike a standard Bezier curve this curve will not have -/// the convex hull property. -/// m1 ... m4 must be rotation matrices! -template -Mat3 bezLerp(const Mat3 &m1, const Mat3 &m2, - const Mat3 &m3, const Mat3 &m4, - T t) -{ - Mat3 m00, m01, m02, m10, m11; - - m00 = slerp(m1, m2, t); - m01 = slerp(m2, m3, t); - m02 = slerp(m3, m4, t); - - m10 = slerp(m00, m01, t); - m11 = slerp(m01, m02, t); - - return slerp(m10, m11, t); -} - -typedef Quat Quats; -typedef Quat Quatd; - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif //OPENVDB_MATH_QUAT_H_HAS_BEEN_INCLUDED - -// --------------------------------------------------------------------------- -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Ray.h b/openvdb_3_0_0_library/math/Ray.h deleted file mode 100755 index 35eb121..0000000 --- a/openvdb_3_0_0_library/math/Ray.h +++ /dev/null @@ -1,342 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Ray.h -/// -/// @author Ken Museth -/// -/// @brief A Ray class. - -#ifndef OPENVDB_MATH_RAY_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_RAY_HAS_BEEN_INCLUDED - -#include "Math.h" -#include "Vec3.h" -#include "Transform.h" -#include // for std::ostream -#include -#include // for std::numeric_limits::max() - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template -class Ray -{ -public: - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - typedef RealT RealType; - typedef Vec3 Vec3Type; - typedef Vec3Type Vec3T; - struct TimeSpan { - RealT t0, t1; - /// @brief Default constructor - TimeSpan() {} - /// @brief Constructor - TimeSpan(RealT _t0, RealT _t1) : t0(_t0), t1(_t1) {} - /// @brief Set both times - inline void set(RealT _t0, RealT _t1) { t0=_t0; t1=_t1; } - /// @brief Get both times - inline void get(RealT& _t0, RealT& _t1) const { _t0=t0; _t1=t1; } - /// @brief Return @c true if t1 is larger then t0 by at least eps. - inline bool valid(RealT eps=math::Delta::value()) const { return (t1-t0)>eps; } - /// @brief Return the midpoint of the ray. - inline RealT mid() const { return 0.5*(t0 + t1); } - /// @brief Multiplies both times - inline void scale(RealT s) {assert(s>0); t0*=s; t1*=s; } - /// @brief Return @c true if time is inclusive - inline bool test(RealT t) const { return (t>=t0 && t<=t1); } - }; - - Ray(const Vec3Type& eye = Vec3Type(0,0,0), - const Vec3Type& direction = Vec3Type(1,0,0), - RealT t0 = math::Delta::value(), - RealT t1 = std::numeric_limits::max()) - : mEye(eye), mDir(direction), mInvDir(1/mDir), mTimeSpan(t0, t1) - { - } - - inline void setEye(const Vec3Type& eye) { mEye = eye; } - - inline void setDir(const Vec3Type& dir) - { - mDir = dir; - mInvDir = 1/mDir; - } - - inline void setMinTime(RealT t0) { assert(t0>0); mTimeSpan.t0 = t0; } - - inline void setMaxTime(RealT t1) { assert(t1>0); mTimeSpan.t1 = t1; } - - inline void setTimes(RealT t0 = math::Delta::value(), - RealT t1 = std::numeric_limits::max()) - { - assert(t0>0 && t1>0); - mTimeSpan.set(t0, t1); - } - - inline void scaleTimes(RealT scale) { mTimeSpan.scale(scale); } - - inline void reset(const Vec3Type& eye, - const Vec3Type& direction, - RealT t0 = math::Delta::value(), - RealT t1 = std::numeric_limits::max()) - { - this->setEye(eye); - this->setDir(direction); - this->setTimes(t0, t1); - } - - inline const Vec3T& eye() const {return mEye;} - - inline const Vec3T& dir() const {return mDir;} - - inline const Vec3T& invDir() const {return mInvDir;} - - inline RealT t0() const {return mTimeSpan.t0;} - - inline RealT t1() const {return mTimeSpan.t1;} - - /// @brief Return the position along the ray at the specified time. - inline Vec3R operator()(RealT time) const { return mEye + mDir * time; } - - /// @brief Return the starting point of the ray. - inline Vec3R start() const { return (*this)(mTimeSpan.t0); } - - /// @brief Return the endpoint of the ray. - inline Vec3R end() const { return (*this)(mTimeSpan.t1); } - - /// @brief Return the midpoint of the ray. - inline Vec3R mid() const { return (*this)(mTimeSpan.mid()); } - - /// @brief Return @c true if t0 is strictly less then t1. - OPENVDB_DEPRECATED inline bool test() const { return mTimeSpan.valid(RealT(0)); } - - /// @brief Return @c true if t1 is larger then t0 by at least eps. - inline bool valid(RealT eps=math::Delta::value()) const - { - return mTimeSpan.valid(eps); - } - - /// @brief Return @c true if @a time is within t0 and t1, both inclusive. - inline bool test(RealT time) const { return mTimeSpan.test(time); } - - /// @brief Return a new Ray that is transformed with the specified map. - /// @param map the map from which to construct the new Ray. - /// @warning Assumes a linear map and a normalize direction. - /// @details The requirement that the direction is normalized - /// follows from the transformation of t0 and t1 - and that fact that - /// we want applyMap and applyInverseMap to be inverse operations. - template - inline Ray applyMap(const MapType& map) const - { - assert(map.isLinear()); - assert(math::isApproxEqual(mDir.length(), RealT(1))); - const Vec3T eye = map.applyMap(mEye); - const Vec3T dir = map.applyJacobian(mDir); - const RealT length = dir.length(); - return Ray(eye, dir/length, length*mTimeSpan.t0, length*mTimeSpan.t1); - } - - /// @brief Return a new Ray that is transformed with the inverse of the specified map. - /// @param map the map from which to construct the new Ray by inverse mapping. - /// @warning Assumes a linear map and a normalize direction. - /// @details The requirement that the direction is normalized - /// follows from the transformation of t0 and t1 - and that fact that - /// we want applyMap and applyInverseMap to be inverse operations. - template - inline Ray applyInverseMap(const MapType& map) const - { - assert(map.isLinear()); - assert(math::isApproxEqual(mDir.length(), RealT(1))); - const Vec3T eye = map.applyInverseMap(mEye); - const Vec3T dir = map.applyInverseJacobian(mDir); - const RealT length = dir.length(); - return Ray(eye, dir/length, length*mTimeSpan.t0, length*mTimeSpan.t1); - } - - /// @brief Return a new ray in world space, assuming the existing - /// ray is represented in the index space of the specified grid. - template - inline Ray indexToWorld(const GridType& grid) const - { - return this->applyMap(*(grid.transform().baseMap())); - } - - /// @brief Return a new ray in the index space of the specified - /// grid, assuming the existing ray is represented in world space. - template - inline Ray worldToIndex(const GridType& grid) const - { - return this->applyInverseMap(*(grid.transform().baseMap())); - } - - /// @brief Return true if this ray intersects the specified sphere. - /// @param center The center of the sphere in the same space as this ray. - /// @param radius The radius of the sphere in the same units as this ray. - /// @param t0 The first intersection point if an intersection exists. - /// @param t1 The second intersection point if an intersection exists. - /// @note If the return value is true, i.e. a hit, and t0 = - /// this->t0() or t1 == this->t1() only one true intersection exist. - inline bool intersects(const Vec3T& center, RealT radius, RealT& t0, RealT& t1) const - { - const Vec3T origin = mEye - center; - const RealT A = mDir.lengthSqr(); - const RealT B = 2 * mDir.dot(origin); - const RealT C = origin.lengthSqr() - radius * radius; - const RealT D = B * B - 4 * A * C; - - if (D < 0) return false; - - const RealT Q = RealT(-0.5)*(B<0 ? (B + Sqrt(D)) : (B - Sqrt(D))); - - t0 = Q / A; - t1 = C / Q; - - if (t0 > t1) std::swap(t0, t1); - if (t0 < mTimeSpan.t0) t0 = mTimeSpan.t0; - if (t1 > mTimeSpan.t1) t1 = mTimeSpan.t1; - return t0 <= t1; - } - - /// @brief Return true if this ray intersects the specified sphere. - /// @param center The center of the sphere in the same space as this ray. - /// @param radius The radius of the sphere in the same units as this ray. - inline bool intersects(const Vec3T& center, RealT radius) const - { - RealT t0, t1; - return this->intersects(center, radius, t0, t1)>0; - } - - /// @brief Return true if this ray intersects the specified sphere. - /// @note For intersection this ray is clipped to the two intersection points. - /// @param center The center of the sphere in the same space as this ray. - /// @param radius The radius of the sphere in the same units as this ray. - inline bool clip(const Vec3T& center, RealT radius) - { - RealT t0, t1; - const bool hit = this->intersects(center, radius, t0, t1); - if (hit) mTimeSpan.set(t0, t1); - return hit; - } - - /// @brief Return true if the Ray intersects the specified - /// axisaligned bounding box. - /// @param bbox Axis-aligned bounding box in the same space as the Ray. - /// @param t0 If an intersection is detected this is assigned - /// the time for the first intersection point. - /// @param t1 If an intersection is detected this is assigned - /// the time for the second intersection point. - template - inline bool intersects(const BBoxT& bbox, RealT& t0, RealT& t1) const - { - mTimeSpan.get(t0, t1); - for (size_t i = 0; i < 3; ++i) { - RealT a = (bbox.min()[i] - mEye[i]) * mInvDir[i]; - RealT b = (bbox.max()[i] - mEye[i]) * mInvDir[i]; - if (a > b) std::swap(a, b); - if (a > t0) t0 = a; - if (b < t1) t1 = b; - if (t0 > t1) return false; - } - return true; - } - - /// @brief Return true if this ray intersects the specified bounding box. - /// @param bbox Axis-aligned bounding box in the same space as this ray. - template - inline bool intersects(const BBoxT& bbox) const - { - RealT t0, t1; - return this->intersects(bbox, t0, t1); - } - - /// @brief Return true if this ray intersects the specified bounding box. - /// @note For intersection this ray is clipped to the two intersection points. - /// @param bbox Axis-aligned bounding box in the same space as this ray. - template - inline bool clip(const BBoxT& bbox) - { - RealT t0, t1; - const bool hit = this->intersects(bbox, t0, t1); - if (hit) mTimeSpan.set(t0, t1); - return hit; - } - - /// @brief Return true if the Ray intersects the plane specified - /// by a normal and distance from the origin. - /// @param normal Normal of the plane. - /// @param distance Distance of the plane to the origin. - /// @param t Time of intersection, if one exists. - inline bool intersects(const Vec3T& normal, RealT distance, RealT& t) const - { - const RealT cosAngle = mDir.dot(normal); - if (math::isApproxZero(cosAngle)) return false;//parallel - t = (distance - mEye.dot(normal))/cosAngle; - return this->test(t); - } - - /// @brief Return true if the Ray intersects the plane specified - /// by a normal and point. - /// @param normal Normal of the plane. - /// @param point Point in the plane. - /// @param t Time of intersection, if one exists. - inline bool intersects(const Vec3T& normal, const Vec3T& point, RealT& t) const - { - return this->intersects(normal, point.dot(normal), t); - } - -private: - Vec3T mEye, mDir, mInvDir; - TimeSpan mTimeSpan; -}; // end of Ray class - -/// @brief Output streaming of the Ray class. -/// @note Primarily intended for debugging. -template -inline std::ostream& operator<<(std::ostream& os, const Ray& r) -{ - os << "eye=" << r.eye() << " dir=" << r.dir() << " 1/dir="< // for ostringstream -#include -#include -#include -#include -#include -#include "Math.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @brief This class computes the minimum and maximum values of a population -/// of floating-point values. -class Extrema -{ -public: - - /// @brief Constructor - /// @warning The min/max values are initiated to extreme values - Extrema() - : mSize(0) - , mMin(std::numeric_limits::max()) - , mMax(-mMin) - { - } - - /// Add a single sample. - void add(double val) - { - ++mSize; - mMin = std::min(val, mMin); - mMax = std::max(val, mMax); - } - - /// Add @a n samples with constant value @a val. - void add(double val, uint64_t n) - { - mSize += n; - mMin = std::min(val, mMin); - mMax = std::max(val, mMax); - } - - /// Return the size of the population, i.e., the total number of samples. - inline uint64_t size() const { return mSize; } - - /// Return the minimum value. - inline double min() const { return mMin; } - - /// Return the maximum value. - inline double max() const { return mMax; } - - /// Add the samples from the other Stats instance. - void add(const Extrema& other) - { - if (other.mSize > 0) this->join(other); - } - - /// @brief Print extrema to the specified output stream. - void print(const std::string &name= "", std::ostream &strm=std::cout, int precision=3) const - { - // Write to a temporary string stream so as not to affect the state - // (precision, field width, etc.) of the output stream. - std::ostringstream os; - os << std::setprecision(precision) << std::setiosflags(std::ios::fixed); - os << "Extrema "; - if (!name.empty()) os << "for \"" << name << "\" "; - if (mSize>0) { - os << "with " << mSize << " samples:\n" - << " Min=" << mMin - << ", Max=" << mMax << std::endl; - } else { - os << ": no samples were added." << std::endl; - } - strm << os.str(); - } - -protected: - - inline void join(const Extrema& other) - { - assert(other.mSize > 0); - mSize += other.mSize; - mMin = std::min(mMin, other.mMin); - mMax = std::max(mMax, other.mMax); - } - - uint64_t mSize; - double mMin, mMax; -};//end Extrema - - -/// @brief This class computes statistics (minimum value, maximum -/// value, mean, variance and standard deviation) of a population -/// of floating-point values. -/// -/// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2, -/// standard deviation = sqrt(variance) -/// -/// @note This class employs incremental computation and double precision. -class Stats : public Extrema -{ -public: - Stats() - : Extrema() - , mAvg(0.0) - , mAux(0.0) - { - } - - /// Add a single sample. - void add(double val) - { - Extrema::add(val); - const double delta = val - mAvg; - mAvg += delta/double(mSize); - mAux += delta*(val - mAvg); - } - - /// Add @a n samples with constant value @a val. - void add(double val, uint64_t n) - { - const double denom = 1.0/double(mSize + n); - const double delta = val - mAvg; - mAvg += denom * delta * double(n); - mAux += denom * delta * delta * double(mSize) * double(n); - Extrema::add(val, n); - } - - /// Add the samples from the other Stats instance. - void add(const Stats& other) - { - if (other.mSize > 0) { - const double denom = 1.0/double(mSize + other.mSize); - const double delta = other.mAvg - mAvg; - mAvg += denom * delta * double(other.mSize); - mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize); - Extrema::join(other); - } - } - - //@{ - /// Return the arithmetic mean, i.e. average, value. - inline double avg() const { return mAvg; } - inline double mean() const { return mAvg; } - //@} - - //@{ - /// @brief Return the population variance. - /// @note The unbiased sample variance = population variance * - //num/(num-1) - inline double var() const { return mSize<2 ? 0.0 : mAux/double(mSize); } - inline double variance() const { return this->var(); } - //@} - - //@{ - /// @brief Return the standard deviation (=Sqrt(variance)) as - /// defined from the (biased) population variance. - inline double std() const { return sqrt(this->var()); } - inline double stdDev() const { return this->std(); } - //@} - - /// @brief Print statistics to the specified output stream. - void print(const std::string &name= "", std::ostream &strm=std::cout, int precision=3) const - { - // Write to a temporary string stream so as not to affect the state - // (precision, field width, etc.) of the output stream. - std::ostringstream os; - os << std::setprecision(precision) << std::setiosflags(std::ios::fixed); - os << "Statistics "; - if (!name.empty()) os << "for \"" << name << "\" "; - if (mSize>0) { - os << "with " << mSize << " samples:\n" - << " Min=" << mMin - << ", Max=" << mMax - << ", Ave=" << mAvg - << ", Std=" << this->stdDev() - << ", Var=" << this->variance() << std::endl; - } else { - os << ": no samples were added." << std::endl; - } - strm << os.str(); - } - -protected: - using Extrema::mSize; - using Extrema::mMin; - using Extrema::mMax; - double mAvg, mAux; -}; // end Stats - - -//////////////////////////////////////// - - -/// @brief This class computes a histogram, with a fixed interval width, -/// of a population of floating-point values. -class Histogram -{ -public: - /// Construct with given minimum and maximum values and the given bin count. - Histogram(double min, double max, size_t numBins = 10) - : mSize(0), mMin(min), mMax(max+1e-10), - mDelta(double(numBins)/(max-min)), mBins(numBins) - { - assert(numBins > 1); - assert(mMax-mMin > 1e-10); - for (size_t i=0; i 1); - assert(mMax-mMin > 1e-10); - for (size_t i=0; imMax) return false; - mBins[size_t(mDelta*(val-mMin))] += n; - mSize += n; - return true; - } - - /// @brief Add all the contributions from the other histogram, provided that - /// it has the same configuration as this histogram. - bool add(const Histogram& other) - { - if (!isApproxEqual(mMin, other.mMin) || !isApproxEqual(mMax, other.mMax) || - mBins.size() != other.mBins.size()) return false; - for (size_t i=0, e=mBins.size(); i!=e; ++i) mBins[i] += other.mBins[i]; - mSize += other.mSize; - return true; - } - - /// Return the number of bins in this histogram. - inline size_t numBins() const { return mBins.size(); } - /// Return the lower bound of this histogram's value range. - inline double min() const { return mMin; } - /// Return the upper bound of this histogram's value range. - inline double max() const { return mMax; } - /// Return the minimum value in the nth bin. - inline double min(int n) const { return mMin+n/mDelta; } - /// Return the maximum value in the nth bin. - inline double max(int n) const { return mMin+(n+1)/mDelta; } - /// Return the number of samples in the nth bin. - inline uint64_t count(int n) const { return mBins[n]; } - /// Return the population size, i.e., the total number of samples. - inline uint64_t size() const { return mSize; } - - /// Print the histogram to the specified output stream. - void print(const std::string& name = "", std::ostream& strm = std::cout) const - { - // Write to a temporary string stream so as not to affect the state - // (precision, field width, etc.) of the output stream. - std::ostringstream os; - os << std::setprecision(6) << std::setiosflags(std::ios::fixed) << std::endl; - os << "Histogram "; - if (!name.empty()) os << "for \"" << name << "\" "; - if (mSize > 0) { - os << "with " << mSize << " samples:\n"; - os << "==============================================================\n"; - os << "|| # | Min | Max | Frequency | % ||\n"; - os << "==============================================================\n"; - for (int i = 0, e = int(mBins.size()); i != e; ++i) { - os << "|| " << std::setw(4) << i << " | " << std::setw(14) << this->min(i) << " | " - << std::setw(14) << this->max(i) << " | " << std::setw(9) << mBins[i] << " | " - << std::setw(3) << (100*mBins[i]/mSize) << " ||\n"; - } - os << "==============================================================\n"; - } else { - os << ": no samples were added." << std::endl; - } - strm << os.str(); - } - -private: - uint64_t mSize; - double mMin, mMax, mDelta; - std::vector mBins; -}; - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_STATS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Stencils.h b/openvdb_3_0_0_library/math/Stencils.h deleted file mode 100755 index e21f5ae..0000000 --- a/openvdb_3_0_0_library/math/Stencils.h +++ /dev/null @@ -1,1650 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// @file Stencils.h - -#ifndef OPENVDB_MATH_STENCILS_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_STENCILS_HAS_BEEN_INCLUDED - -#include -#include -#include // for Pow2, needed by WENO and Gudonov -#include // for Real -#include // for Coord -#include // for WENO5 and GudonovsNormSqrd - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - - -template -class BaseStencil -{ -public: - typedef _GridType GridType; - typedef typename GridType::TreeType TreeType; - typedef typename GridType::ValueType ValueType; - typedef std::vector BufferType; - typedef typename BufferType::iterator IterType; - typedef typename GridType::ConstAccessor AccessorType; - - /// @brief Initialize the stencil buffer with the values of voxel (i, j, k) - /// and its neighbors. - /// @param ijk Index coordinates of stencil center - inline void moveTo(const Coord& ijk) - { - mCenter = ijk; - mStencil[0] = mCache.getValue(ijk); - static_cast(*this).init(mCenter); - } - - /// @brief Initialize the stencil buffer with the values of voxel (i, j, k) - /// and its neighbors. The method also takes a value of the center - /// element of the stencil, assuming it is already known. - /// @param ijk Index coordinates of stnecil center - /// @param centerValue Value of the center element of the stencil - inline void moveTo(const Coord& ijk, const ValueType& centerValue) - { - mCenter = ijk; - mStencil[0] = centerValue; - static_cast(*this).init(mCenter); - } - - /// @brief Initialize the stencil buffer with the values of voxel - /// (x, y, z) and its neighbors. - /// - /// @note This version is slightly faster than the one above, since - /// the center voxel's value is read directly from the iterator. - template - inline void moveTo(const IterType& iter) - { - mCenter = iter.getCoord(); - mStencil[0] = *iter; - static_cast(*this).init(mCenter); - } - - /// @brief Initialize the stencil buffer with the values of voxel (x, y, z) - /// and its neighbors. - /// @param xyz Floating point voxel coordinates of stencil center - /// @details This method will check to see if it is necessary to - /// update the stencil based on the cached index coordinates of - /// the center point. - inline void moveTo(const Vec3R& xyz) - { - Coord ijk = openvdb::Coord::floor(xyz); - if (ijk != mCenter) this->moveTo(ijk); - } - - /// @brief Return the value from the stencil buffer with linear - /// offset pos. - /// - /// @note The default (@a pos = 0) corresponds to the first element - /// which is typically the center point of the stencil. - inline const ValueType& getValue(unsigned int pos = 0) const - { - assert(pos < mStencil.size()); - return mStencil[pos]; - } - - /// @brief Return the value at the specified location relative to the center of the stencil - template - inline const ValueType& getValue() const - { - return mStencil[static_cast(*this).template pos()]; - } - - /// @brief Set the value at the specified location relative to the center of the stencil - template - inline void setValue(const ValueType& value) - { - mStencil[static_cast(*this).template pos()] = value; - } - - /// @brief Return the size of the stencil buffer. - inline int size() { return mStencil.size(); } - - /// @brief Return the median value of the current stencil. - inline ValueType median() const - { - std::vector tmp(mStencil);//local copy - assert(!tmp.empty()); - size_t midpoint = (tmp.size() - 1) >> 1; - // Partially sort the vector until the median value is at the midpoint. - std::nth_element(tmp.begin(), tmp.begin() + midpoint, tmp.end()); - return tmp[midpoint]; - } - - /// @brief Return the mean value of the current stencil. - inline ValueType mean() const - { - ValueType sum = 0.0; - for (int n = 0, s = int(mStencil.size()); n < s; ++n) sum += mStencil[n]; - return sum / mStencil.size(); - } - - /// @brief Return the smallest value in the stencil buffer. - inline ValueType min() const - { - IterType iter = std::min_element(mStencil.begin(), mStencil.end()); - return *iter; - } - - /// @brief Return the largest value in the stencil buffer. - inline ValueType max() const - { - IterType iter = std::max_element(mStencil.begin(), mStencil.end()); - return *iter; - } - - /// @brief Return the coordinates of the center point of the stencil. - inline const Coord& getCenterCoord() const { return mCenter; } - - /// @brief Return the value at the center of the stencil - inline const ValueType& getCenterValue() const { return mStencil[0]; } - - /// @brief Return true if the center of the stencil intersects the - /// iso-contour specified by the isoValue - inline bool intersects(const ValueType &isoValue = zeroVal()) const - { - const bool less = this->getValue< 0, 0, 0>() < isoValue; - return (less ^ (this->getValue<-1, 0, 0>() < isoValue)) || - (less ^ (this->getValue< 1, 0, 0>() < isoValue)) || - (less ^ (this->getValue< 0,-1, 0>() < isoValue)) || - (less ^ (this->getValue< 0, 1, 0>() < isoValue)) || - (less ^ (this->getValue< 0, 0,-1>() < isoValue)) || - (less ^ (this->getValue< 0, 0, 1>() < isoValue)) ; - } - - /// @brief Return a const reference to the grid from which this - /// stencil was constructed. - inline const GridType& grid() const { return *mGrid; } - - /// @brief Return a const reference to the ValueAccessor - /// associated with this Stencil. - inline const AccessorType& accessor() const { return mCache; } - -protected: - // Constructor is protected to prevent direct instantiation. - BaseStencil(const GridType& grid, int size): - mGrid(&grid), mCache(grid.getConstAccessor()), - mStencil(size), mCenter(Coord::max()) - { - } - - const GridType* mGrid; - AccessorType mCache; - BufferType mStencil; - Coord mCenter; - -}; // class BaseStencil - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the seven point stencil - template struct SevenPt {}; - template<> struct SevenPt< 0, 0, 0> { enum { idx = 0 }; }; - template<> struct SevenPt< 1, 0, 0> { enum { idx = 1 }; }; - template<> struct SevenPt< 0, 1, 0> { enum { idx = 2 }; }; - template<> struct SevenPt< 0, 0, 1> { enum { idx = 3 }; }; - template<> struct SevenPt<-1, 0, 0> { enum { idx = 4 }; }; - template<> struct SevenPt< 0,-1, 0> { enum { idx = 5 }; }; - template<> struct SevenPt< 0, 0,-1> { enum { idx = 6 }; }; - -} - - -template -class SevenPointStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - static const int SIZE = 7; - - SevenPointStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return SevenPt::idx; } - -private: - inline void init(const Coord& ijk) - { - BaseType::template setValue<-1, 0, 0>(mCache.getValue(ijk.offsetBy(-1, 0, 0))); - BaseType::template setValue< 1, 0, 0>(mCache.getValue(ijk.offsetBy( 1, 0, 0))); - - BaseType::template setValue< 0,-1, 0>(mCache.getValue(ijk.offsetBy( 0,-1, 0))); - BaseType::template setValue< 0, 1, 0>(mCache.getValue(ijk.offsetBy( 0, 1, 0))); - - BaseType::template setValue< 0, 0,-1>(mCache.getValue(ijk.offsetBy( 0, 0,-1))); - BaseType::template setValue< 0, 0, 1>(mCache.getValue(ijk.offsetBy( 0, 0, 1))); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the eight point box stencil - template struct BoxPt {}; - template<> struct BoxPt< 0, 0, 0> { enum { idx = 0 }; }; - template<> struct BoxPt< 0, 0, 1> { enum { idx = 1 }; }; - template<> struct BoxPt< 0, 1, 1> { enum { idx = 2 }; }; - template<> struct BoxPt< 0, 1, 0> { enum { idx = 3 }; }; - template<> struct BoxPt< 1, 0, 0> { enum { idx = 4 }; }; - template<> struct BoxPt< 1, 0, 1> { enum { idx = 5 }; }; - template<> struct BoxPt< 1, 1, 1> { enum { idx = 6 }; }; - template<> struct BoxPt< 1, 1, 0> { enum { idx = 7 }; }; -} - -template -class BoxStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - static const int SIZE = 8; - - BoxStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return BoxPt::idx; } - - /// @brief Return true if the center of the stencil intersects the - /// iso-contour specified by the isoValue - inline bool intersects(const ValueType &isoValue = zeroVal()) const - { - const bool less = mStencil[0] < isoValue; - return (less ^ (mStencil[1] < isoValue)) || - (less ^ (mStencil[2] < isoValue)) || - (less ^ (mStencil[3] < isoValue)) || - (less ^ (mStencil[4] < isoValue)) || - (less ^ (mStencil[5] < isoValue)) || - (less ^ (mStencil[6] < isoValue)) || - (less ^ (mStencil[7] < isoValue)) ; - } - - /// @brief Return the trilinear interpolation at the normalized position. - /// @param xyz Floating point coordinate position. - /// @warning It is assumed that the stencil has already been moved - /// to the relevant voxel position, e.g. using moveTo(xyz). - /// @note Trilinear interpolation kernal reads as: - /// v000 (1-u)(1-v)(1-w) + v001 (1-u)(1-v)w + v010 (1-u)v(1-w) + v011 (1-u)vw - /// + v100 u(1-v)(1-w) + v101 u(1-v)w + v110 uv(1-w) + v111 uvw - inline ValueType interpolation(const Vec3Type& xyz) const - { - const Real u = xyz[0] - BaseType::mCenter[0]; assert(u>=0 && u<=1); - const Real v = xyz[1] - BaseType::mCenter[1]; assert(v>=0 && v<=1); - const Real w = xyz[2] - BaseType::mCenter[2]; assert(w>=0 && w<=1); - - ValueType V = BaseType::template getValue<0,0,0>(); - ValueType A = static_cast(V + (BaseType::template getValue<0,0,1>() - V) * w); - V = BaseType::template getValue< 0, 1, 0>(); - ValueType B = static_cast(V + (BaseType::template getValue<0,1,1>() - V) * w); - ValueType C = static_cast(A + (B - A) * v); - - V = BaseType::template getValue<1,0,0>(); - A = static_cast(V + (BaseType::template getValue<1,0,1>() - V) * w); - V = BaseType::template getValue<1,1,0>(); - B = static_cast(V + (BaseType::template getValue<1,1,1>() - V) * w); - ValueType D = static_cast(A + (B - A) * v); - - return static_cast(C + (D - C) * u); - } - - /// @brief Return the gradient in world space of the trilinear interpolation kernel. - /// @param xyz Floating point coordinate position. - /// @warning It is assumed that the stencil has already been moved - /// to the relevant voxel position, e.g. using moveTo(xyz). - /// @note Computed as partial derivatives of the trilinear interpolation kernel: - /// v000 (1-u)(1-v)(1-w) + v001 (1-u)(1-v)w + v010 (1-u)v(1-w) + v011 (1-u)vw - /// + v100 u(1-v)(1-w) + v101 u(1-v)w + v110 uv(1-w) + v111 uvw - inline Vec3Type gradient(const Vec3Type& xyz) const - { - const Real u = xyz[0] - BaseType::mCenter[0]; assert(u>=0 && u<=1); - const Real v = xyz[1] - BaseType::mCenter[1]; assert(v>=0 && v<=1); - const Real w = xyz[2] - BaseType::mCenter[2]; assert(w>=0 && w<=1); - - ValueType D[4]={BaseType::template getValue<0,0,1>()-BaseType::template getValue<0,0,0>(), - BaseType::template getValue<0,1,1>()-BaseType::template getValue<0,1,0>(), - BaseType::template getValue<1,0,1>()-BaseType::template getValue<1,0,0>(), - BaseType::template getValue<1,1,1>()-BaseType::template getValue<1,1,0>()}; - - // Z component - ValueType A = static_cast(D[0] + (D[1]- D[0]) * v); - ValueType B = static_cast(D[2] + (D[3]- D[2]) * v); - Vec3Type grad( - zeroVal(), zeroVal(), static_cast(A + (B - A) * u)); - - D[0] = static_cast(BaseType::template getValue<0,0,0>() + D[0] * w); - D[1] = static_cast(BaseType::template getValue<0,1,0>() + D[1] * w); - D[2] = static_cast(BaseType::template getValue<1,0,0>() + D[2] * w); - D[3] = static_cast(BaseType::template getValue<1,1,0>() + D[3] * w); - - // X component - A = static_cast(D[0] + (D[1] - D[0]) * v); - B = static_cast(D[2] + (D[3] - D[2]) * v); - - grad[0] = B - A; - - // Y component - A = D[1] - D[0]; - B = D[3] - D[2]; - - grad[1] = static_cast(A + (B - A) * u); - - return BaseType::mGrid->transform().baseMap()->applyIJT(grad, xyz); - } - -private: - inline void init(const Coord& ijk) - { - BaseType::template setValue< 0, 0, 1>(mCache.getValue(ijk.offsetBy( 0, 0, 1))); - BaseType::template setValue< 0, 1, 1>(mCache.getValue(ijk.offsetBy( 0, 1, 1))); - BaseType::template setValue< 0, 1, 0>(mCache.getValue(ijk.offsetBy( 0, 1, 0))); - BaseType::template setValue< 1, 0, 0>(mCache.getValue(ijk.offsetBy( 1, 0, 0))); - BaseType::template setValue< 1, 0, 1>(mCache.getValue(ijk.offsetBy( 1, 0, 1))); - BaseType::template setValue< 1, 1, 1>(mCache.getValue(ijk.offsetBy( 1, 1, 1))); - BaseType::template setValue< 1, 1, 0>(mCache.getValue(ijk.offsetBy( 1, 1, 0))); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the dense point stencil - template struct DensePt {}; - template<> struct DensePt< 0, 0, 0> { enum { idx = 0 }; }; - - template<> struct DensePt< 1, 0, 0> { enum { idx = 1 }; }; - template<> struct DensePt< 0, 1, 0> { enum { idx = 2 }; }; - template<> struct DensePt< 0, 0, 1> { enum { idx = 3 }; }; - - template<> struct DensePt<-1, 0, 0> { enum { idx = 4 }; }; - template<> struct DensePt< 0,-1, 0> { enum { idx = 5 }; }; - template<> struct DensePt< 0, 0,-1> { enum { idx = 6 }; }; - - template<> struct DensePt<-1,-1, 0> { enum { idx = 7 }; }; - template<> struct DensePt< 0,-1,-1> { enum { idx = 8 }; }; - template<> struct DensePt<-1, 0,-1> { enum { idx = 9 }; }; - - template<> struct DensePt< 1,-1, 0> { enum { idx = 10 }; }; - template<> struct DensePt< 0, 1,-1> { enum { idx = 11 }; }; - template<> struct DensePt<-1, 0, 1> { enum { idx = 12 }; }; - - template<> struct DensePt<-1, 1, 0> { enum { idx = 13 }; }; - template<> struct DensePt< 0,-1, 1> { enum { idx = 14 }; }; - template<> struct DensePt< 1, 0,-1> { enum { idx = 15 }; }; - - template<> struct DensePt< 1, 1, 0> { enum { idx = 16 }; }; - template<> struct DensePt< 0, 1, 1> { enum { idx = 17 }; }; - template<> struct DensePt< 1, 0, 1> { enum { idx = 18 }; }; - -} - - -template -class SecondOrderDenseStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 19; - - SecondOrderDenseStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return DensePt::idx; } - -private: - inline void init(const Coord& ijk) - { - mStencil[DensePt< 1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[DensePt< 0, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[DensePt< 0, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - - mStencil[DensePt<-1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[DensePt< 0,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[DensePt< 0, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - - mStencil[DensePt<-1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, -1, 0)); - mStencil[DensePt< 1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, -1, 0)); - mStencil[DensePt<-1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 1, 0)); - mStencil[DensePt< 1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 1, 0)); - - mStencil[DensePt<-1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, -1)); - mStencil[DensePt< 1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, -1)); - mStencil[DensePt<-1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 1)); - mStencil[DensePt< 1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 1)); - - mStencil[DensePt< 0,-1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, -1, -1)); - mStencil[DensePt< 0, 1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, -1)); - mStencil[DensePt< 0,-1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, -1, 1)); - mStencil[DensePt< 0, 1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 1)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the dense point stencil - template struct ThirteenPt {}; - template<> struct ThirteenPt< 0, 0, 0> { enum { idx = 0 }; }; - - template<> struct ThirteenPt< 1, 0, 0> { enum { idx = 1 }; }; - template<> struct ThirteenPt< 0, 1, 0> { enum { idx = 2 }; }; - template<> struct ThirteenPt< 0, 0, 1> { enum { idx = 3 }; }; - - template<> struct ThirteenPt<-1, 0, 0> { enum { idx = 4 }; }; - template<> struct ThirteenPt< 0,-1, 0> { enum { idx = 5 }; }; - template<> struct ThirteenPt< 0, 0,-1> { enum { idx = 6 }; }; - - template<> struct ThirteenPt< 2, 0, 0> { enum { idx = 7 }; }; - template<> struct ThirteenPt< 0, 2, 0> { enum { idx = 8 }; }; - template<> struct ThirteenPt< 0, 0, 2> { enum { idx = 9 }; }; - - template<> struct ThirteenPt<-2, 0, 0> { enum { idx = 10 }; }; - template<> struct ThirteenPt< 0,-2, 0> { enum { idx = 11 }; }; - template<> struct ThirteenPt< 0, 0,-2> { enum { idx = 12 }; }; - -} - - -template -class ThirteenPointStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 13; - - ThirteenPointStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return ThirteenPt::idx; } - -private: - inline void init(const Coord& ijk) - { - mStencil[ThirteenPt< 2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 0)); - mStencil[ThirteenPt< 1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[ThirteenPt<-1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[ThirteenPt<-2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 0)); - - mStencil[ThirteenPt< 0, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 0)); - mStencil[ThirteenPt< 0, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[ThirteenPt< 0,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[ThirteenPt< 0,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -2, 0)); - - mStencil[ThirteenPt< 0, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 2)); - mStencil[ThirteenPt< 0, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - mStencil[ThirteenPt< 0, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - mStencil[ThirteenPt< 0, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -2)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the 4th-order dense point stencil - template struct FourthDensePt {}; - template<> struct FourthDensePt< 0, 0, 0> { enum { idx = 0 }; }; - - template<> struct FourthDensePt<-2, 2, 0> { enum { idx = 1 }; }; - template<> struct FourthDensePt<-1, 2, 0> { enum { idx = 2 }; }; - template<> struct FourthDensePt< 0, 2, 0> { enum { idx = 3 }; }; - template<> struct FourthDensePt< 1, 2, 0> { enum { idx = 4 }; }; - template<> struct FourthDensePt< 2, 2, 0> { enum { idx = 5 }; }; - - template<> struct FourthDensePt<-2, 1, 0> { enum { idx = 6 }; }; - template<> struct FourthDensePt<-1, 1, 0> { enum { idx = 7 }; }; - template<> struct FourthDensePt< 0, 1, 0> { enum { idx = 8 }; }; - template<> struct FourthDensePt< 1, 1, 0> { enum { idx = 9 }; }; - template<> struct FourthDensePt< 2, 1, 0> { enum { idx = 10 }; }; - - template<> struct FourthDensePt<-2, 0, 0> { enum { idx = 11 }; }; - template<> struct FourthDensePt<-1, 0, 0> { enum { idx = 12 }; }; - template<> struct FourthDensePt< 1, 0, 0> { enum { idx = 13 }; }; - template<> struct FourthDensePt< 2, 0, 0> { enum { idx = 14 }; }; - - template<> struct FourthDensePt<-2,-1, 0> { enum { idx = 15 }; }; - template<> struct FourthDensePt<-1,-1, 0> { enum { idx = 16 }; }; - template<> struct FourthDensePt< 0,-1, 0> { enum { idx = 17 }; }; - template<> struct FourthDensePt< 1,-1, 0> { enum { idx = 18 }; }; - template<> struct FourthDensePt< 2,-1, 0> { enum { idx = 19 }; }; - - template<> struct FourthDensePt<-2,-2, 0> { enum { idx = 20 }; }; - template<> struct FourthDensePt<-1,-2, 0> { enum { idx = 21 }; }; - template<> struct FourthDensePt< 0,-2, 0> { enum { idx = 22 }; }; - template<> struct FourthDensePt< 1,-2, 0> { enum { idx = 23 }; }; - template<> struct FourthDensePt< 2,-2, 0> { enum { idx = 24 }; }; - - - template<> struct FourthDensePt<-2, 0, 2> { enum { idx = 25 }; }; - template<> struct FourthDensePt<-1, 0, 2> { enum { idx = 26 }; }; - template<> struct FourthDensePt< 0, 0, 2> { enum { idx = 27 }; }; - template<> struct FourthDensePt< 1, 0, 2> { enum { idx = 28 }; }; - template<> struct FourthDensePt< 2, 0, 2> { enum { idx = 29 }; }; - - template<> struct FourthDensePt<-2, 0, 1> { enum { idx = 30 }; }; - template<> struct FourthDensePt<-1, 0, 1> { enum { idx = 31 }; }; - template<> struct FourthDensePt< 0, 0, 1> { enum { idx = 32 }; }; - template<> struct FourthDensePt< 1, 0, 1> { enum { idx = 33 }; }; - template<> struct FourthDensePt< 2, 0, 1> { enum { idx = 34 }; }; - - template<> struct FourthDensePt<-2, 0,-1> { enum { idx = 35 }; }; - template<> struct FourthDensePt<-1, 0,-1> { enum { idx = 36 }; }; - template<> struct FourthDensePt< 0, 0,-1> { enum { idx = 37 }; }; - template<> struct FourthDensePt< 1, 0,-1> { enum { idx = 38 }; }; - template<> struct FourthDensePt< 2, 0,-1> { enum { idx = 39 }; }; - - template<> struct FourthDensePt<-2, 0,-2> { enum { idx = 40 }; }; - template<> struct FourthDensePt<-1, 0,-2> { enum { idx = 41 }; }; - template<> struct FourthDensePt< 0, 0,-2> { enum { idx = 42 }; }; - template<> struct FourthDensePt< 1, 0,-2> { enum { idx = 43 }; }; - template<> struct FourthDensePt< 2, 0,-2> { enum { idx = 44 }; }; - - - template<> struct FourthDensePt< 0,-2, 2> { enum { idx = 45 }; }; - template<> struct FourthDensePt< 0,-1, 2> { enum { idx = 46 }; }; - template<> struct FourthDensePt< 0, 1, 2> { enum { idx = 47 }; }; - template<> struct FourthDensePt< 0, 2, 2> { enum { idx = 48 }; }; - - template<> struct FourthDensePt< 0,-2, 1> { enum { idx = 49 }; }; - template<> struct FourthDensePt< 0,-1, 1> { enum { idx = 50 }; }; - template<> struct FourthDensePt< 0, 1, 1> { enum { idx = 51 }; }; - template<> struct FourthDensePt< 0, 2, 1> { enum { idx = 52 }; }; - - template<> struct FourthDensePt< 0,-2,-1> { enum { idx = 53 }; }; - template<> struct FourthDensePt< 0,-1,-1> { enum { idx = 54 }; }; - template<> struct FourthDensePt< 0, 1,-1> { enum { idx = 55 }; }; - template<> struct FourthDensePt< 0, 2,-1> { enum { idx = 56 }; }; - - template<> struct FourthDensePt< 0,-2,-2> { enum { idx = 57 }; }; - template<> struct FourthDensePt< 0,-1,-2> { enum { idx = 58 }; }; - template<> struct FourthDensePt< 0, 1,-2> { enum { idx = 59 }; }; - template<> struct FourthDensePt< 0, 2,-2> { enum { idx = 60 }; }; - -} - - -template -class FourthOrderDenseStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 61; - - FourthOrderDenseStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return FourthDensePt::idx; } - -private: - inline void init(const Coord& ijk) - { - mStencil[FourthDensePt<-2, 2, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 2, 0)); - mStencil[FourthDensePt<-1, 2, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 2, 0)); - mStencil[FourthDensePt< 0, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 0)); - mStencil[FourthDensePt< 1, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 2, 0)); - mStencil[FourthDensePt< 2, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 2, 0)); - - mStencil[FourthDensePt<-2, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 1, 0)); - mStencil[FourthDensePt<-1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 1, 0)); - mStencil[FourthDensePt< 0, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[FourthDensePt< 1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 1, 0)); - mStencil[FourthDensePt< 2, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 1, 0)); - - mStencil[FourthDensePt<-2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 0)); - mStencil[FourthDensePt<-1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[FourthDensePt< 1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[FourthDensePt< 2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 0)); - - mStencil[FourthDensePt<-2,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-2,-1, 0)); - mStencil[FourthDensePt<-1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1,-1, 0)); - mStencil[FourthDensePt< 0,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 0)); - mStencil[FourthDensePt< 1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1,-1, 0)); - mStencil[FourthDensePt< 2,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 2,-1, 0)); - - mStencil[FourthDensePt<-2,-2, 0>::idx] = mCache.getValue(ijk.offsetBy(-2,-2, 0)); - mStencil[FourthDensePt<-1,-2, 0>::idx] = mCache.getValue(ijk.offsetBy(-1,-2, 0)); - mStencil[FourthDensePt< 0,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 0)); - mStencil[FourthDensePt< 1,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 1,-2, 0)); - mStencil[FourthDensePt< 2,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 2,-2, 0)); - - mStencil[FourthDensePt<-2, 0, 2>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 2)); - mStencil[FourthDensePt<-1, 0, 2>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 2)); - mStencil[FourthDensePt< 0, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 2)); - mStencil[FourthDensePt< 1, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 2)); - mStencil[FourthDensePt< 2, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 2)); - - mStencil[FourthDensePt<-2, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 1)); - mStencil[FourthDensePt<-1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 1)); - mStencil[FourthDensePt< 0, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - mStencil[FourthDensePt< 1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 1)); - mStencil[FourthDensePt< 2, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 1)); - - mStencil[FourthDensePt<-2, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-2, 0,-1)); - mStencil[FourthDensePt<-1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0,-1)); - mStencil[FourthDensePt< 0, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0,-1)); - mStencil[FourthDensePt< 1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0,-1)); - mStencil[FourthDensePt< 2, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 2, 0,-1)); - - mStencil[FourthDensePt<-2, 0,-2>::idx] = mCache.getValue(ijk.offsetBy(-2, 0,-2)); - mStencil[FourthDensePt<-1, 0,-2>::idx] = mCache.getValue(ijk.offsetBy(-1, 0,-2)); - mStencil[FourthDensePt< 0, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0,-2)); - mStencil[FourthDensePt< 1, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 1, 0,-2)); - mStencil[FourthDensePt< 2, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 2, 0,-2)); - - - mStencil[FourthDensePt< 0,-2, 2>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 2)); - mStencil[FourthDensePt< 0,-1, 2>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 2)); - mStencil[FourthDensePt< 0, 1, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 2)); - mStencil[FourthDensePt< 0, 2, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 2)); - - mStencil[FourthDensePt< 0,-2, 1>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 1)); - mStencil[FourthDensePt< 0,-1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 1)); - mStencil[FourthDensePt< 0, 1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 1)); - mStencil[FourthDensePt< 0, 2, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 1)); - - mStencil[FourthDensePt< 0,-2,-1>::idx] = mCache.getValue(ijk.offsetBy( 0,-2,-1)); - mStencil[FourthDensePt< 0,-1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0,-1,-1)); - mStencil[FourthDensePt< 0, 1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1,-1)); - mStencil[FourthDensePt< 0, 2,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 2,-1)); - - mStencil[FourthDensePt< 0,-2,-2>::idx] = mCache.getValue(ijk.offsetBy( 0,-2,-2)); - mStencil[FourthDensePt< 0,-1,-2>::idx] = mCache.getValue(ijk.offsetBy( 0,-1,-2)); - mStencil[FourthDensePt< 0, 1,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 1,-2)); - mStencil[FourthDensePt< 0, 2,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 2,-2)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the dense point stencil - template struct NineteenPt {}; - template<> struct NineteenPt< 0, 0, 0> { enum { idx = 0 }; }; - - template<> struct NineteenPt< 1, 0, 0> { enum { idx = 1 }; }; - template<> struct NineteenPt< 0, 1, 0> { enum { idx = 2 }; }; - template<> struct NineteenPt< 0, 0, 1> { enum { idx = 3 }; }; - - template<> struct NineteenPt<-1, 0, 0> { enum { idx = 4 }; }; - template<> struct NineteenPt< 0,-1, 0> { enum { idx = 5 }; }; - template<> struct NineteenPt< 0, 0,-1> { enum { idx = 6 }; }; - - template<> struct NineteenPt< 2, 0, 0> { enum { idx = 7 }; }; - template<> struct NineteenPt< 0, 2, 0> { enum { idx = 8 }; }; - template<> struct NineteenPt< 0, 0, 2> { enum { idx = 9 }; }; - - template<> struct NineteenPt<-2, 0, 0> { enum { idx = 10 }; }; - template<> struct NineteenPt< 0,-2, 0> { enum { idx = 11 }; }; - template<> struct NineteenPt< 0, 0,-2> { enum { idx = 12 }; }; - - template<> struct NineteenPt< 3, 0, 0> { enum { idx = 13 }; }; - template<> struct NineteenPt< 0, 3, 0> { enum { idx = 14 }; }; - template<> struct NineteenPt< 0, 0, 3> { enum { idx = 15 }; }; - - template<> struct NineteenPt<-3, 0, 0> { enum { idx = 16 }; }; - template<> struct NineteenPt< 0,-3, 0> { enum { idx = 17 }; }; - template<> struct NineteenPt< 0, 0,-3> { enum { idx = 18 }; }; - -} - - -template -class NineteenPointStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 19; - - NineteenPointStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return NineteenPt::idx; } - -private: - inline void init(const Coord& ijk) - { - mStencil[NineteenPt< 3, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 3, 0, 0)); - mStencil[NineteenPt< 2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 0)); - mStencil[NineteenPt< 1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[NineteenPt<-1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[NineteenPt<-2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 0)); - mStencil[NineteenPt<-3, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-3, 0, 0)); - - mStencil[NineteenPt< 0, 3, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 3, 0)); - mStencil[NineteenPt< 0, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 0)); - mStencil[NineteenPt< 0, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[NineteenPt< 0,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[NineteenPt< 0,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -2, 0)); - mStencil[NineteenPt< 0,-3, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, -3, 0)); - - mStencil[NineteenPt< 0, 0, 3>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 3)); - mStencil[NineteenPt< 0, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 2)); - mStencil[NineteenPt< 0, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - mStencil[NineteenPt< 0, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - mStencil[NineteenPt< 0, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -2)); - mStencil[NineteenPt< 0, 0,-3>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, -3)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -//////////////////////////////////////// - - -namespace { // anonymous namespace for stencil-layout map - - // the 4th-order dense point stencil - template struct SixthDensePt { }; - template<> struct SixthDensePt< 0, 0, 0> { enum { idx = 0 }; }; - - template<> struct SixthDensePt<-3, 3, 0> { enum { idx = 1 }; }; - template<> struct SixthDensePt<-2, 3, 0> { enum { idx = 2 }; }; - template<> struct SixthDensePt<-1, 3, 0> { enum { idx = 3 }; }; - template<> struct SixthDensePt< 0, 3, 0> { enum { idx = 4 }; }; - template<> struct SixthDensePt< 1, 3, 0> { enum { idx = 5 }; }; - template<> struct SixthDensePt< 2, 3, 0> { enum { idx = 6 }; }; - template<> struct SixthDensePt< 3, 3, 0> { enum { idx = 7 }; }; - - template<> struct SixthDensePt<-3, 2, 0> { enum { idx = 8 }; }; - template<> struct SixthDensePt<-2, 2, 0> { enum { idx = 9 }; }; - template<> struct SixthDensePt<-1, 2, 0> { enum { idx = 10 }; }; - template<> struct SixthDensePt< 0, 2, 0> { enum { idx = 11 }; }; - template<> struct SixthDensePt< 1, 2, 0> { enum { idx = 12 }; }; - template<> struct SixthDensePt< 2, 2, 0> { enum { idx = 13 }; }; - template<> struct SixthDensePt< 3, 2, 0> { enum { idx = 14 }; }; - - template<> struct SixthDensePt<-3, 1, 0> { enum { idx = 15 }; }; - template<> struct SixthDensePt<-2, 1, 0> { enum { idx = 16 }; }; - template<> struct SixthDensePt<-1, 1, 0> { enum { idx = 17 }; }; - template<> struct SixthDensePt< 0, 1, 0> { enum { idx = 18 }; }; - template<> struct SixthDensePt< 1, 1, 0> { enum { idx = 19 }; }; - template<> struct SixthDensePt< 2, 1, 0> { enum { idx = 20 }; }; - template<> struct SixthDensePt< 3, 1, 0> { enum { idx = 21 }; }; - - template<> struct SixthDensePt<-3, 0, 0> { enum { idx = 22 }; }; - template<> struct SixthDensePt<-2, 0, 0> { enum { idx = 23 }; }; - template<> struct SixthDensePt<-1, 0, 0> { enum { idx = 24 }; }; - template<> struct SixthDensePt< 1, 0, 0> { enum { idx = 25 }; }; - template<> struct SixthDensePt< 2, 0, 0> { enum { idx = 26 }; }; - template<> struct SixthDensePt< 3, 0, 0> { enum { idx = 27 }; }; - - - template<> struct SixthDensePt<-3,-1, 0> { enum { idx = 28 }; }; - template<> struct SixthDensePt<-2,-1, 0> { enum { idx = 29 }; }; - template<> struct SixthDensePt<-1,-1, 0> { enum { idx = 30 }; }; - template<> struct SixthDensePt< 0,-1, 0> { enum { idx = 31 }; }; - template<> struct SixthDensePt< 1,-1, 0> { enum { idx = 32 }; }; - template<> struct SixthDensePt< 2,-1, 0> { enum { idx = 33 }; }; - template<> struct SixthDensePt< 3,-1, 0> { enum { idx = 34 }; }; - - - template<> struct SixthDensePt<-3,-2, 0> { enum { idx = 35 }; }; - template<> struct SixthDensePt<-2,-2, 0> { enum { idx = 36 }; }; - template<> struct SixthDensePt<-1,-2, 0> { enum { idx = 37 }; }; - template<> struct SixthDensePt< 0,-2, 0> { enum { idx = 38 }; }; - template<> struct SixthDensePt< 1,-2, 0> { enum { idx = 39 }; }; - template<> struct SixthDensePt< 2,-2, 0> { enum { idx = 40 }; }; - template<> struct SixthDensePt< 3,-2, 0> { enum { idx = 41 }; }; - - - template<> struct SixthDensePt<-3,-3, 0> { enum { idx = 42 }; }; - template<> struct SixthDensePt<-2,-3, 0> { enum { idx = 43 }; }; - template<> struct SixthDensePt<-1,-3, 0> { enum { idx = 44 }; }; - template<> struct SixthDensePt< 0,-3, 0> { enum { idx = 45 }; }; - template<> struct SixthDensePt< 1,-3, 0> { enum { idx = 46 }; }; - template<> struct SixthDensePt< 2,-3, 0> { enum { idx = 47 }; }; - template<> struct SixthDensePt< 3,-3, 0> { enum { idx = 48 }; }; - - - template<> struct SixthDensePt<-3, 0, 3> { enum { idx = 49 }; }; - template<> struct SixthDensePt<-2, 0, 3> { enum { idx = 50 }; }; - template<> struct SixthDensePt<-1, 0, 3> { enum { idx = 51 }; }; - template<> struct SixthDensePt< 0, 0, 3> { enum { idx = 52 }; }; - template<> struct SixthDensePt< 1, 0, 3> { enum { idx = 53 }; }; - template<> struct SixthDensePt< 2, 0, 3> { enum { idx = 54 }; }; - template<> struct SixthDensePt< 3, 0, 3> { enum { idx = 55 }; }; - - - template<> struct SixthDensePt<-3, 0, 2> { enum { idx = 56 }; }; - template<> struct SixthDensePt<-2, 0, 2> { enum { idx = 57 }; }; - template<> struct SixthDensePt<-1, 0, 2> { enum { idx = 58 }; }; - template<> struct SixthDensePt< 0, 0, 2> { enum { idx = 59 }; }; - template<> struct SixthDensePt< 1, 0, 2> { enum { idx = 60 }; }; - template<> struct SixthDensePt< 2, 0, 2> { enum { idx = 61 }; }; - template<> struct SixthDensePt< 3, 0, 2> { enum { idx = 62 }; }; - - template<> struct SixthDensePt<-3, 0, 1> { enum { idx = 63 }; }; - template<> struct SixthDensePt<-2, 0, 1> { enum { idx = 64 }; }; - template<> struct SixthDensePt<-1, 0, 1> { enum { idx = 65 }; }; - template<> struct SixthDensePt< 0, 0, 1> { enum { idx = 66 }; }; - template<> struct SixthDensePt< 1, 0, 1> { enum { idx = 67 }; }; - template<> struct SixthDensePt< 2, 0, 1> { enum { idx = 68 }; }; - template<> struct SixthDensePt< 3, 0, 1> { enum { idx = 69 }; }; - - - template<> struct SixthDensePt<-3, 0,-1> { enum { idx = 70 }; }; - template<> struct SixthDensePt<-2, 0,-1> { enum { idx = 71 }; }; - template<> struct SixthDensePt<-1, 0,-1> { enum { idx = 72 }; }; - template<> struct SixthDensePt< 0, 0,-1> { enum { idx = 73 }; }; - template<> struct SixthDensePt< 1, 0,-1> { enum { idx = 74 }; }; - template<> struct SixthDensePt< 2, 0,-1> { enum { idx = 75 }; }; - template<> struct SixthDensePt< 3, 0,-1> { enum { idx = 76 }; }; - - - template<> struct SixthDensePt<-3, 0,-2> { enum { idx = 77 }; }; - template<> struct SixthDensePt<-2, 0,-2> { enum { idx = 78 }; }; - template<> struct SixthDensePt<-1, 0,-2> { enum { idx = 79 }; }; - template<> struct SixthDensePt< 0, 0,-2> { enum { idx = 80 }; }; - template<> struct SixthDensePt< 1, 0,-2> { enum { idx = 81 }; }; - template<> struct SixthDensePt< 2, 0,-2> { enum { idx = 82 }; }; - template<> struct SixthDensePt< 3, 0,-2> { enum { idx = 83 }; }; - - - template<> struct SixthDensePt<-3, 0,-3> { enum { idx = 84 }; }; - template<> struct SixthDensePt<-2, 0,-3> { enum { idx = 85 }; }; - template<> struct SixthDensePt<-1, 0,-3> { enum { idx = 86 }; }; - template<> struct SixthDensePt< 0, 0,-3> { enum { idx = 87 }; }; - template<> struct SixthDensePt< 1, 0,-3> { enum { idx = 88 }; }; - template<> struct SixthDensePt< 2, 0,-3> { enum { idx = 89 }; }; - template<> struct SixthDensePt< 3, 0,-3> { enum { idx = 90 }; }; - - - template<> struct SixthDensePt< 0,-3, 3> { enum { idx = 91 }; }; - template<> struct SixthDensePt< 0,-2, 3> { enum { idx = 92 }; }; - template<> struct SixthDensePt< 0,-1, 3> { enum { idx = 93 }; }; - template<> struct SixthDensePt< 0, 1, 3> { enum { idx = 94 }; }; - template<> struct SixthDensePt< 0, 2, 3> { enum { idx = 95 }; }; - template<> struct SixthDensePt< 0, 3, 3> { enum { idx = 96 }; }; - - template<> struct SixthDensePt< 0,-3, 2> { enum { idx = 97 }; }; - template<> struct SixthDensePt< 0,-2, 2> { enum { idx = 98 }; }; - template<> struct SixthDensePt< 0,-1, 2> { enum { idx = 99 }; }; - template<> struct SixthDensePt< 0, 1, 2> { enum { idx = 100 }; }; - template<> struct SixthDensePt< 0, 2, 2> { enum { idx = 101 }; }; - template<> struct SixthDensePt< 0, 3, 2> { enum { idx = 102 }; }; - - template<> struct SixthDensePt< 0,-3, 1> { enum { idx = 103 }; }; - template<> struct SixthDensePt< 0,-2, 1> { enum { idx = 104 }; }; - template<> struct SixthDensePt< 0,-1, 1> { enum { idx = 105 }; }; - template<> struct SixthDensePt< 0, 1, 1> { enum { idx = 106 }; }; - template<> struct SixthDensePt< 0, 2, 1> { enum { idx = 107 }; }; - template<> struct SixthDensePt< 0, 3, 1> { enum { idx = 108 }; }; - - template<> struct SixthDensePt< 0,-3,-1> { enum { idx = 109 }; }; - template<> struct SixthDensePt< 0,-2,-1> { enum { idx = 110 }; }; - template<> struct SixthDensePt< 0,-1,-1> { enum { idx = 111 }; }; - template<> struct SixthDensePt< 0, 1,-1> { enum { idx = 112 }; }; - template<> struct SixthDensePt< 0, 2,-1> { enum { idx = 113 }; }; - template<> struct SixthDensePt< 0, 3,-1> { enum { idx = 114 }; }; - - template<> struct SixthDensePt< 0,-3,-2> { enum { idx = 115 }; }; - template<> struct SixthDensePt< 0,-2,-2> { enum { idx = 116 }; }; - template<> struct SixthDensePt< 0,-1,-2> { enum { idx = 117 }; }; - template<> struct SixthDensePt< 0, 1,-2> { enum { idx = 118 }; }; - template<> struct SixthDensePt< 0, 2,-2> { enum { idx = 119 }; }; - template<> struct SixthDensePt< 0, 3,-2> { enum { idx = 120 }; }; - - template<> struct SixthDensePt< 0,-3,-3> { enum { idx = 121 }; }; - template<> struct SixthDensePt< 0,-2,-3> { enum { idx = 122 }; }; - template<> struct SixthDensePt< 0,-1,-3> { enum { idx = 123 }; }; - template<> struct SixthDensePt< 0, 1,-3> { enum { idx = 124 }; }; - template<> struct SixthDensePt< 0, 2,-3> { enum { idx = 125 }; }; - template<> struct SixthDensePt< 0, 3,-3> { enum { idx = 126 }; }; - -} - - -template -class SixthOrderDenseStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 127; - - SixthOrderDenseStencil(const GridType& grid): BaseType(grid, SIZE) {} - - /// Return linear offset for the specified stencil point relative to its center - template - unsigned int pos() const { return SixthDensePt::idx; } - -private: - inline void init(const Coord& ijk) - { - mStencil[SixthDensePt<-3, 3, 0>::idx] = mCache.getValue(ijk.offsetBy(-3, 3, 0)); - mStencil[SixthDensePt<-2, 3, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 3, 0)); - mStencil[SixthDensePt<-1, 3, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 3, 0)); - mStencil[SixthDensePt< 0, 3, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 3, 0)); - mStencil[SixthDensePt< 1, 3, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 3, 0)); - mStencil[SixthDensePt< 2, 3, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 3, 0)); - mStencil[SixthDensePt< 3, 3, 0>::idx] = mCache.getValue(ijk.offsetBy( 3, 3, 0)); - - mStencil[SixthDensePt<-3, 2, 0>::idx] = mCache.getValue(ijk.offsetBy(-3, 2, 0)); - mStencil[SixthDensePt<-2, 2, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 2, 0)); - mStencil[SixthDensePt<-1, 2, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 2, 0)); - mStencil[SixthDensePt< 0, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 0)); - mStencil[SixthDensePt< 1, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 2, 0)); - mStencil[SixthDensePt< 2, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 2, 0)); - mStencil[SixthDensePt< 3, 2, 0>::idx] = mCache.getValue(ijk.offsetBy( 3, 2, 0)); - - mStencil[SixthDensePt<-3, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-3, 1, 0)); - mStencil[SixthDensePt<-2, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 1, 0)); - mStencil[SixthDensePt<-1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 1, 0)); - mStencil[SixthDensePt< 0, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[SixthDensePt< 1, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 1, 0)); - mStencil[SixthDensePt< 2, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 1, 0)); - mStencil[SixthDensePt< 3, 1, 0>::idx] = mCache.getValue(ijk.offsetBy( 3, 1, 0)); - - mStencil[SixthDensePt<-3, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-3, 0, 0)); - mStencil[SixthDensePt<-2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 0)); - mStencil[SixthDensePt<-1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[SixthDensePt< 1, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[SixthDensePt< 2, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 0)); - mStencil[SixthDensePt< 3, 0, 0>::idx] = mCache.getValue(ijk.offsetBy( 3, 0, 0)); - - mStencil[SixthDensePt<-3,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-3,-1, 0)); - mStencil[SixthDensePt<-2,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-2,-1, 0)); - mStencil[SixthDensePt<-1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy(-1,-1, 0)); - mStencil[SixthDensePt< 0,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 0)); - mStencil[SixthDensePt< 1,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 1,-1, 0)); - mStencil[SixthDensePt< 2,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 2,-1, 0)); - mStencil[SixthDensePt< 3,-1, 0>::idx] = mCache.getValue(ijk.offsetBy( 3,-1, 0)); - - mStencil[SixthDensePt<-3,-2, 0>::idx] = mCache.getValue(ijk.offsetBy(-3,-2, 0)); - mStencil[SixthDensePt<-2,-2, 0>::idx] = mCache.getValue(ijk.offsetBy(-2,-2, 0)); - mStencil[SixthDensePt<-1,-2, 0>::idx] = mCache.getValue(ijk.offsetBy(-1,-2, 0)); - mStencil[SixthDensePt< 0,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 0)); - mStencil[SixthDensePt< 1,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 1,-2, 0)); - mStencil[SixthDensePt< 2,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 2,-2, 0)); - mStencil[SixthDensePt< 3,-2, 0>::idx] = mCache.getValue(ijk.offsetBy( 3,-2, 0)); - - mStencil[SixthDensePt<-3,-3, 0>::idx] = mCache.getValue(ijk.offsetBy(-3,-3, 0)); - mStencil[SixthDensePt<-2,-3, 0>::idx] = mCache.getValue(ijk.offsetBy(-2,-3, 0)); - mStencil[SixthDensePt<-1,-3, 0>::idx] = mCache.getValue(ijk.offsetBy(-1,-3, 0)); - mStencil[SixthDensePt< 0,-3, 0>::idx] = mCache.getValue(ijk.offsetBy( 0,-3, 0)); - mStencil[SixthDensePt< 1,-3, 0>::idx] = mCache.getValue(ijk.offsetBy( 1,-3, 0)); - mStencil[SixthDensePt< 2,-3, 0>::idx] = mCache.getValue(ijk.offsetBy( 2,-3, 0)); - mStencil[SixthDensePt< 3,-3, 0>::idx] = mCache.getValue(ijk.offsetBy( 3,-3, 0)); - - mStencil[SixthDensePt<-3, 0, 3>::idx] = mCache.getValue(ijk.offsetBy(-3, 0, 3)); - mStencil[SixthDensePt<-2, 0, 3>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 3)); - mStencil[SixthDensePt<-1, 0, 3>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 3)); - mStencil[SixthDensePt< 0, 0, 3>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 3)); - mStencil[SixthDensePt< 1, 0, 3>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 3)); - mStencil[SixthDensePt< 2, 0, 3>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 3)); - mStencil[SixthDensePt< 3, 0, 3>::idx] = mCache.getValue(ijk.offsetBy( 3, 0, 3)); - - mStencil[SixthDensePt<-3, 0, 2>::idx] = mCache.getValue(ijk.offsetBy(-3, 0, 2)); - mStencil[SixthDensePt<-2, 0, 2>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 2)); - mStencil[SixthDensePt<-1, 0, 2>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 2)); - mStencil[SixthDensePt< 0, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 2)); - mStencil[SixthDensePt< 1, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 2)); - mStencil[SixthDensePt< 2, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 2)); - mStencil[SixthDensePt< 3, 0, 2>::idx] = mCache.getValue(ijk.offsetBy( 3, 0, 2)); - - mStencil[SixthDensePt<-3, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-3, 0, 1)); - mStencil[SixthDensePt<-2, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-2, 0, 1)); - mStencil[SixthDensePt<-1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0, 1)); - mStencil[SixthDensePt< 0, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - mStencil[SixthDensePt< 1, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0, 1)); - mStencil[SixthDensePt< 2, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 2, 0, 1)); - mStencil[SixthDensePt< 3, 0, 1>::idx] = mCache.getValue(ijk.offsetBy( 3, 0, 1)); - - mStencil[SixthDensePt<-3, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-3, 0,-1)); - mStencil[SixthDensePt<-2, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-2, 0,-1)); - mStencil[SixthDensePt<-1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy(-1, 0,-1)); - mStencil[SixthDensePt< 0, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 0,-1)); - mStencil[SixthDensePt< 1, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 1, 0,-1)); - mStencil[SixthDensePt< 2, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 2, 0,-1)); - mStencil[SixthDensePt< 3, 0,-1>::idx] = mCache.getValue(ijk.offsetBy( 3, 0,-1)); - - mStencil[SixthDensePt<-3, 0,-2>::idx] = mCache.getValue(ijk.offsetBy(-3, 0,-2)); - mStencil[SixthDensePt<-2, 0,-2>::idx] = mCache.getValue(ijk.offsetBy(-2, 0,-2)); - mStencil[SixthDensePt<-1, 0,-2>::idx] = mCache.getValue(ijk.offsetBy(-1, 0,-2)); - mStencil[SixthDensePt< 0, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 0,-2)); - mStencil[SixthDensePt< 1, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 1, 0,-2)); - mStencil[SixthDensePt< 2, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 2, 0,-2)); - mStencil[SixthDensePt< 3, 0,-2>::idx] = mCache.getValue(ijk.offsetBy( 3, 0,-2)); - - mStencil[SixthDensePt<-3, 0,-3>::idx] = mCache.getValue(ijk.offsetBy(-3, 0,-3)); - mStencil[SixthDensePt<-2, 0,-3>::idx] = mCache.getValue(ijk.offsetBy(-2, 0,-3)); - mStencil[SixthDensePt<-1, 0,-3>::idx] = mCache.getValue(ijk.offsetBy(-1, 0,-3)); - mStencil[SixthDensePt< 0, 0,-3>::idx] = mCache.getValue(ijk.offsetBy( 0, 0,-3)); - mStencil[SixthDensePt< 1, 0,-3>::idx] = mCache.getValue(ijk.offsetBy( 1, 0,-3)); - mStencil[SixthDensePt< 2, 0,-3>::idx] = mCache.getValue(ijk.offsetBy( 2, 0,-3)); - mStencil[SixthDensePt< 3, 0,-3>::idx] = mCache.getValue(ijk.offsetBy( 3, 0,-3)); - - mStencil[SixthDensePt< 0,-3, 3>::idx] = mCache.getValue(ijk.offsetBy( 0,-3, 3)); - mStencil[SixthDensePt< 0,-2, 3>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 3)); - mStencil[SixthDensePt< 0,-1, 3>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 3)); - mStencil[SixthDensePt< 0, 1, 3>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 3)); - mStencil[SixthDensePt< 0, 2, 3>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 3)); - mStencil[SixthDensePt< 0, 3, 3>::idx] = mCache.getValue(ijk.offsetBy( 0, 3, 3)); - - mStencil[SixthDensePt< 0,-3, 2>::idx] = mCache.getValue(ijk.offsetBy( 0,-3, 2)); - mStencil[SixthDensePt< 0,-2, 2>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 2)); - mStencil[SixthDensePt< 0,-1, 2>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 2)); - mStencil[SixthDensePt< 0, 1, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 2)); - mStencil[SixthDensePt< 0, 2, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 2)); - mStencil[SixthDensePt< 0, 3, 2>::idx] = mCache.getValue(ijk.offsetBy( 0, 3, 2)); - - mStencil[SixthDensePt< 0,-3, 1>::idx] = mCache.getValue(ijk.offsetBy( 0,-3, 1)); - mStencil[SixthDensePt< 0,-2, 1>::idx] = mCache.getValue(ijk.offsetBy( 0,-2, 1)); - mStencil[SixthDensePt< 0,-1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0,-1, 1)); - mStencil[SixthDensePt< 0, 1, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1, 1)); - mStencil[SixthDensePt< 0, 2, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 2, 1)); - mStencil[SixthDensePt< 0, 3, 1>::idx] = mCache.getValue(ijk.offsetBy( 0, 3, 1)); - - mStencil[SixthDensePt< 0,-3,-1>::idx] = mCache.getValue(ijk.offsetBy( 0,-3,-1)); - mStencil[SixthDensePt< 0,-2,-1>::idx] = mCache.getValue(ijk.offsetBy( 0,-2,-1)); - mStencil[SixthDensePt< 0,-1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0,-1,-1)); - mStencil[SixthDensePt< 0, 1,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 1,-1)); - mStencil[SixthDensePt< 0, 2,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 2,-1)); - mStencil[SixthDensePt< 0, 3,-1>::idx] = mCache.getValue(ijk.offsetBy( 0, 3,-1)); - - mStencil[SixthDensePt< 0,-3,-2>::idx] = mCache.getValue(ijk.offsetBy( 0,-3,-2)); - mStencil[SixthDensePt< 0,-2,-2>::idx] = mCache.getValue(ijk.offsetBy( 0,-2,-2)); - mStencil[SixthDensePt< 0,-1,-2>::idx] = mCache.getValue(ijk.offsetBy( 0,-1,-2)); - mStencil[SixthDensePt< 0, 1,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 1,-2)); - mStencil[SixthDensePt< 0, 2,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 2,-2)); - mStencil[SixthDensePt< 0, 3,-2>::idx] = mCache.getValue(ijk.offsetBy( 0, 3,-2)); - - mStencil[SixthDensePt< 0,-3,-3>::idx] = mCache.getValue(ijk.offsetBy( 0,-3,-3)); - mStencil[SixthDensePt< 0,-2,-3>::idx] = mCache.getValue(ijk.offsetBy( 0,-2,-3)); - mStencil[SixthDensePt< 0,-1,-3>::idx] = mCache.getValue(ijk.offsetBy( 0,-1,-3)); - mStencil[SixthDensePt< 0, 1,-3>::idx] = mCache.getValue(ijk.offsetBy( 0, 1,-3)); - mStencil[SixthDensePt< 0, 2,-3>::idx] = mCache.getValue(ijk.offsetBy( 0, 2,-3)); - mStencil[SixthDensePt< 0, 3,-3>::idx] = mCache.getValue(ijk.offsetBy( 0, 3,-3)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; -}; - - -////////////////////////////////////////////////////////////////////// - - -/// This is a simple 7-point nearest neighbor stencil that supports -/// gradient by second-order central differencing, first-order upwinding, -/// Laplacian, closest-point transform and zero-crossing test. -/// -/// @note For optimal random access performance this class -/// includes its own grid accessor. -template -class GradStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 7; - - GradStencil(const GridType& grid): - BaseType(grid, SIZE), - mInv2Dx(ValueType(0.5 / grid.voxelSize()[0])), - mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx)) - { - } - - GradStencil(const GridType& grid, Real dx): - BaseType(grid, SIZE), - mInv2Dx(ValueType(0.5 / dx)), - mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx)) - { - } - - /// @brief Return the norm square of the single-sided upwind gradient - /// (computed via Gudonov's scheme) at the previously buffered location. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType normSqGrad() const - { - return mInvDx2 * math::GudonovsNormSqrd(mStencil[0] > 0, - mStencil[0] - mStencil[1], - mStencil[2] - mStencil[0], - mStencil[0] - mStencil[3], - mStencil[4] - mStencil[0], - mStencil[0] - mStencil[5], - mStencil[6] - mStencil[0]); - } - - /// @brief Return the gradient computed at the previously buffered - /// location by second order central differencing. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline Vec3Type gradient() const - { - return Vec3Type(mStencil[2] - mStencil[1], - mStencil[4] - mStencil[3], - mStencil[6] - mStencil[5])*mInv2Dx; - } - /// @brief Return the first-order upwind gradient corresponding to the direction V. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline Vec3Type gradient(const Vec3Type& V) const - { - return Vec3Type(V[0]>0 ? mStencil[0] - mStencil[1] : mStencil[2] - mStencil[0], - V[1]>0 ? mStencil[0] - mStencil[3] : mStencil[4] - mStencil[0], - V[2]>0 ? mStencil[0] - mStencil[5] : mStencil[6] - mStencil[0])*2*mInv2Dx; - } - - /// Return the Laplacian computed at the previously buffered - /// location by second-order central differencing. - inline ValueType laplacian() const - { - return mInvDx2 * (mStencil[1] + mStencil[2] + - mStencil[3] + mStencil[4] + - mStencil[5] + mStencil[6] - 6*mStencil[0]); - } - - /// Return @c true if the sign of the value at the center point of the stencil - /// is different from the signs of any of its six nearest neighbors. - inline bool zeroCrossing() const - { - const BufferType& v = mStencil; - return (v[0]>0 ? (v[1]<0 || v[2]<0 || v[3]<0 || v[4]<0 || v[5]<0 || v[6]<0) - : (v[1]>0 || v[2]>0 || v[3]>0 || v[4]>0 || v[5]>0 || v[6]>0)); - } - - /// @brief Compute the closest-point transform to a level set. - /// @return the closest point in index space to the surface - /// from which the level set was derived. - /// - /// @note This method assumes that the grid represents a level set - /// with distances in world units and a simple affine transfrom - /// with uniform scaling. - inline Vec3Type cpt() - { - const Coord& ijk = BaseType::getCenterCoord(); - const ValueType d = ValueType(mStencil[0] * 0.5 * mInvDx2); // distance in voxels / (2dx^2) - return Vec3Type(ijk[0] - d*(mStencil[2] - mStencil[1]), - ijk[1] - d*(mStencil[4] - mStencil[3]), - ijk[2] - d*(mStencil[6] - mStencil[5])); - } - -private: - - inline void init(const Coord& ijk) - { - mStencil[1] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[2] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - - mStencil[3] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[4] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - - mStencil[5] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - mStencil[6] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; - const ValueType mInv2Dx, mInvDx2; -}; // class GradStencil - - -//////////////////////////////////////// - - -/// @brief This is a special 19-point stencil that supports optimal fifth-order WENO -/// upwinding, second-order central differencing, Laplacian, and zero-crossing test. -/// -/// @note For optimal random access performance this class -/// includes its own grid accessor. -template -class WenoStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename BaseType::BufferType BufferType; - typedef typename GridType::ValueType ValueType; - typedef math::Vec3 Vec3Type; - - static const int SIZE = 19; - - WenoStencil(const GridType& grid): - BaseType(grid, SIZE), - mDx2(ValueType(math::Pow2(grid.voxelSize()[0]))), - mInv2Dx(ValueType(0.5 / grid.voxelSize()[0])), - mInvDx2(ValueType(1.0 / mDx2)) - { - } - - WenoStencil(const GridType& grid, Real dx): - BaseType(grid, SIZE), - mDx2(ValueType(dx * dx)), - mInv2Dx(ValueType(0.5 / dx)), - mInvDx2(ValueType(1.0 / mDx2)) - { - } - - /// @brief Return the norm-square of the WENO upwind gradient (computed via - /// WENO upwinding and Gudonov's scheme) at the previously buffered location. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType normSqGrad() const - { - const BufferType& v = mStencil; -#ifdef DWA_OPENVDB - // SSE optimized - const simd::Float4 - v1(v[2]-v[1], v[ 8]-v[ 7], v[14]-v[13], 0), - v2(v[3]-v[2], v[ 9]-v[ 8], v[15]-v[14], 0), - v3(v[0]-v[3], v[ 0]-v[ 9], v[ 0]-v[15], 0), - v4(v[4]-v[0], v[10]-v[ 0], v[16]-v[ 0], 0), - v5(v[5]-v[4], v[11]-v[10], v[17]-v[16], 0), - v6(v[6]-v[5], v[12]-v[11], v[18]-v[17], 0), - dP_m = math::WENO5(v1, v2, v3, v4, v5, mDx2), - dP_p = math::WENO5(v6, v5, v4, v3, v2, mDx2); - - return mInvDx2 * math::GudonovsNormSqrd(mStencil[0] > 0, dP_m, dP_p); -#else - const Real - dP_xm = math::WENO5(v[ 2]-v[ 1],v[ 3]-v[ 2],v[ 0]-v[ 3],v[ 4]-v[ 0],v[ 5]-v[ 4],mDx2), - dP_xp = math::WENO5(v[ 6]-v[ 5],v[ 5]-v[ 4],v[ 4]-v[ 0],v[ 0]-v[ 3],v[ 3]-v[ 2],mDx2), - dP_ym = math::WENO5(v[ 8]-v[ 7],v[ 9]-v[ 8],v[ 0]-v[ 9],v[10]-v[ 0],v[11]-v[10],mDx2), - dP_yp = math::WENO5(v[12]-v[11],v[11]-v[10],v[10]-v[ 0],v[ 0]-v[ 9],v[ 9]-v[ 8],mDx2), - dP_zm = math::WENO5(v[14]-v[13],v[15]-v[14],v[ 0]-v[15],v[16]-v[ 0],v[17]-v[16],mDx2), - dP_zp = math::WENO5(v[18]-v[17],v[17]-v[16],v[16]-v[ 0],v[ 0]-v[15],v[15]-v[14],mDx2); - return static_cast( - mInvDx2*math::GudonovsNormSqrd(v[0]>0,dP_xm,dP_xp,dP_ym,dP_yp,dP_zm,dP_zp)); -#endif - } - - /// Return the optimal fifth-order upwind gradient corresponding to the - /// direction V. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline Vec3Type gradient(const Vec3Type& V) const - { - const BufferType& v = mStencil; - return 2*mInv2Dx * Vec3Type( - V[0]>0 ? math::WENO5(v[ 2]-v[ 1],v[ 3]-v[ 2],v[ 0]-v[ 3], v[ 4]-v[ 0],v[ 5]-v[ 4],mDx2) - : math::WENO5(v[ 6]-v[ 5],v[ 5]-v[ 4],v[ 4]-v[ 0], v[ 0]-v[ 3],v[ 3]-v[ 2],mDx2), - V[1]>0 ? math::WENO5(v[ 8]-v[ 7],v[ 9]-v[ 8],v[ 0]-v[ 9], v[10]-v[ 0],v[11]-v[10],mDx2) - : math::WENO5(v[12]-v[11],v[11]-v[10],v[10]-v[ 0], v[ 0]-v[ 9],v[ 9]-v[ 8],mDx2), - V[2]>0 ? math::WENO5(v[14]-v[13],v[15]-v[14],v[ 0]-v[15], v[16]-v[ 0],v[17]-v[16],mDx2) - : math::WENO5(v[18]-v[17],v[17]-v[16],v[16]-v[ 0], v[ 0]-v[15],v[15]-v[14],mDx2)); - } - /// Return the gradient computed at the previously buffered - /// location by second-order central differencing. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline Vec3Type gradient() const - { - return mInv2Dx * Vec3Type( - mStencil[ 4] - mStencil[ 3], - mStencil[10] - mStencil[ 9], - mStencil[16] - mStencil[15]); - } - - /// Return the Laplacian computed at the previously buffered - /// location by second-order central differencing. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType laplacian() const - { - return mInvDx2 * ( - mStencil[ 3] + mStencil[ 4] + - mStencil[ 9] + mStencil[10] + - mStencil[15] + mStencil[16] - 6*mStencil[0]); - } - - /// Return @c true if the sign of the value at the center point of the stencil - /// differs from the sign of any of its six nearest neighbors - inline bool zeroCrossing() const - { - const BufferType& v = mStencil; - return (v[ 0]>0 ? (v[ 3]<0 || v[ 4]<0 || v[ 9]<0 || v[10]<0 || v[15]<0 || v[16]<0) - : (v[ 3]>0 || v[ 4]>0 || v[ 9]>0 || v[10]>0 || v[15]>0 || v[16]>0)); - } - -private: - inline void init(const Coord& ijk) - { - mStencil[ 1] = mCache.getValue(ijk.offsetBy(-3, 0, 0)); - mStencil[ 2] = mCache.getValue(ijk.offsetBy(-2, 0, 0)); - mStencil[ 3] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[ 4] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - mStencil[ 5] = mCache.getValue(ijk.offsetBy( 2, 0, 0)); - mStencil[ 6] = mCache.getValue(ijk.offsetBy( 3, 0, 0)); - - mStencil[ 7] = mCache.getValue(ijk.offsetBy( 0, -3, 0)); - mStencil[ 8] = mCache.getValue(ijk.offsetBy( 0, -2, 0)); - mStencil[ 9] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[10] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - mStencil[11] = mCache.getValue(ijk.offsetBy( 0, 2, 0)); - mStencil[12] = mCache.getValue(ijk.offsetBy( 0, 3, 0)); - - mStencil[13] = mCache.getValue(ijk.offsetBy( 0, 0, -3)); - mStencil[14] = mCache.getValue(ijk.offsetBy( 0, 0, -2)); - mStencil[15] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - mStencil[16] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - mStencil[17] = mCache.getValue(ijk.offsetBy( 0, 0, 2)); - mStencil[18] = mCache.getValue(ijk.offsetBy( 0, 0, 3)); - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; - const ValueType mDx2, mInv2Dx, mInvDx2; -}; // class WenoStencil - - -////////////////////////////////////////////////////////////////////// - - -template -class CurvatureStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename GridType::ValueType ValueType; - - static const int SIZE = 19; - - CurvatureStencil(const GridType& grid): - BaseType(grid, SIZE), - mInv2Dx(ValueType(0.5 / grid.voxelSize()[0])), - mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx)) - { - } - - CurvatureStencil(const GridType& grid, Real dx): - BaseType(grid, SIZE), - mInv2Dx(ValueType(0.5 / dx)), - mInvDx2(ValueType(4.0 * mInv2Dx * mInv2Dx)) - { - } - - /// @brief Return the mean curvature at the previously buffered location. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType meanCurvature() - { - Real alpha, beta; - return this->meanCurvature(alpha, beta) ? ValueType(alpha*mInv2Dx/math::Pow3(beta)) : 0; - } - - /// Return the mean curvature multiplied by the norm of the - /// central-difference gradient. This method is very useful for - /// mean-curvature flow of level sets! - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType meanCurvatureNormGrad() - { - Real alpha, beta; - return this->meanCurvature(alpha, beta) ? ValueType(alpha*mInvDx2/(2*math::Pow2(beta))) : 0; - } - - /// Return the Laplacian computed at the previously buffered - /// location by second-order central differencing. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline ValueType laplacian() const - { - return mInvDx2 * ( - mStencil[1] + mStencil[2] + - mStencil[3] + mStencil[4] + - mStencil[5] + mStencil[6] - 6*mStencil[0]); - } - - /// Return the gradient computed at the previously buffered - /// location by second-order central differencing. - /// - /// @note This method should not be called until the stencil - /// buffer has been populated via a call to moveTo(ijk). - inline math::Vec3 gradient() - { - return math::Vec3( - mStencil[2] - mStencil[1], - mStencil[4] - mStencil[3], - mStencil[6] - mStencil[5])*mInv2Dx; - } - -private: - inline void init(const Coord &ijk) - { - mStencil[ 1] = mCache.getValue(ijk.offsetBy(-1, 0, 0)); - mStencil[ 2] = mCache.getValue(ijk.offsetBy( 1, 0, 0)); - - mStencil[ 3] = mCache.getValue(ijk.offsetBy( 0, -1, 0)); - mStencil[ 4] = mCache.getValue(ijk.offsetBy( 0, 1, 0)); - - mStencil[ 5] = mCache.getValue(ijk.offsetBy( 0, 0, -1)); - mStencil[ 6] = mCache.getValue(ijk.offsetBy( 0, 0, 1)); - - mStencil[ 7] = mCache.getValue(ijk.offsetBy(-1, -1, 0)); - mStencil[ 8] = mCache.getValue(ijk.offsetBy( 1, -1, 0)); - mStencil[ 9] = mCache.getValue(ijk.offsetBy(-1, 1, 0)); - mStencil[10] = mCache.getValue(ijk.offsetBy( 1, 1, 0)); - - mStencil[11] = mCache.getValue(ijk.offsetBy(-1, 0, -1)); - mStencil[12] = mCache.getValue(ijk.offsetBy( 1, 0, -1)); - mStencil[13] = mCache.getValue(ijk.offsetBy(-1, 0, 1)); - mStencil[14] = mCache.getValue(ijk.offsetBy( 1, 0, 1)); - - mStencil[15] = mCache.getValue(ijk.offsetBy( 0, -1, -1)); - mStencil[16] = mCache.getValue(ijk.offsetBy( 0, 1, -1)); - mStencil[17] = mCache.getValue(ijk.offsetBy( 0, -1, 1)); - mStencil[18] = mCache.getValue(ijk.offsetBy( 0, 1, 1)); - } - - inline bool meanCurvature(Real& alpha, Real& beta) const - { - // For performance all finite differences are unscaled wrt dx - const Real - Half(0.5), Quarter(0.25), - Dx = Half * (mStencil[2] - mStencil[1]), Dx2 = Dx * Dx, // * 1/dx - Dy = Half * (mStencil[4] - mStencil[3]), Dy2 = Dy * Dy, // * 1/dx - Dz = Half * (mStencil[6] - mStencil[5]), Dz2 = Dz * Dz, // * 1/dx - normGrad = Dx2 + Dy2 + Dz2; - if (normGrad <= math::Tolerance::value()) { - alpha = beta = 0; - return false; - } - const Real - Dxx = mStencil[2] - 2 * mStencil[0] + mStencil[1], // * 1/dx2 - Dyy = mStencil[4] - 2 * mStencil[0] + mStencil[3], // * 1/dx2 - Dzz = mStencil[6] - 2 * mStencil[0] + mStencil[5], // * 1/dx2 - Dxy = Quarter * (mStencil[10] - mStencil[ 8] + mStencil[7] - mStencil[ 9]), // * 1/dx2 - Dxz = Quarter * (mStencil[14] - mStencil[12] + mStencil[11] - mStencil[13]), // * 1/dx2 - Dyz = Quarter * (mStencil[18] - mStencil[16] + mStencil[15] - mStencil[17]); // * 1/dx2 - alpha = (Dx2*(Dyy+Dzz)+Dy2*(Dxx+Dzz)+Dz2*(Dxx+Dyy)-2*(Dx*(Dy*Dxy+Dz*Dxz)+Dy*Dz*Dyz)); - beta = std::sqrt(normGrad); // * 1/dx - return true; - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; - const ValueType mInv2Dx, mInvDx2; -}; // class CurvatureStencil - - -////////////////////////////////////////////////////////////////////// - - -/// @brief Dense stencil of a given width -template -class DenseStencil: public BaseStencil > -{ -public: - typedef BaseStencil > BaseType; - typedef typename GridType::ValueType ValueType; - - DenseStencil(const GridType& grid, int halfWidth) : - BaseType(grid, /*size=*/math::Pow3(2 * halfWidth + 1)), - mHalfWidth(halfWidth) - { - assert(halfWidth>0); - } - - inline const ValueType& getCenterValue() const { return mStencil[(mStencil.size()-1)>>1]; } - - /// @brief Initialize the stencil buffer with the values of voxel (x, y, z) - /// and its neighbors. - inline void moveTo(const Coord& ijk) - { - BaseType::mCenter = ijk; - this->init(ijk); - } - /// @brief Initialize the stencil buffer with the values of voxel - /// (x, y, z) and its neighbors. - template - inline void moveTo(const IterType& iter) - { - BaseType::mCenter = iter.getCoord(); - this->init(BaseType::mCenter); - } - -private: - /// Initialize the stencil buffer centered at (i, j, k). - /// @warning The center point is NOT at mStencil[0] for this DenseStencil! - inline void init(const Coord& ijk) - { - int n = 0; - for (Coord p=ijk.offsetBy(-mHalfWidth), q=ijk.offsetBy(mHalfWidth); p[0] <= q[0]; ++p[0]) { - for (p[1] = ijk[1]-mHalfWidth; p[1] <= q[1]; ++p[1]) { - for (p[2] = ijk[2]-mHalfWidth; p[2] <= q[2]; ++p[2]) { - mStencil[n++] = mCache.getValue(p); - } - } - } - } - - template friend class BaseStencil; // allow base class to call init() - using BaseType::mCache; - using BaseType::mStencil; - const int mHalfWidth; -}; - - -} // end math namespace -} // namespace OPENVDB_VERSION_NAME -} // end openvdb namespace - -#endif // OPENVDB_MATH_STENCILS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Transform.cc b/openvdb_3_0_0_library/math/Transform.cc deleted file mode 100755 index f0deea9..0000000 --- a/openvdb_3_0_0_library/math/Transform.cc +++ /dev/null @@ -1,574 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Transform.h" -#include "LegacyFrustum.h" - -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - - -//////////////////////////////////////// - - -Transform::Transform(const MapBase::Ptr& map): - mMap(boost::const_pointer_cast(map)) -{ - // auto-convert to simplest type - if (!mMap->isType() && mMap->isLinear()) { - AffineMap::Ptr affine = mMap->getAffineMap(); - mMap = simplify(affine); - } -} - -Transform::Transform(const Transform& other): - mMap(boost::const_pointer_cast(other.baseMap())) -{ -} - - -//////////////////////////////////////// - - -// Factory methods - -Transform::Ptr -Transform::createLinearTransform(double voxelDim) -{ - return Transform::Ptr(new Transform( - MapBase::Ptr(new UniformScaleMap(voxelDim)))); -} - -Transform::Ptr -Transform::createLinearTransform(const Mat4R& m) -{ - return Transform::Ptr(new Transform(MapBase::Ptr(new AffineMap(m)))); -} - -Transform::Ptr -Transform::createFrustumTransform(const BBoxd& bbox, double taper, - double depth, double voxelDim) -{ - return Transform::Ptr(new Transform( - NonlinearFrustumMap(bbox, taper, depth).preScale(Vec3d(voxelDim, voxelDim, voxelDim)))); -} - - -//////////////////////////////////////// - - -void -Transform::read(std::istream& is) -{ - // Read the type name. - Name type = readString(is); - - if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NEW_TRANSFORM) { - // Handle old-style transforms. - - if (type == "LinearTransform") { - // First read in the old transform's base class. - Coord tmpMin, tmpMax; - is.read(reinterpret_cast(&tmpMin), sizeof(Coord::ValueType) * 3); - is.read(reinterpret_cast(&tmpMax), sizeof(Coord::ValueType) * 3); - - // Second read in the old linear transform - Mat4d tmpLocalToWorld, tmpWorldToLocal, tmpVoxelToLocal, tmpLocalToVoxel; - - tmpLocalToWorld.read(is); - tmpWorldToLocal.read(is); - tmpVoxelToLocal.read(is); - tmpLocalToVoxel.read(is); - - // Convert and simplify - AffineMap::Ptr affineMap(new AffineMap(tmpVoxelToLocal*tmpLocalToWorld)); - mMap = simplify(affineMap); - - } else if (type == "FrustumTransform") { - - internal::LegacyFrustum legacyFrustum(is); - - CoordBBox bb = legacyFrustum.getBBox(); - BBoxd bbox(bb.min().asVec3d(), bb.max().asVec3d() - /* -Vec3d(1,1,1) */ - ); - double taper = legacyFrustum.getTaper(); - double depth = legacyFrustum.getDepth(); - - double nearPlaneWidth = legacyFrustum.getNearPlaneWidth(); - double nearPlaneDist = legacyFrustum.getNearPlaneDist(); - const Mat4d& camxform = legacyFrustum.getCamXForm(); - - // create the new frustum with these parameters - Mat4d xform(Mat4d::identity()); - xform.setToTranslation(Vec3d(0,0, -nearPlaneDist)); - xform.preScale(Vec3d(nearPlaneWidth, nearPlaneWidth, -nearPlaneWidth)); - - // create the linear part of the frustum (the second map) - Mat4d second = xform * camxform; - - // we might have precision problems, the constructor for the - // affine map is not forgiving (so we fix here). - const Vec4d col3 = second.col(3); - const Vec4d ref(0, 0, 0, 1); - - if (ref.eq(col3) ) { - second.setCol(3, ref); - } - - MapBase::Ptr linearMap(simplify(AffineMap(second).getAffineMap())); - - // note that the depth is scaled on the nearPlaneSize. - // the linearMap will uniformly scale the frustum to the correct size - // and rotate to align with the camera - mMap = MapBase::Ptr(new NonlinearFrustumMap( - bbox, taper, depth/nearPlaneWidth, linearMap)); - - } else { - OPENVDB_THROW(IoError, "Transforms of type " + type + " are no longer supported"); - } - } else { - // Check if the map has been registered. - if (!MapRegistry::isRegistered(type)) { - OPENVDB_THROW(KeyError, "Map " << type << " is not registered"); - } - - // Create the map of the type and then read it in. - mMap = math::MapRegistry::createMap(type); - mMap->read(is); - } -} - - -void -Transform::write(std::ostream& os) const -{ - if (!mMap) OPENVDB_THROW(IoError, "Transform does not have a map"); - - // Write the type-name of the map. - writeString(os, mMap->type()); - - mMap->write(os); -} - - -//////////////////////////////////////// - - -bool -Transform::isIdentity() const -{ - if (mMap->isLinear()) { - return mMap->getAffineMap()->isIdentity(); - } else if ( mMap->isType() ) { - NonlinearFrustumMap::Ptr frustum - = boost::static_pointer_cast(mMap); - return frustum->isIdentity(); - } - // unknown nonlinear map type - return false; -} - - -//////////////////////////////////////// - - -void -Transform::preRotate(double radians, const Axis axis) -{ - mMap = mMap->preRotate(radians, axis); -} - -void -Transform::preTranslate(const Vec3d& t) -{ - mMap = mMap->preTranslate(t); -} - -void -Transform::preScale(const Vec3d& s) -{ - mMap = mMap->preScale(s); -} - -void -Transform::preScale(double s) -{ - const Vec3d vec(s,s,s); - mMap = mMap->preScale(vec); -} - -void -Transform::preShear(double shear, Axis axis0, Axis axis1) -{ - mMap = mMap->preShear(shear, axis0, axis1); -} - -void -Transform::preMult(const Mat4d& m) -{ - if (mMap->isLinear()) { - - const Mat4d currentMat4 = mMap->getAffineMap()->getMat4(); - const Mat4d newMat4 = m * currentMat4; - - AffineMap::Ptr affineMap( new AffineMap( newMat4) ); - mMap = simplify(affineMap); - - } else if (mMap->isType() ) { - - NonlinearFrustumMap::Ptr currentFrustum = - boost::static_pointer_cast(mMap); - - const Mat4d currentMat4 = currentFrustum->secondMap().getMat4(); - const Mat4d newMat4 = m * currentMat4; - - AffineMap affine(newMat4); - - NonlinearFrustumMap::Ptr frustum( new NonlinearFrustumMap( currentFrustum->getBBox(), - currentFrustum->getTaper(), - currentFrustum->getDepth(), - affine.copy() ) ); - mMap = boost::static_pointer_cast( frustum ); - } - -} - -void -Transform::preMult(const Mat3d& m) -{ - Mat4d mat4 = Mat4d::identity(); - mat4.setMat3(m); - preMult(mat4); -} - -void -Transform::postRotate(double radians, const Axis axis) -{ - mMap = mMap->postRotate(radians, axis); -} - -void -Transform::postTranslate(const Vec3d& t) -{ - mMap = mMap->postTranslate(t); -} - -void -Transform::postScale(const Vec3d& s) -{ - mMap = mMap->postScale(s); -} - -void -Transform::postScale(double s) -{ - const Vec3d vec(s,s,s); - mMap = mMap->postScale(vec); -} - -void -Transform::postShear(double shear, Axis axis0, Axis axis1) -{ - mMap = mMap->postShear(shear, axis0, axis1); -} - - -void -Transform::postMult(const Mat4d& m) -{ - if (mMap->isLinear()) { - - const Mat4d currentMat4 = mMap->getAffineMap()->getMat4(); - const Mat4d newMat4 = currentMat4 * m; - - AffineMap::Ptr affineMap( new AffineMap( newMat4) ); - mMap = simplify(affineMap); - - } else if (mMap->isType() ) { - - NonlinearFrustumMap::Ptr currentFrustum = - boost::static_pointer_cast(mMap); - - const Mat4d currentMat4 = currentFrustum->secondMap().getMat4(); - const Mat4d newMat4 = currentMat4 * m; - - AffineMap affine(newMat4); - - NonlinearFrustumMap::Ptr frustum( new NonlinearFrustumMap( currentFrustum->getBBox(), - currentFrustum->getTaper(), - currentFrustum->getDepth(), - affine.copy() ) ); - mMap = boost::static_pointer_cast( frustum ); - } - -} - -void -Transform::postMult(const Mat3d& m) -{ - Mat4d mat4 = Mat4d::identity(); - mat4.setMat3(m); - postMult(mat4); -} - - -//////////////////////////////////////// - - -BBoxd -Transform::indexToWorld(const CoordBBox& indexBBox) const -{ - return this->indexToWorld(BBoxd(indexBBox.min().asVec3d(), indexBBox.max().asVec3d())); -} - - -BBoxd -Transform::indexToWorld(const BBoxd& indexBBox) const -{ - const Vec3d &imin = indexBBox.min(), &imax = indexBBox.max(); - - Vec3d corners[8]; - corners[0] = imin; - corners[1] = Vec3d(imax(0), imin(1), imin(2)); - corners[2] = Vec3d(imax(0), imax(1), imin(2)); - corners[3] = Vec3d(imin(0), imax(1), imin(2)); - corners[4] = Vec3d(imin(0), imin(1), imax(2)); - corners[5] = Vec3d(imax(0), imin(1), imax(2)); - corners[6] = imax; - corners[7] = Vec3d(imin(0), imax(1), imax(2)); - - BBoxd worldBBox; - Vec3d &wmin = worldBBox.min(), &wmax = worldBBox.max(); - - wmin = wmax = this->indexToWorld(corners[0]); - for (int i = 1; i < 8; ++i) { - Vec3d image = this->indexToWorld(corners[i]); - wmin = minComponent(wmin, image); - wmax = maxComponent(wmax, image); - } - return worldBBox; -} - - -BBoxd -Transform::worldToIndex(const BBoxd& worldBBox) const -{ - Vec3d indexMin, indexMax; - calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax); - return BBoxd(indexMin, indexMax); -} - - -CoordBBox -Transform::worldToIndexCellCentered(const BBoxd& worldBBox) const -{ - Vec3d indexMin, indexMax; - calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax); - return CoordBBox(Coord::round(indexMin), Coord::round(indexMax)); -} - - -CoordBBox -Transform::worldToIndexNodeCentered(const BBoxd& worldBBox) const -{ - Vec3d indexMin, indexMax; - calculateBounds(*this, worldBBox.min(), worldBBox.max(), indexMin, indexMax); - return CoordBBox(Coord::floor(indexMin), Coord::floor(indexMax)); -} - - -//////////////////////////////////////// - -// Utility methods - -void -calculateBounds(const Transform& t, - const Vec3d& minWS, - const Vec3d& maxWS, - Vec3d& minIS, - Vec3d& maxIS) -{ - /// the pre-image of the 8 corners of the box - Vec3d corners[8]; - corners[0] = minWS; - corners[1] = Vec3d(maxWS(0), minWS(1), minWS(2)); - corners[2] = Vec3d(maxWS(0), maxWS(1), minWS(2)); - corners[3] = Vec3d(minWS(0), maxWS(1), minWS(2)); - corners[4] = Vec3d(minWS(0), minWS(1), maxWS(2)); - corners[5] = Vec3d(maxWS(0), minWS(1), maxWS(2)); - corners[6] = maxWS; - corners[7] = Vec3d(minWS(0), maxWS(1), maxWS(2)); - - Vec3d pre_image; - minIS = t.worldToIndex(corners[0]); - maxIS = minIS; - for (int i = 1; i < 8; ++i) { - pre_image = t.worldToIndex(corners[i]); - for (int j = 0; j < 3; ++j) { - minIS(j) = std::min(minIS(j), pre_image(j)); - maxIS(j) = std::max(maxIS(j), pre_image(j)); - } - } -} - - -//////////////////////////////////////// - - -bool -Transform::operator==(const Transform& other) const -{ - if (!this->voxelSize().eq(other.voxelSize())) return false; - - if (this->mapType() == other.mapType()) { - return this->baseMap()->isEqual(*other.baseMap()); - } - - if (this->isLinear() && other.isLinear()) { - // promote both maps to mat4 form and compare - return ( *(this->baseMap()->getAffineMap()) == - *(other.baseMap()->getAffineMap()) ); - } - - return this->baseMap()->isEqual(*other.baseMap()); -} - - -//////////////////////////////////////// - - -void -Transform::print(std::ostream& os, const std::string& indent) const -{ - struct Local { - // Print a Vec4d more compactly than Vec4d::str() does. - static std::string rowAsString(const Vec4d& row) - { - std::ostringstream ostr; - ostr << "[" << std::setprecision(3) << row[0] << ", " - << row[1] << ", " << row[2] << ", " << row[3] << "] "; - return ostr.str(); - } - }; - - // Write to a string stream so that I/O manipulators don't affect the output stream. - std::ostringstream ostr; - - { - Vec3d dim = this->voxelSize(); - if (dim.eq(Vec3d(dim[0]))) { - ostr << indent << std::left << "voxel size: " << std::setprecision(3) << dim[0]; - } else { - ostr << indent << std::left << "voxel dimensions: [" << std::setprecision(3) - << dim[0] << ", " << dim[1] << ", " << dim[2] << "]"; - } - ostr << "\n"; - } - - if (this->isLinear()) { - openvdb::Mat4R v2w = this->baseMap()->getAffineMap()->getMat4(); - - ostr << indent << std::left << "index to world:\n"; - for (int row = 0; row < 4; ++row) { - ostr << indent << " " << std::left << Local::rowAsString(v2w[row]) << "\n"; - } - - } else if (this->mapType() == NonlinearFrustumMap::mapType()) { - const NonlinearFrustumMap& frustum = - static_cast(*this->baseMap()); - const openvdb::Mat4R linear = this->baseMap()->getAffineMap()->getMat4(); - - std::vector linearRow; - size_t w = 0; - for (int row = 0; row < 4; ++row) { - std::string str = Local::rowAsString(linear[row]); - w = std::max(w, str.size()); - linearRow.push_back(str); - } - w = std::max(w, 30); - const int iw = int(w); - - // Print rows of the linear component matrix side-by-side with frustum parameters. - ostr << indent << std::left << std::setw(iw) << "linear:" - << " frustum:\n"; - ostr << indent << " " << std::left << std::setw(iw) << linearRow[0] - << " taper: " << frustum.getTaper() << "\n"; - ostr << indent << " " << std::left << std::setw(iw) << linearRow[1] - << " depth: " << frustum.getDepth() << "\n"; - - std::ostringstream ostmp; - ostmp << indent << " " << std::left << std::setw(iw) << linearRow[2] - << " bounds: " << frustum.getBBox(); - if (ostmp.str().size() < 79) { - ostr << ostmp.str() << "\n"; - ostr << indent << " " << std::left << std::setw(iw) << linearRow[3] << "\n"; - } else { - // If the frustum bounding box doesn't fit on one line, split it into two lines. - ostr << indent << " " << std::left << std::setw(iw) << linearRow[2] - << " bounds: " << frustum.getBBox().min() << " ->\n"; - ostr << indent << " " << std::left << std::setw(iw) << linearRow[3] - << " " << frustum.getBBox().max() << "\n"; - } - - } else { - /// @todo Handle other map types. - } - - os << ostr.str(); -} - - -//////////////////////////////////////// - - -std::ostream& -operator<<(std::ostream& os, const Transform& t) -{ - os << "Transform type: " << t.baseMap()->type() << std::endl; - os << t.baseMap()->str() << std::endl; - return os; -} - - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Transform.h b/openvdb_3_0_0_library/math/Transform.h deleted file mode 100755 index 337926f..0000000 --- a/openvdb_3_0_0_library/math/Transform.h +++ /dev/null @@ -1,310 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_TRANSFORM_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_TRANSFORM_HAS_BEEN_INCLUDED - -#include "Maps.h" -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -// Forward declaration -class Transform; - - -// Utility methods - -/// @brief Calculate an axis-aligned bounding box in index space from an -/// axis-aligned bounding box in world space. -/// @see Transform::worldToIndex(const BBoxd&) const -OPENVDB_API void -calculateBounds(const Transform& t, const Vec3d& minWS, const Vec3d& maxWS, - Vec3d& minIS, Vec3d& maxIS); - -/// @brief Calculate an axis-aligned bounding box in index space from a -/// bounding sphere in world space. -/// @todo void calculateBounds(const Transform& t, const Vec3d& center, const Real radius, -/// Vec3d& minIS, Vec3d& maxIS); - - -//////////////////////////////////////// - - -/// @class Transform -class OPENVDB_API Transform -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - Transform(): mMap(MapBase::Ptr(new ScaleMap())) {} - Transform(const MapBase::Ptr&); - Transform(const Transform&); - ~Transform() {} - - Ptr copy() const { return Ptr(new Transform(mMap->copy())); } - - //@{ - /// @brief Create and return a shared pointer to a new transform. - static Transform::Ptr createLinearTransform(double voxelSize = 1.0); - static Transform::Ptr createLinearTransform(const Mat4R&); - static Transform::Ptr createFrustumTransform(const BBoxd&, double taper, - double depth, double voxelSize = 1.0); - //@} - - /// Return @c true if the transformation map is exclusively linear/affine. - bool isLinear() const { return mMap->isLinear(); } - - /// Return @c true if the transform is equivalent to an idenity. - bool isIdentity() const ; - /// Return the transformation map's type-name - Name mapType() const { return mMap->type(); } - - - //@{ - /// @brief Update the linear (affine) map by prepending or - /// postfixing the appropriate operation. In the case of - /// a frustum, the pre-operations apply to the linear part - /// of the transform and not the entire transform, while the - /// post-operations are allways applied last. - void preRotate(double radians, const Axis axis = X_AXIS); - void preTranslate(const Vec3d&); - void preScale(const Vec3d&); - void preScale(double); - void preShear(double shear, Axis axis0, Axis axis1); - void preMult(const Mat4d&); - void preMult(const Mat3d&); - - void postRotate(double radians, const Axis axis = X_AXIS); - void postTranslate(const Vec3d&); - void postScale(const Vec3d&); - void postScale(double); - void postShear(double shear, Axis axis0, Axis axis1); - void postMult(const Mat4d&); - void postMult(const Mat3d&); - //@} - - /// Return the size of a voxel using the linear component of the map. - Vec3d voxelSize() const { return mMap->voxelSize(); } - /// @brief Return the size of a voxel at position (x, y, z). - /// @note Maps that have a nonlinear component (e.g., perspective and frustum maps) - /// have position-dependent voxel sizes. - Vec3d voxelSize(const Vec3d& xyz) const { return mMap->voxelSize(xyz); } - - /// Return the voxel volume of the linear component of the map. - double voxelVolume() const { return mMap->determinant(); } - /// Return the voxel volume at position (x, y, z). - double voxelVolume(const Vec3d& xyz) const { return mMap->determinant(xyz); } - /// Return true if the voxels in world space are uniformly sized cubes - bool hasUniformScale() const { return mMap->hasUniformScale(); } - - //@{ - /// @brief Apply this transformation to the given coordinates. - Vec3d indexToWorld(const Vec3d& xyz) const { return mMap->applyMap(xyz); } - Vec3d indexToWorld(const Coord& ijk) const { return mMap->applyMap(ijk.asVec3d()); } - Vec3d worldToIndex(const Vec3d& xyz) const { return mMap->applyInverseMap(xyz); } - Coord worldToIndexCellCentered(const Vec3d& xyz) const {return Coord::round(worldToIndex(xyz));} - Coord worldToIndexNodeCentered(const Vec3d& xyz) const {return Coord::floor(worldToIndex(xyz));} - //@} - - //@{ - /// @brief Apply this transformation to the given index-space bounding box. - /// @return an axis-aligned world-space bounding box - BBoxd indexToWorld(const CoordBBox&) const; - BBoxd indexToWorld(const BBoxd&) const; - //@} - //@{ - /// @brief Apply the inverse of this transformation to the given world-space bounding box. - /// @return an axis-aligned index-space bounding box - BBoxd worldToIndex(const BBoxd&) const; - CoordBBox worldToIndexCellCentered(const BBoxd&) const; - CoordBBox worldToIndexNodeCentered(const BBoxd&) const; - //@} - - //@{ - /// Return a base pointer to the transformation map. - MapBase::ConstPtr baseMap() const { return mMap; } - MapBase::Ptr baseMap() { return mMap; } - //@} - - //@{ - /// @brief Return the result of downcasting the base map pointer to a - /// @c MapType pointer, or return a null pointer if the types are incompatible. - template typename MapType::Ptr map(); - template typename MapType::ConstPtr map() const; - template typename MapType::ConstPtr constMap() const; - //@} - - /// Unserialize this transform from the given stream. - void read(std::istream&); - /// Serialize this transform to the given stream. - void write(std::ostream&) const; - - /// @brief Print a description of this transform. - /// @param os a stream to which to write textual information - /// @param indent a string with which to prefix each line of text - void print(std::ostream& os = std::cout, const std::string& indent = "") const; - - bool operator==(const Transform& other) const; - inline bool operator!=(const Transform& other) const { return !(*this == other); } - -private: - MapBase::Ptr mMap; -}; // class Transform - - -OPENVDB_API std::ostream& operator<<(std::ostream&, const Transform&); - - -//////////////////////////////////////// - - -template -inline typename MapType::Ptr -Transform::map() -{ - if (mMap->type() == MapType::mapType()) { - return boost::static_pointer_cast(mMap); - } - return typename MapType::Ptr(); -} - - -template -inline typename MapType::ConstPtr -Transform::map() const -{ - return boost::const_pointer_cast( - const_cast(this)->map()); -} - - -template -inline typename MapType::ConstPtr -Transform::constMap() const -{ - return map(); -} - - -//////////////////////////////////////// - - -/// Helper function used internally by processTypedMap() -template -inline void -doProcessTypedMap(Transform& transform, OpType& op) -{ - ResolvedMapType& resolvedMap = *transform.map(); -#ifdef _MSC_VER - op.operator()(resolvedMap); -#else - op.template operator()(resolvedMap); -#endif -} - -/// Helper function used internally by processTypedMap() -template -inline void -doProcessTypedMap(const Transform& transform, OpType& op) -{ - const ResolvedMapType& resolvedMap = *transform.map(); -#ifdef _MSC_VER - op.operator()(resolvedMap); -#else - op.template operator()(resolvedMap); -#endif -} - - -/// @brief Utility function that, given a generic map pointer, -/// calls a functor on the fully-resoved map -/// -/// Usage: -/// @code -/// struct Foo { -/// template -/// void operator()(const MapT& map) const { blah } -/// }; -/// -/// processTypedMap(myMap, Foo()); -/// @endcode -/// -/// @return @c false if the grid type is unknown or unhandled. -template -bool -processTypedMap(TransformType& transform, OpType& op) -{ - using namespace openvdb; - - const Name mapType = transform.mapType(); - if (mapType == UniformScaleMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == UniformScaleTranslateMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == ScaleMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == ScaleTranslateMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == UnitaryMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == AffineMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == TranslationMap::mapType()) { - doProcessTypedMap(transform, op); - - } else if (mapType == NonlinearFrustumMap::mapType()) { - doProcessTypedMap(transform, op); - } else { - return false; - } - return true; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_TRANSFORM_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Tuple.h b/openvdb_3_0_0_library/math/Tuple.h deleted file mode 100755 index 1004e7c..0000000 --- a/openvdb_3_0_0_library/math/Tuple.h +++ /dev/null @@ -1,212 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Tuple.h -/// @author Ben Kwa - -#ifndef OPENVDB_MATH_TUPLE_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_TUPLE_HAS_BEEN_INCLUDED - -#include -#include -#include "Math.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -/// @class Tuple "Tuple.h" -/// A base class for homogenous tuple types -template -class Tuple { -public: - typedef T value_type; - typedef T ValueType; - - static const int size = SIZE; - - /// Default ctor. Does nothing. Required because declaring a copy (or - /// other) constructor means the default constructor gets left out. - Tuple() {} - - /// Copy constructor. Used when the class signature matches exactly. - inline Tuple(Tuple const &src) { - for (int i = 0; i < SIZE; ++i) { - mm[i] = src.mm[i]; - } - } - - /// Conversion constructor. Tuples with different value types and - /// different sizes can be interconverted using this member. Converting - /// from a larger tuple results in truncation; converting from a smaller - /// tuple results in the extra data members being zeroed out. This - /// function assumes that the integer 0 is convertible to the tuple's - /// value type. - template - explicit Tuple(Tuple const &src) { - enum { COPY_END = (SIZE < src_size ? SIZE : src_size) }; - - for (int i = 0; i < COPY_END; ++i) { - mm[i] = src[i]; - } - for (int i = COPY_END; i < SIZE; ++i) { - mm[i] = 0; - } - } - - T operator[](int i) const { - // we'd prefer to use size_t, but can't because gcc3.2 doesn't like - // it - it conflicts with child class conversion operators to - // pointer types. -// assert(i >= 0 && i < SIZE); - return mm[i]; - } - - T& operator[](int i) { - // see above for size_t vs int -// assert(i >= 0 && i < SIZE); - return mm[i]; - } - - /// @name Compatibility - /// These are mostly for backwards compability with functions that take - /// old-style Vs (which are just arrays). - //@{ - /// Copies this tuple into an array of a compatible type - template - void toV(S *v) const { - for (int i = 0; i < SIZE; ++i) { - v[i] = mm[i]; - } - } - - /// Exposes the internal array. Be careful when using this function. - value_type *asV() { - return mm; - } - /// Exposes the internal array. Be careful when using this function. - value_type const *asV() const { - return mm; - } - //@} Compatibility - - /// @return string representation of Classname - std::string - str() const { - std::ostringstream buffer; - - buffer << "["; - - // For each column - for (unsigned j(0); j < SIZE; j++) { - if (j) buffer << ", "; - buffer << mm[j]; - } - - buffer << "]"; - - return buffer.str(); - } - - void write(std::ostream& os) const { - os.write(reinterpret_cast(&mm), sizeof(T)*SIZE); - } - void read(std::istream& is) { - is.read(reinterpret_cast(&mm), sizeof(T)*SIZE); - } - -protected: - T mm[SIZE]; -}; - - -//////////////////////////////////////// - - -/// @return true if t0 < t1, comparing components in order of significance. -template -bool -operator<(const Tuple& t0, const Tuple& t1) -{ - for (int i = 0; i < SIZE-1; ++i) { - if (!isExactlyEqual(t0[i], t1[i])) return t0[i] < t1[i]; - } - return t0[SIZE-1] < t1[SIZE-1]; -} - - -/// @return true if t0 > t1, comparing components in order of significance. -template -bool -operator>(const Tuple& t0, const Tuple& t1) -{ - for (int i = 0; i < SIZE-1; ++i) { - if (!isExactlyEqual(t0[i], t1[i])) return t0[i] > t1[i]; - } - return t0[SIZE-1] > t1[SIZE-1]; -} - - -//////////////////////////////////////// - - -/// @return the absolute value of the given Tuple. -template -Tuple -Abs(const Tuple& t) -{ - Tuple result; - for (int i = 0; i < SIZE; ++i) result[i] = math::Abs(t[i]); - return result; -} - - -//////////////////////////////////////// - - -/// Write a Tuple to an output stream -template -std::ostream& operator<<(std::ostream& ostr, const Tuple& classname) -{ - ostr << classname.str(); - return ostr; -} - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_TUPLE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Vec2.h b/openvdb_3_0_0_library/math/Vec2.h deleted file mode 100755 index 6808919..0000000 --- a/openvdb_3_0_0_library/math/Vec2.h +++ /dev/null @@ -1,531 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_VEC2_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_VEC2_HAS_BEEN_INCLUDED - -#include -#include -#include "Math.h" -#include "Tuple.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Mat2; - -template -class Vec2: public Tuple<2, T> -{ -public: - typedef T value_type; - typedef T ValueType; - - /// Trivial constructor, the vector is NOT initialized - Vec2() {} - - /// Constructor with one argument, e.g. Vec2f v(0); - explicit Vec2(T val) { this->mm[0] = this->mm[1] = val; } - - /// Constructor with three arguments, e.g. Vec2f v(1,2,3); - Vec2(T x, T y) - { - this->mm[0] = x; - this->mm[1] = y; - } - - /// Constructor with array argument, e.g. float a[2]; Vec2f v(a); - template - Vec2(Source *a) - { - this->mm[0] = a[0]; - this->mm[1] = a[1]; - } // trivial - - /// Conversion constructor - template - explicit Vec2(const Tuple<2, Source> &t) - { - this->mm[0] = static_cast(t[0]); - this->mm[1] = static_cast(t[1]); - } - - /// Reference to the component, e.g. v.x() = 4.5f; - T& x() {return this->mm[0];} - T& y() {return this->mm[1];} - - /// Get the component, e.g. float f = v.y(); - T x() const {return this->mm[0];} - T y() const {return this->mm[1];} - - /// Alternative indexed reference to the elements - T& operator()(int i) {return this->mm[i];} - - /// Alternative indexed constant reference to the elements, - T operator()(int i) const {return this->mm[i];} - - T* asPointer() {return this->mm;} - const T* asPointer() const {return this->mm;} - - /// "this" vector gets initialized to [x, y, z], - /// calling v.init(); has same effect as calling v = Vec2::zero(); - const Vec2& init(T x=0, T y=0) - { - this->mm[0] = x; this->mm[1] = y; - return *this; - } - - /// Set "this" vector to zero - const Vec2& setZero() - { - this->mm[0] = 0; this->mm[1] = 0; - return *this; - } - - /// Assignment operator - template - const Vec2& operator=(const Vec2 &v) - { - // note: don't static_cast because that suppresses warnings - this->mm[0] = v[0]; - this->mm[1] = v[1]; - - return *this; - } - - /// Equality operator, does exact floating point comparisons - bool operator==(const Vec2 &v) const - { - return (isExactlyEqual(this->mm[0], v.mm[0]) && isExactlyEqual(this->mm[1], v.mm[1])); - } - - /// Inequality operator, does exact floating point comparisons - bool operator!=(const Vec2 &v) const { return !(*this==v); } - - /// Test if "this" vector is equivalent to vector v with tolerance of eps - bool eq(const Vec2 &v, T eps = static_cast(1.0e-7)) const - { - return isApproxEqual(this->mm[0], v.mm[0], eps) && - isApproxEqual(this->mm[1], v.mm[1], eps); - } // trivial - - /// Negation operator, for e.g. v1 = -v2; - Vec2 operator-() const {return Vec2(-this->mm[0], -this->mm[1]);} - - /// this = v1 + v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.add(v1,v); - template - const Vec2& add(const Vec2 &v1, const Vec2 &v2) - { - this->mm[0] = v1[0] + v2[0]; - this->mm[1] = v1[1] + v2[1]; - - return *this; - } - - /// this = v1 - v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.sub(v1,v); - template - const Vec2& sub(const Vec2 &v1, const Vec2 &v2) - { - this->mm[0] = v1[0] - v2[0]; - this->mm[1] = v1[1] - v2[1]; - - return *this; - } - - /// this = scalar*v, v need not be a distinct object from "this", - /// e.g. v.scale(1.5,v1); - template - const Vec2& scale(T0 scalar, const Vec2 &v) - { - this->mm[0] = scalar * v[0]; - this->mm[1] = scalar * v[1]; - - return *this; - } - - template - const Vec2 &div(T0 scalar, const Vec2 &v) - { - this->mm[0] = v[0] / scalar; - this->mm[1] = v[1] / scalar; - - return *this; - } - - /// Dot product - T dot(const Vec2 &v) const { return this->mm[0]*v[0] + this->mm[1]*v[1]; } // trivial - - /// Length of the vector - T length() const - { - return static_cast(sqrt(double(this->mm[0]*this->mm[0] + this->mm[1]*this->mm[1]))); - } - - /// Squared length of the vector, much faster than length() as it - /// does not involve square root - T lengthSqr() const { return (this->mm[0]*this->mm[0] + this->mm[1]*this->mm[1]); } - - /// Return a reference to itsef after the exponent has been - /// applied to all the vector components. - inline const Vec2& exp() - { - this->mm[0] = std::exp(this->mm[0]); - this->mm[1] = std::exp(this->mm[1]); - return *this; - } - - /// Return the sum of all the vector components. - inline T sum() const - { - return this->mm[0] + this->mm[1]; - } - - /// this = normalized this - bool normalize(T eps=1.0e-8) - { - T d = length(); - if (isApproxEqual(d, T(0), eps)) { - return false; - } - *this *= (T(1) / d); - return true; - } - - /// return normalized this, throws if null vector - Vec2 unit(T eps=0) const - { - T d; - return unit(eps, d); - } - - /// return normalized this and length, throws if null vector - Vec2 unit(T eps, T& len) const - { - len = length(); - if (isApproxEqual(len, T(0), eps)) { - OPENVDB_THROW(ArithmeticError, "Normalizing null 2-vector"); - } - return *this / len; - } - - /// Returns v, where \f$v_i *= scalar\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator*=(S scalar) - { - this->mm[0] *= scalar; - this->mm[1] *= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i *= v1_i\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator*=(const Vec2 &v1) - { - this->mm[0] *= v1[0]; - this->mm[1] *= v1[1]; - return *this; - } - - /// Returns v, where \f$v_i /= scalar\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator/=(S scalar) - { - this->mm[0] /= scalar; - this->mm[1] /= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i /= v1_i\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator/=(const Vec2 &v1) - { - this->mm[0] /= v1[0]; - this->mm[1] /= v1[1]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator+=(S scalar) - { - this->mm[0] += scalar; - this->mm[1] += scalar; - return *this; - } - - /// Returns v0, where \f$v0_i += v1_i\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator+=(const Vec2 &v1) - { - this->mm[0] += v1[0]; - this->mm[1] += v1[1]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator-=(S scalar) - { - this->mm[0] -= scalar; - this->mm[1] -= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i -= v1_i\f$ for \f$i \in [0, 1]\f$ - template - const Vec2 &operator-=(const Vec2 &v1) - { - this->mm[0] -= v1[0]; - this->mm[1] -= v1[1]; - return *this; - } - - // Number of cols, rows, elements - static unsigned numRows() { return 1; } - static unsigned numColumns() { return 2; } - static unsigned numElements() { return 2; } - - /// Returns the scalar component of v in the direction of onto, onto need - /// not be unit. e.g float c = Vec2f::component(v1,v2); - T component(const Vec2 &onto, T eps=1.0e-8) const - { - T l = onto.length(); - if (isApproxEqual(l, T(0), eps)) return 0; - - return dot(onto)*(T(1)/l); - } - - /// Return the projection of v onto the vector, onto need not be unit - /// e.g. Vec2f v = Vec2f::projection(v,n); - Vec2 projection(const Vec2 &onto, T eps=1.0e-8) const - { - T l = onto.lengthSqr(); - if (isApproxEqual(l, T(0), eps)) return Vec2::zero(); - - return onto*(dot(onto)*(T(1)/l)); - } - - /// Return an arbitrary unit vector perpendicular to v - /// Vector v must be a unit vector - /// e.g. v.normalize(); Vec2f n = Vec2f::getArbPerpendicular(v); - Vec2 getArbPerpendicular() const { return Vec2(-this->mm[1], this->mm[0]); } - - /// True if a Nan is present in vector - bool isNan() const { return isnan(this->mm[0]) || isnan(this->mm[1]); } - - /// True if an Inf is present in vector - bool isInfinite() const { return isinf(this->mm[0]) || isinf(this->mm[1]); } - - /// True if all no Nan or Inf values present - bool isFinite() const { return finite(this->mm[0]) && finite(this->mm[1]); } - - /// Predefined constants, e.g. Vec2f v = Vec2f::xNegAxis(); - static Vec2 zero() { return Vec2(0, 0); } -}; - - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator*(S scalar, const Vec2 &v) -{ - return v * scalar; -} - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator*(const Vec2 &v, S scalar) -{ - Vec2::type> result(v); - result *= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i * v1_i\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator*(const Vec2 &v0, const Vec2 &v1) -{ - Vec2::type> result(v0[0] * v1[0], v0[1] * v1[1]); - return result; -} - -/// Returns V, where \f$V_i = scalar / v_i\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator/(S scalar, const Vec2 &v) -{ - return Vec2::type>(scalar/v[0], scalar/v[1]); -} - -/// Returns V, where \f$V_i = v_i / scalar\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator/(const Vec2 &v, S scalar) -{ - Vec2::type> result(v); - result /= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i / v1_i\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator/(const Vec2 &v0, const Vec2 &v1) -{ - Vec2::type> result(v0[0] / v1[0], v0[1] / v1[1]); - return result; -} - -/// Returns V, where \f$V_i = v0_i + v1_i\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator+(const Vec2 &v0, const Vec2 &v1) -{ - Vec2::type> result(v0); - result += v1; - return result; -} - -/// Returns V, where \f$V_i = v_i + scalar\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator+(const Vec2 &v, S scalar) -{ - Vec2::type> result(v); - result += scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i - v1_i\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator-(const Vec2 &v0, const Vec2 &v1) -{ - Vec2::type> result(v0); - result -= v1; - return result; -} - -/// Returns V, where \f$V_i = v_i - scalar\f$ for \f$i \in [0, 1]\f$ -template -inline Vec2::type> operator-(const Vec2 &v, S scalar) -{ - Vec2::type> result(v); - result -= scalar; - return result; -} - -/// Angle between two vectors, the result is between [0, pi], -/// e.g. float a = Vec2f::angle(v1,v2); -template -inline T angle(const Vec2 &v1, const Vec2 &v2) -{ - T c = v1.dot(v2); - return acos(c); -} - -template -inline bool -isApproxEqual(const Vec2& a, const Vec2& b) -{ - return a.eq(b); -} -template -inline bool -isApproxEqual(const Vec2& a, const Vec2& b, const Vec2& eps) -{ - return isApproxEqual(a.x(), b.x(), eps.x()) && - isApproxEqual(a.y(), b.y(), eps.y()); -} - -/// Orthonormalize vectors v1 and v2 and store back the resulting basis -/// e.g. Vec2f::orthonormalize(v1,v2); -template -inline void orthonormalize(Vec2 &v1, Vec2 &v2) -{ - // If the input vectors are v0, v1, and v2, then the Gram-Schmidt - // orthonormalization produces vectors u0, u1, and u2 as follows, - // - // u0 = v0/|v0| - // u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0| - // - // where |A| indicates length of vector A and A*B indicates dot - // product of vectors A and B. - - // compute u0 - v1.normalize(); - - // compute u1 - T d0 = v1.dot(v2); - v2 -= v1*d0; - v2.normalize(); -} - - -/// \remark We are switching to a more explicit name because the semantics -/// are different from std::min/max. In that case, the function returns a -/// reference to one of the objects based on a comparator. Here, we must -/// fabricate a new object which might not match either of the inputs. - -/// Return component-wise minimum of the two vectors. -template -inline Vec2 minComponent(const Vec2 &v1, const Vec2 &v2) -{ - return Vec2( - std::min(v1.x(), v2.x()), - std::min(v1.y(), v2.y())); -} - -/// Return component-wise maximum of the two vectors. -template -inline Vec2 maxComponent(const Vec2 &v1, const Vec2 &v2) -{ - return Vec2( - std::max(v1.x(), v2.x()), - std::max(v1.y(), v2.y())); -} - -/// @brief Return a vector with the exponent applied to each of -/// the components of the input vector. -template -inline Vec2 Exp(Vec2 v) { return v.exp(); } - -typedef Vec2 Vec2i; -typedef Vec2 Vec2ui; -typedef Vec2 Vec2s; -typedef Vec2 Vec2d; - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_VEC2_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Vec3.h b/openvdb_3_0_0_library/math/Vec3.h deleted file mode 100755 index fbee1c7..0000000 --- a/openvdb_3_0_0_library/math/Vec3.h +++ /dev/null @@ -1,639 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_VEC3_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_VEC3_HAS_BEEN_INCLUDED - -#include -#include -#include "Math.h" -#include "Tuple.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Mat3; - -template -class Vec3: public Tuple<3, T> -{ -public: - typedef T value_type; - typedef T ValueType; - - /// Trivial constructor, the vector is NOT initialized - Vec3() {} - - /// Constructor with one argument, e.g. Vec3f v(0); - explicit Vec3(T val) { this->mm[0] = this->mm[1] = this->mm[2] = val; } - - /// Constructor with three arguments, e.g. Vec3d v(1,2,3); - Vec3(T x, T y, T z) - { - this->mm[0] = x; - this->mm[1] = y; - this->mm[2] = z; - } - - /// Constructor with array argument, e.g. double a[3]; Vec3d v(a); - template - Vec3(Source *a) - { - this->mm[0] = a[0]; - this->mm[1] = a[1]; - this->mm[2] = a[2]; - } - - /// @brief Construct a Vec3 from a 3-Tuple with a possibly different value type. - /// @details Type conversion warnings are suppressed. - template - explicit Vec3(const Tuple<3, Source> &v) - { - this->mm[0] = static_cast(v[0]); - this->mm[1] = static_cast(v[1]); - this->mm[2] = static_cast(v[2]); - } - - /// @brief Construct a Vec3 from another Vec3 with a possibly different value type. - /// @details Type conversion warnings are suppressed. - template - Vec3(const Vec3& v) - { - this->mm[0] = static_cast(v[0]); - this->mm[1] = static_cast(v[1]); - this->mm[2] = static_cast(v[2]); - } - - /// Reference to the component, e.g. v.x() = 4.5f; - T& x() { return this->mm[0]; } - T& y() { return this->mm[1]; } - T& z() { return this->mm[2]; } - - /// Get the component, e.g. float f = v.y(); - T x() const { return this->mm[0]; } - T y() const { return this->mm[1]; } - T z() const { return this->mm[2]; } - - T* asPointer() { return this->mm; } - const T* asPointer() const { return this->mm; } - - /// Alternative indexed reference to the elements - T& operator()(int i) { return this->mm[i]; } - - /// Alternative indexed constant reference to the elements, - T operator()(int i) const { return this->mm[i]; } - - /// "this" vector gets initialized to [x, y, z], - /// calling v.init(); has same effect as calling v = Vec3::zero(); - const Vec3& init(T x=0, T y=0, T z=0) - { - this->mm[0] = x; this->mm[1] = y; this->mm[2] = z; - return *this; - } - - - /// Set "this" vector to zero - const Vec3& setZero() - { - this->mm[0] = 0; this->mm[1] = 0; this->mm[2] = 0; - return *this; - } - - /// @brief Assignment operator - /// @details Type conversion warnings are not suppressed. - template - const Vec3& operator=(const Vec3 &v) - { - // note: don't static_cast because that suppresses warnings - this->mm[0] = v[0]; - this->mm[1] = v[1]; - this->mm[2] = v[2]; - - return *this; - } - - /// Test if "this" vector is equivalent to vector v with tolerance of eps - bool eq(const Vec3 &v, T eps = static_cast(1.0e-7)) const - { - return isRelOrApproxEqual(this->mm[0], v.mm[0], eps, eps) && - isRelOrApproxEqual(this->mm[1], v.mm[1], eps, eps) && - isRelOrApproxEqual(this->mm[2], v.mm[2], eps, eps); - } - - - /// Negation operator, for e.g. v1 = -v2; - Vec3 operator-() const { return Vec3(-this->mm[0], -this->mm[1], -this->mm[2]); } - - /// this = v1 + v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.add(v1,v); - template - const Vec3& add(const Vec3 &v1, const Vec3 &v2) - { - this->mm[0] = v1[0] + v2[0]; - this->mm[1] = v1[1] + v2[1]; - this->mm[2] = v1[2] + v2[2]; - - return *this; - } - - /// this = v1 - v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.sub(v1,v); - template - const Vec3& sub(const Vec3 &v1, const Vec3 &v2) - { - this->mm[0] = v1[0] - v2[0]; - this->mm[1] = v1[1] - v2[1]; - this->mm[2] = v1[2] - v2[2]; - - return *this; - } - - /// this = scalar*v, v need not be a distinct object from "this", - /// e.g. v.scale(1.5,v1); - template - const Vec3& scale(T0 scale, const Vec3 &v) - { - this->mm[0] = scale * v[0]; - this->mm[1] = scale * v[1]; - this->mm[2] = scale * v[2]; - - return *this; - } - - template - const Vec3 &div(T0 scale, const Vec3 &v) - { - this->mm[0] = v[0] / scale; - this->mm[1] = v[1] / scale; - this->mm[2] = v[2] / scale; - - return *this; - } - - /// Dot product - T dot(const Vec3 &v) const - { - return - this->mm[0]*v.mm[0] + - this->mm[1]*v.mm[1] + - this->mm[2]*v.mm[2]; - } - - /// Length of the vector - T length() const - { - return static_cast(sqrt(double( - this->mm[0]*this->mm[0] + - this->mm[1]*this->mm[1] + - this->mm[2]*this->mm[2]))); - } - - - /// Squared length of the vector, much faster than length() as it - /// does not involve square root - T lengthSqr() const - { - return - this->mm[0]*this->mm[0] + - this->mm[1]*this->mm[1] + - this->mm[2]*this->mm[2]; - } - - /// Return the cross product of "this" vector and v; - Vec3 cross(const Vec3 &v) const - { - return Vec3(this->mm[1]*v.mm[2] - this->mm[2]*v.mm[1], - this->mm[2]*v.mm[0] - this->mm[0]*v.mm[2], - this->mm[0]*v.mm[1] - this->mm[1]*v.mm[0]); - } - - - /// this = v1 cross v2, v1 and v2 must be distinct objects than "this" - const Vec3& cross(const Vec3 &v1, const Vec3 &v2) - { - // assert(this!=&v1); - // assert(this!=&v2); - this->mm[0] = v1.mm[1]*v2.mm[2] - v1.mm[2]*v2.mm[1]; - this->mm[1] = v1.mm[2]*v2.mm[0] - v1.mm[0]*v2.mm[2]; - this->mm[2] = v1.mm[0]*v2.mm[1] - v1.mm[1]*v2.mm[0]; - return *this; - } - - /// Returns v, where \f$v_i *= scalar\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator*=(S scalar) - { - this->mm[0] = static_cast(this->mm[0] * scalar); - this->mm[1] = static_cast(this->mm[1] * scalar); - this->mm[2] = static_cast(this->mm[2] * scalar); - return *this; - } - - /// Returns v0, where \f$v0_i *= v1_i\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator*=(const Vec3 &v1) - { - this->mm[0] *= v1[0]; - this->mm[1] *= v1[1]; - this->mm[2] *= v1[2]; - return *this; - } - - /// Returns v, where \f$v_i /= scalar\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator/=(S scalar) - { - this->mm[0] /= scalar; - this->mm[1] /= scalar; - this->mm[2] /= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i /= v1_i\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator/=(const Vec3 &v1) - { - this->mm[0] /= v1[0]; - this->mm[1] /= v1[1]; - this->mm[2] /= v1[2]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator+=(S scalar) - { - this->mm[0] = static_cast(this->mm[0] + scalar); - this->mm[1] = static_cast(this->mm[1] + scalar); - this->mm[2] = static_cast(this->mm[2] + scalar); - return *this; - } - - /// Returns v0, where \f$v0_i += v1_i\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator+=(const Vec3 &v1) - { - this->mm[0] += v1[0]; - this->mm[1] += v1[1]; - this->mm[2] += v1[2]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator-=(S scalar) - { - this->mm[0] -= scalar; - this->mm[1] -= scalar; - this->mm[2] -= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i -= v1_i\f$ for \f$i \in [0, 2]\f$ - template - const Vec3 &operator-=(const Vec3 &v1) - { - this->mm[0] -= v1[0]; - this->mm[1] -= v1[1]; - this->mm[2] -= v1[2]; - return *this; - } - - /// Return a reference to itsef after the exponent has been - /// applied to all the vector components. - inline const Vec3& exp() - { - this->mm[0] = std::exp(this->mm[0]); - this->mm[1] = std::exp(this->mm[1]); - this->mm[2] = std::exp(this->mm[2]); - return *this; - } - - /// Return the sum of all the vector components. - inline T sum() const - { - return this->mm[0] + this->mm[1] + this->mm[2]; - } - - /// this = normalized this - bool normalize(T eps = T(1.0e-7)) - { - T d = length(); - if (isApproxEqual(d, T(0), eps)) { - return false; - } - *this *= (T(1) / d); - return true; - } - - - /// return normalized this, throws if null vector - Vec3 unit(T eps=0) const - { - T d; - return unit(eps, d); - } - - /// return normalized this and length, throws if null vector - Vec3 unit(T eps, T& len) const - { - len = length(); - if (isApproxEqual(len, T(0), eps)) { - OPENVDB_THROW(ArithmeticError, "Normalizing null 3-vector"); - } - return *this / len; - } - - // Number of cols, rows, elements - static unsigned numRows() { return 1; } - static unsigned numColumns() { return 3; } - static unsigned numElements() { return 3; } - - /// Returns the scalar component of v in the direction of onto, onto need - /// not be unit. e.g double c = Vec3d::component(v1,v2); - T component(const Vec3 &onto, T eps = static_cast(1.0e-7)) const - { - T l = onto.length(); - if (isApproxEqual(l, T(0), eps)) return 0; - - return dot(onto)*(T(1)/l); - } - - /// Return the projection of v onto the vector, onto need not be unit - /// e.g. Vec3d a = vprojection(n); - Vec3 projection(const Vec3 &onto, T eps = static_cast(1.0e-7)) const - { - T l = onto.lengthSqr(); - if (isApproxEqual(l, T(0), eps)) return Vec3::zero(); - - return onto*(dot(onto)*(T(1)/l)); - } - - /// Return an arbitrary unit vector perpendicular to v - /// Vector this must be a unit vector - /// e.g. v = v.normalize(); Vec3d n = v.getArbPerpendicular(); - Vec3 getArbPerpendicular() const - { - Vec3 u; - T l; - - if ( fabs(this->mm[0]) >= fabs(this->mm[1]) ) { - // v.x or v.z is the largest magnitude component, swap them - l = this->mm[0]*this->mm[0] + this->mm[2]*this->mm[2]; - l = static_cast(T(1)/sqrt(double(l))); - u.mm[0] = -this->mm[2]*l; - u.mm[1] = (T)0.0; - u.mm[2] = +this->mm[0]*l; - } else { - // W.y or W.z is the largest magnitude component, swap them - l = this->mm[1]*this->mm[1] + this->mm[2]*this->mm[2]; - l = static_cast(T(1)/sqrt(double(l))); - u.mm[0] = (T)0.0; - u.mm[1] = +this->mm[2]*l; - u.mm[2] = -this->mm[1]*l; - } - - return u; - } - - /// True if a Nan is present in vector - bool isNan() const { return isnan(this->mm[0]) || isnan(this->mm[1]) || isnan(this->mm[2]); } - - /// True if an Inf is present in vector - bool isInfinite() const - { - return isinf(this->mm[0]) || isinf(this->mm[1]) || isinf(this->mm[2]); - } - - /// True if all no Nan or Inf values present - bool isFinite() const - { - return finite(this->mm[0]) && finite(this->mm[1]) && finite(this->mm[2]); - } - - /// Predefined constants, e.g. Vec3d v = Vec3d::xNegAxis(); - static Vec3 zero() { return Vec3(0, 0, 0); } -}; - - -/// Equality operator, does exact floating point comparisons -template -inline bool operator==(const Vec3 &v0, const Vec3 &v1) -{ - return isExactlyEqual(v0[0], v1[0]) && isExactlyEqual(v0[1], v1[1]) - && isExactlyEqual(v0[2], v1[2]); -} - -/// Inequality operator, does exact floating point comparisons -template -inline bool operator!=(const Vec3 &v0, const Vec3 &v1) { return !(v0==v1); } - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator*(S scalar, const Vec3 &v) { return v*scalar; } - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator*(const Vec3 &v, S scalar) -{ - Vec3::type> result(v); - result *= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i * v1_i\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator*(const Vec3 &v0, const Vec3 &v1) -{ - Vec3::type> result(v0[0] * v1[0], v0[1] * v1[1], v0[2] * v1[2]); - return result; -} - - -/// Returns V, where \f$V_i = scalar / v_i\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator/(S scalar, const Vec3 &v) -{ - return Vec3::type>(scalar/v[0], scalar/v[1], scalar/v[2]); -} - -/// Returns V, where \f$V_i = v_i / scalar\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator/(const Vec3 &v, S scalar) -{ - Vec3::type> result(v); - result /= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i / v1_i\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator/(const Vec3 &v0, const Vec3 &v1) -{ - Vec3::type> result(v0[0] / v1[0], v0[1] / v1[1], v0[2] / v1[2]); - return result; -} - -/// Returns V, where \f$V_i = v0_i + v1_i\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator+(const Vec3 &v0, const Vec3 &v1) -{ - Vec3::type> result(v0); - result += v1; - return result; -} - -/// Returns V, where \f$V_i = v_i + scalar\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator+(const Vec3 &v, S scalar) -{ - Vec3::type> result(v); - result += scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i - v1_i\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator-(const Vec3 &v0, const Vec3 &v1) -{ - Vec3::type> result(v0); - result -= v1; - return result; -} - -/// Returns V, where \f$V_i = v_i - scalar\f$ for \f$i \in [0, 2]\f$ -template -inline Vec3::type> operator-(const Vec3 &v, S scalar) -{ - Vec3::type> result(v); - result -= scalar; - return result; -} - -/// Angle between two vectors, the result is between [0, pi], -/// e.g. double a = Vec3d::angle(v1,v2); -template -inline T angle(const Vec3 &v1, const Vec3 &v2) -{ - Vec3 c = v1.cross(v2); - return static_cast(atan2(c.length(), v1.dot(v2))); -} - -template -inline bool -isApproxEqual(const Vec3& a, const Vec3& b) -{ - return a.eq(b); -} -template -inline bool -isApproxEqual(const Vec3& a, const Vec3& b, const Vec3& eps) -{ - return isApproxEqual(a.x(), b.x(), eps.x()) && - isApproxEqual(a.y(), b.y(), eps.y()) && - isApproxEqual(a.z(), b.z(), eps.z()); -} - -/// Orthonormalize vectors v1, v2 and v3 and store back the resulting -/// basis e.g. Vec3d::orthonormalize(v1,v2,v3); -template -inline void orthonormalize(Vec3 &v1, Vec3 &v2, Vec3 &v3) -{ - // If the input vectors are v0, v1, and v2, then the Gram-Schmidt - // orthonormalization produces vectors u0, u1, and u2 as follows, - // - // u0 = v0/|v0| - // u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0| - // u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1| - // - // where |A| indicates length of vector A and A*B indicates dot - // product of vectors A and B. - - // compute u0 - v1.normalize(); - - // compute u1 - T d0 = v1.dot(v2); - v2 -= v1*d0; - v2.normalize(); - - // compute u2 - T d1 = v2.dot(v3); - d0 = v1.dot(v3); - v3 -= v1*d0 + v2*d1; - v3.normalize(); -} - -/// @remark We are switching to a more explicit name because the semantics -/// are different from std::min/max. In that case, the function returns a -/// reference to one of the objects based on a comparator. Here, we must -/// fabricate a new object which might not match either of the inputs. - -/// Return component-wise minimum of the two vectors. -template -inline Vec3 minComponent(const Vec3 &v1, const Vec3 &v2) -{ - return Vec3( - std::min(v1.x(), v2.x()), - std::min(v1.y(), v2.y()), - std::min(v1.z(), v2.z())); -} - -/// Return component-wise maximum of the two vectors. -template -inline Vec3 maxComponent(const Vec3 &v1, const Vec3 &v2) -{ - return Vec3( - std::max(v1.x(), v2.x()), - std::max(v1.y(), v2.y()), - std::max(v1.z(), v2.z())); -} - -/// @brief Return a vector with the exponent applied to each of -/// the components of the input vector. -template -inline Vec3 Exp(Vec3 v) { return v.exp(); } - -typedef Vec3 Vec3i; -typedef Vec3 Vec3ui; -typedef Vec3 Vec3s; -typedef Vec3 Vec3d; - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_VEC3_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/math/Vec4.h b/openvdb_3_0_0_library/math/Vec4.h deleted file mode 100755 index 260d0ed..0000000 --- a/openvdb_3_0_0_library/math/Vec4.h +++ /dev/null @@ -1,556 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_MATH_VEC4_HAS_BEEN_INCLUDED -#define OPENVDB_MATH_VEC4_HAS_BEEN_INCLUDED - -#include -#include -#include "Math.h" -#include "Tuple.h" -#include "Vec3.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace math { - -template class Mat3; - -template -class Vec4: public Tuple<4, T> -{ -public: - typedef T value_type; - typedef T ValueType; - - /// Trivial constructor, the vector is NOT initialized - Vec4() {} - - /// Constructor with one argument, e.g. Vec4f v(0); - explicit Vec4(T val) { this->mm[0] = this->mm[1] = this->mm[2] = this->mm[3] = val; } - - /// Constructor with three arguments, e.g. Vec4f v(1,2,3); - Vec4(T x, T y, T z, T w) - { - this->mm[0] = x; - this->mm[1] = y; - this->mm[2] = z; - this->mm[3] = w; - } - - /// Constructor with array argument, e.g. float a[4]; Vec4f v(a); - template - Vec4(Source *a) - { - this->mm[0] = a[0]; - this->mm[1] = a[1]; - this->mm[2] = a[2]; - this->mm[3] = a[3]; - } - - /// Conversion constructor - template - explicit Vec4(const Tuple<4, Source> &v) - { - this->mm[0] = static_cast(v[0]); - this->mm[1] = static_cast(v[1]); - this->mm[2] = static_cast(v[2]); - this->mm[3] = static_cast(v[3]); - } - - /// Reference to the component, e.g. v.x() = 4.5f; - T& x() { return this->mm[0]; } - T& y() { return this->mm[1]; } - T& z() { return this->mm[2]; } - T& w() { return this->mm[3]; } - - /// Get the component, e.g. float f = v.y(); - T x() const { return this->mm[0]; } - T y() const { return this->mm[1]; } - T z() const { return this->mm[2]; } - T w() const { return this->mm[3]; } - - T* asPointer() { return this->mm; } - const T* asPointer() const { return this->mm; } - - /// Alternative indexed reference to the elements - T& operator()(int i) { return this->mm[i]; } - - /// Alternative indexed constant reference to the elements, - T operator()(int i) const { return this->mm[i]; } - - /// Returns a Vec3 with the first three elements of the Vec4. - Vec3 getVec3() const { return Vec3(this->mm[0], this->mm[1], this->mm[2]); } - - /// "this" vector gets initialized to [x, y, z, w], - /// calling v.init(); has same effect as calling v = Vec4::zero(); - const Vec4& init(T x=0, T y=0, T z=0, T w=0) - { - this->mm[0] = x; this->mm[1] = y; this->mm[2] = z; this->mm[3] = w; - return *this; - } - - /// Set "this" vector to zero - const Vec4& setZero() - { - this->mm[0] = 0; this->mm[1] = 0; this->mm[2] = 0; this->mm[3] = 0; - return *this; - } - - /// Assignment operator - template - const Vec4& operator=(const Vec4 &v) - { - // note: don't static_cast because that suppresses warnings - this->mm[0] = v[0]; - this->mm[1] = v[1]; - this->mm[2] = v[2]; - this->mm[3] = v[3]; - - return *this; - } - - /// Test if "this" vector is equivalent to vector v with tolerance - /// of eps - bool eq(const Vec4 &v, T eps=1.0e-8) const - { - return isApproxEqual(this->mm[0], v.mm[0], eps) && - isApproxEqual(this->mm[1], v.mm[1], eps) && - isApproxEqual(this->mm[2], v.mm[2], eps) && - isApproxEqual(this->mm[3], v.mm[3], eps); - } - - /// Negation operator, for e.g. v1 = -v2; - Vec4 operator-() const - { - return Vec4( - -this->mm[0], - -this->mm[1], - -this->mm[2], - -this->mm[3]); - } - - /// this = v1 + v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.add(v1,v); - template - const Vec4& add(const Vec4 &v1, const Vec4 &v2) - { - this->mm[0] = v1[0] + v2[0]; - this->mm[1] = v1[1] + v2[1]; - this->mm[2] = v1[2] + v2[2]; - this->mm[3] = v1[3] + v2[3]; - - return *this; - } - - - /// this = v1 - v2 - /// "this", v1 and v2 need not be distinct objects, e.g. v.sub(v1,v); - template - const Vec4& sub(const Vec4 &v1, const Vec4 &v2) - { - this->mm[0] = v1[0] - v2[0]; - this->mm[1] = v1[1] - v2[1]; - this->mm[2] = v1[2] - v2[2]; - this->mm[3] = v1[3] - v2[3]; - - return *this; - } - - /// this = scalar*v, v need not be a distinct object from "this", - /// e.g. v.scale(1.5,v1); - template - const Vec4& scale(T0 scale, const Vec4 &v) - { - this->mm[0] = scale * v[0]; - this->mm[1] = scale * v[1]; - this->mm[2] = scale * v[2]; - this->mm[3] = scale * v[3]; - - return *this; - } - - template - const Vec4 &div(T0 scalar, const Vec4 &v) - { - this->mm[0] = v[0] / scalar; - this->mm[1] = v[1] / scalar; - this->mm[2] = v[2] / scalar; - this->mm[3] = v[3] / scalar; - - return *this; - } - - /// Dot product - T dot(const Vec4 &v) const - { - return (this->mm[0]*v.mm[0] + this->mm[1]*v.mm[1] - + this->mm[2]*v.mm[2] + this->mm[3]*v.mm[3]); - } - - /// Length of the vector - T length() const - { - return sqrt( - this->mm[0]*this->mm[0] + - this->mm[1]*this->mm[1] + - this->mm[2]*this->mm[2] + - this->mm[3]*this->mm[3]); - } - - - /// Squared length of the vector, much faster than length() as it - /// does not involve square root - T lengthSqr() const - { - return (this->mm[0]*this->mm[0] + this->mm[1]*this->mm[1] - + this->mm[2]*this->mm[2] + this->mm[3]*this->mm[3]); - } - - /// Return a reference to itsef after the exponent has been - /// applied to all the vector components. - inline const Vec4& exp() - { - this->mm[0] = std::exp(this->mm[0]); - this->mm[1] = std::exp(this->mm[1]); - this->mm[2] = std::exp(this->mm[2]); - this->mm[3] = std::exp(this->mm[3]); - return *this; - } - - /// Return the sum of all the vector components. - inline T sum() const - { - return this->mm[0] + this->mm[1] + this->mm[2] + this->mm[3]; - } - - - /// this = normalized this - bool normalize(T eps=1.0e-8) - { - T d = length(); - if (isApproxEqual(d, T(0), eps)) { - return false; - } - *this *= (T(1) / d); - return true; - } - - /// return normalized this, throws if null vector - Vec4 unit(T eps=0) const - { - T d; - return unit(eps, d); - } - - /// return normalized this and length, throws if null vector - Vec4 unit(T eps, T& len) const - { - len = length(); - if (isApproxEqual(len, T(0), eps)) { - throw ArithmeticError("Normalizing null 4-vector"); - } - return *this / len; - } - - /// Returns v, where \f$v_i *= scalar\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator*=(S scalar) - { - this->mm[0] *= scalar; - this->mm[1] *= scalar; - this->mm[2] *= scalar; - this->mm[3] *= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i *= v1_i\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator*=(const Vec4 &v1) - { - this->mm[0] *= v1[0]; - this->mm[1] *= v1[1]; - this->mm[2] *= v1[2]; - this->mm[3] *= v1[3]; - - return *this; - } - - /// Returns v, where \f$v_i /= scalar\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator/=(S scalar) - { - this->mm[0] /= scalar; - this->mm[1] /= scalar; - this->mm[2] /= scalar; - this->mm[3] /= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i /= v1_i\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator/=(const Vec4 &v1) - { - this->mm[0] /= v1[0]; - this->mm[1] /= v1[1]; - this->mm[2] /= v1[2]; - this->mm[3] /= v1[3]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator+=(S scalar) - { - this->mm[0] += scalar; - this->mm[1] += scalar; - this->mm[2] += scalar; - this->mm[3] += scalar; - return *this; - } - - /// Returns v0, where \f$v0_i += v1_i\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator+=(const Vec4 &v1) - { - this->mm[0] += v1[0]; - this->mm[1] += v1[1]; - this->mm[2] += v1[2]; - this->mm[3] += v1[3]; - return *this; - } - - /// Returns v, where \f$v_i += scalar\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator-=(S scalar) - { - this->mm[0] -= scalar; - this->mm[1] -= scalar; - this->mm[2] -= scalar; - this->mm[3] -= scalar; - return *this; - } - - /// Returns v0, where \f$v0_i -= v1_i\f$ for \f$i \in [0, 3]\f$ - template - const Vec4 &operator-=(const Vec4 &v1) - { - this->mm[0] -= v1[0]; - this->mm[1] -= v1[1]; - this->mm[2] -= v1[2]; - this->mm[3] -= v1[3]; - return *this; - } - - // Number of cols, rows, elements - static unsigned numRows() { return 1; } - static unsigned numColumns() { return 4; } - static unsigned numElements() { return 4; } - - /// True if a Nan is present in vector - bool isNan() const - { - return isnan(this->mm[0]) || isnan(this->mm[1]) - || isnan(this->mm[2]) || isnan(this->mm[3]); - } - - /// True if an Inf is present in vector - bool isInfinite() const - { - return isinf(this->mm[0]) || isinf(this->mm[1]) - || isinf(this->mm[2]) || isinf(this->mm[3]); - } - - /// True if all no Nan or Inf values present - bool isFinite() const - { - return finite(this->mm[0]) && finite(this->mm[1]) - && finite(this->mm[2]) && finite(this->mm[3]); - } - - /// Predefined constants, e.g. Vec4f v = Vec4f::xNegAxis(); - static Vec4 zero() { return Vec4(0, 0, 0, 0); } - static Vec4 origin() { return Vec4(0, 0, 0, 1); } -}; - -/// Equality operator, does exact floating point comparisons -template -inline bool operator==(const Vec4 &v0, const Vec4 &v1) -{ - return - isExactlyEqual(v0[0], v1[0]) && - isExactlyEqual(v0[1], v1[1]) && - isExactlyEqual(v0[2], v1[2]) && - isExactlyEqual(v0[3], v1[3]); -} - -/// Inequality operator, does exact floating point comparisons -template -inline bool operator!=(const Vec4 &v0, const Vec4 &v1) { return !(v0==v1); } - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator*(S scalar, const Vec4 &v) -{ return v*scalar; } - -/// Returns V, where \f$V_i = v_i * scalar\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator*(const Vec4 &v, S scalar) -{ - Vec4::type> result(v); - result *= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i * v1_i\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator*(const Vec4 &v0, - const Vec4 &v1) -{ - Vec4::type> result(v0[0]*v1[0], - v0[1]*v1[1], - v0[2]*v1[2], - v0[3]*v1[3]); - return result; -} - -/// Returns V, where \f$V_i = scalar / v_i\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator/(S scalar, const Vec4 &v) -{ - return Vec4::type>(scalar/v[0], - scalar/v[1], - scalar/v[2], - scalar/v[3]); -} - -/// Returns V, where \f$V_i = v_i / scalar\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator/(const Vec4 &v, S scalar) -{ - Vec4::type> result(v); - result /= scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i / v1_i\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator/(const Vec4 &v0, - const Vec4 &v1) -{ - Vec4::type> - result(v0[0]/v1[0], v0[1]/v1[1], v0[2]/v1[2], v0[3]/v1[3]); - return result; -} - -/// Returns V, where \f$V_i = v0_i + v1_i\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator+(const Vec4 &v0, const Vec4 &v1) -{ - Vec4::type> result(v0); - result += v1; - return result; -} - -/// Returns V, where \f$V_i = v_i + scalar\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator+(const Vec4 &v, S scalar) -{ - Vec4::type> result(v); - result += scalar; - return result; -} - -/// Returns V, where \f$V_i = v0_i - v1_i\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator-(const Vec4 &v0, const Vec4 &v1) -{ - Vec4::type> result(v0); - result -= v1; - return result; -} - -/// Returns V, where \f$V_i = v_i - scalar\f$ for \f$i \in [0, 3]\f$ -template -inline Vec4::type> operator-(const Vec4 &v, S scalar) -{ - Vec4::type> result(v); - result -= scalar; - return result; -} - -/// @remark We are switching to a more explicit name because the semantics -/// are different from std::min/max. In that case, the function returns a -/// reference to one of the objects based on a comparator. Here, we must -/// fabricate a new object which might not match either of the inputs. - -/// Return component-wise minimum of the two vectors. -template -inline Vec4 minComponent(const Vec4 &v1, const Vec4 &v2) -{ - return Vec4( - std::min(v1.x(), v2.x()), - std::min(v1.y(), v2.y()), - std::min(v1.z(), v2.z()), - std::min(v1.w(), v2.w())); -} - -/// Return component-wise maximum of the two vectors. -template -inline Vec4 maxComponent(const Vec4 &v1, const Vec4 &v2) -{ - return Vec4( - std::max(v1.x(), v2.x()), - std::max(v1.y(), v2.y()), - std::max(v1.z(), v2.z()), - std::max(v1.w(), v2.w())); -} - -/// @brief Return a vector with the exponent applied to each of -/// the components of the input vector. -template -inline Vec4 Exp(Vec4 v) { return v.exp(); } - -typedef Vec4 Vec4i; -typedef Vec4 Vec4ui; -typedef Vec4 Vec4s; -typedef Vec4 Vec4d; - -} // namespace math -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_MATH_VEC4_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/metadata/MetaMap.cc b/openvdb_3_0_0_library/metadata/MetaMap.cc deleted file mode 100755 index 899f716..0000000 --- a/openvdb_3_0_0_library/metadata/MetaMap.cc +++ /dev/null @@ -1,216 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -MetaMap::MetaMap(const MetaMap& other) -{ - this->insertMeta(other); -} - - -MetaMap::Ptr -MetaMap::copyMeta() const -{ - MetaMap::Ptr ret(new MetaMap); - ret->mMeta = this->mMeta; - return ret; -} - - -MetaMap::Ptr -MetaMap::deepCopyMeta() const -{ - return MetaMap::Ptr(new MetaMap(*this)); -} - - -MetaMap& -MetaMap::operator=(const MetaMap& other) -{ - if (&other != this) { - this->clearMetadata(); - // Insert all metadata into this map. - ConstMetaIterator iter = other.beginMeta(); - for ( ; iter != other.endMeta(); ++iter) { - this->insertMeta(iter->first, *(iter->second)); - } - } - return *this; -} - - -void -MetaMap::readMeta(std::istream &is) -{ - // Clear out the current metamap if need be. - this->clearMetadata(); - - // Read in the number of metadata items. - Index32 count = 0; - is.read(reinterpret_cast(&count), sizeof(Index32)); - - // Read in each metadata. - for (Index32 i = 0; i < count; ++i) { - // Read in the name. - Name name = readString(is); - - // Read in the metadata typename. - Name typeName = readString(is); - - // Create a metadata type from the typename. Make sure that the type is - // registered. - if (!Metadata::isRegisteredType(typeName)) { - OPENVDB_LOG_WARN("cannot read metadata \"" << name - << "\" of unregistered type \"" << typeName << "\""); - UnknownMetadata metadata; - metadata.read(is); - } else { - Metadata::Ptr metadata = Metadata::createMetadata(typeName); - - // Read the value from the stream. - metadata->read(is); - - // Add the name and metadata to the map. - insertMeta(name, *metadata); - } - } -} - - -void -MetaMap::writeMeta(std::ostream &os) const -{ - // Write out the number of metadata items we have in the map. Note that we - // save as Index32 to save a 32-bit number. Using size_t would be platform - // dependent. - Index32 count = (Index32)metaCount(); - os.write(reinterpret_cast(&count), sizeof(Index32)); - - // Iterate through each metadata and write it out. - for (ConstMetaIterator iter = beginMeta(); iter != endMeta(); ++iter) { - // Write the name of the metadata. - writeString(os, iter->first); - - // Write the type name of the metadata. - writeString(os, iter->second->typeName()); - - // Write out the metadata value. - iter->second->write(os); - } -} - - -void -MetaMap::insertMeta(const Name &name, const Metadata &m) -{ - if(name.size() == 0) - OPENVDB_THROW(ValueError, "Metadata name cannot be an empty string"); - - // See if the value already exists, if so then replace the existing one. - MetaIterator iter = mMeta.find(name); - - if(iter == mMeta.end()) { - // Create a copy of the metadata and store it in the map - Metadata::Ptr tmp = m.copy(); - mMeta[name] = tmp; - } else { - if(iter->second->typeName() != m.typeName()) { - std::ostringstream ostr; - ostr << "Cannot assign value of type " - << m.typeName() << " to metadata attribute " << name - << " of " << "type " << iter->second->typeName(); - OPENVDB_THROW(TypeError, ostr.str()); - } - // else - Metadata::Ptr tmp = m.copy(); - iter->second = tmp; - } -} - - -void -MetaMap::insertMeta(const MetaMap& other) -{ - for (ConstMetaIterator it = other.beginMeta(), end = other.endMeta(); it != end; ++it) { - if (it->second) this->insertMeta(it->first, *it->second); - } -} - - -void -MetaMap::removeMeta(const Name &name) -{ - // Find the required metadata - MetaIterator iter = mMeta.find(name); - - if(iter == mMeta.end()) - return; - // else, delete the metadata and remove from the map - mMeta.erase(iter); -} - - -std::string -MetaMap::str(const std::string& indent) const -{ - std::ostringstream ostr; - char sep[2] = { 0, 0 }; - for (ConstMetaIterator iter = beginMeta(); iter != endMeta(); ++iter) { - ostr << sep << indent << iter->first; - if (iter->second) { - const std::string value = iter->second->str(); - if (!value.empty()) ostr << ": " << value; - } - sep[0] = '\n'; - } - return ostr.str(); -} - -std::ostream& -operator<<(std::ostream& ostr, const MetaMap& metamap) -{ - ostr << metamap.str(); - return ostr; -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/metadata/MetaMap.h b/openvdb_3_0_0_library/metadata/MetaMap.h deleted file mode 100755 index 646a04d..0000000 --- a/openvdb_3_0_0_library/metadata/MetaMap.h +++ /dev/null @@ -1,246 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED -#define OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// Container that maps names (strings) to values of arbitrary types -class OPENVDB_API MetaMap -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - typedef std::map MetadataMap; - typedef MetadataMap::iterator MetaIterator; - typedef MetadataMap::const_iterator ConstMetaIterator; - ///< @todo this should really iterate over a map of Metadata::ConstPtrs - - MetaMap() {} - MetaMap(const MetaMap& other); - virtual ~MetaMap() {} - - /// Return a copy of this map whose fields are shared with this map. - MetaMap::Ptr copyMeta() const; - /// Return a deep copy of this map that shares no data with this map. - MetaMap::Ptr deepCopyMeta() const; - - /// Assign a deep copy of another map to this map. - MetaMap& operator=(const MetaMap&); - - /// Unserialize metadata from the given stream. - void readMeta(std::istream&); - /// Serialize metadata to the given stream. - void writeMeta(std::ostream&) const; - - /// @brief Insert a new metadata field or overwrite the value of an existing field. - /// @details If a field with the given name doesn't already exist, add a new field. - /// Otherwise, if the new value's type is the same as the existing field's value type, - /// overwrite the existing value with new value. - /// @throw TypeError if a field with the given name already exists, but its value type - /// is not the same as the new value's - /// @throw ValueError if the given field name is empty. - void insertMeta(const Name&, const Metadata& value); - /// @brief Deep copy all of the metadata fields from the given map into this map. - /// @throw TypeError if any field in the given map has the same name as - /// but a different value type than one of this map's fields. - void insertMeta(const MetaMap&); - - /// Remove the given metadata field if it exists. - void removeMeta(const Name&); - - //@{ - /// @brief Return a pointer to the metadata with the given name. - /// If no such field exists, return a null pointer. - Metadata::Ptr operator[](const Name&); - Metadata::ConstPtr operator[](const Name&) const; - //@} - - //@{ - /// @brief Return a pointer to a TypedMetadata object of type @c T and with the given name. - /// If no such field exists or if there is a type mismatch, return a null pointer. - template typename T::Ptr getMetadata(const Name&); - template typename T::ConstPtr getMetadata(const Name&) const; - //@} - - /// @brief Return a reference to the value of type @c T stored in the given metadata field. - /// @throw LookupError if no field with the given name exists. - /// @throw TypeError if the given field is not of type @c T. - template T& metaValue(const Name&); - template const T& metaValue(const Name&) const; - - // Functions for iterating over the metadata - MetaIterator beginMeta() { return mMeta.begin(); } - MetaIterator endMeta() { return mMeta.end(); } - ConstMetaIterator beginMeta() const { return mMeta.begin(); } - ConstMetaIterator endMeta() const { return mMeta.end(); } - - void clearMetadata() { mMeta.clear(); } - - size_t metaCount() const { return mMeta.size(); } - - /// Return a string describing this metadata map. Prefix each line with @a indent. - std::string str(const std::string& indent = "") const; - -private: - /// @brief Return a pointer to TypedMetadata with the given template parameter. - /// @throw LookupError if no field with the given name is found. - /// @throw TypeError if the given field is not of type T. - template - typename TypedMetadata::Ptr getValidTypedMetadata(const Name&) const; - - MetadataMap mMeta; -}; - -/// Write a MetaMap to an output stream -std::ostream& operator<<(std::ostream&, const MetaMap&); - - -//////////////////////////////////////// - - -inline Metadata::Ptr -MetaMap::operator[](const Name& name) -{ - MetaIterator iter = mMeta.find(name); - return (iter == mMeta.end() ? Metadata::Ptr() : iter->second); -} - -inline Metadata::ConstPtr -MetaMap::operator[](const Name &name) const -{ - ConstMetaIterator iter = mMeta.find(name); - return (iter == mMeta.end() ? Metadata::Ptr() : iter->second); -} - - -//////////////////////////////////////// - - -template -inline typename T::Ptr -MetaMap::getMetadata(const Name &name) -{ - ConstMetaIterator iter = mMeta.find(name); - if(iter == mMeta.end()) { - return typename T::Ptr(); - } - - // To ensure that we get valid conversion if the metadata pointers cross dso - // boundaries, we have to check the qualified typename and then do a static - // cast. This is slower than doing a dynamic_pointer_cast, but is safer when - // pointers cross dso boundaries. - if (iter->second->typeName() == T::staticTypeName()) { - return boost::static_pointer_cast(iter->second); - } // else - return typename T::Ptr(); -} - -template -inline typename T::ConstPtr -MetaMap::getMetadata(const Name &name) const -{ - ConstMetaIterator iter = mMeta.find(name); - if(iter == mMeta.end()) { - return typename T::ConstPtr(); - } - // To ensure that we get valid conversion if the metadata pointers cross dso - // boundaries, we have to check the qualified typename and then do a static - // cast. This is slower than doing a dynamic_pointer_cast, but is safer when - // pointers cross dso boundaries. - if (iter->second->typeName() == T::staticTypeName()) { - return boost::static_pointer_cast(iter->second); - } // else - return typename T::ConstPtr(); -} - - -//////////////////////////////////////// - - -template -inline typename TypedMetadata::Ptr -MetaMap::getValidTypedMetadata(const Name &name) const -{ - ConstMetaIterator iter = mMeta.find(name); - if (iter == mMeta.end()) OPENVDB_THROW(LookupError, "Cannot find metadata " << name); - - // To ensure that we get valid conversion if the metadata pointers cross dso - // boundaries, we have to check the qualified typename and then do a static - // cast. This is slower than doing a dynamic_pointer_cast, but is safer when - // pointers cross dso boundaries. - typename TypedMetadata::Ptr m; - if (iter->second->typeName() == TypedMetadata::staticTypeName()) { - m = boost::static_pointer_cast, Metadata>(iter->second); - } - if (!m) OPENVDB_THROW(TypeError, "Invalid type for metadata " << name); - return m; -} - - -//////////////////////////////////////// - - -template -inline T& -MetaMap::metaValue(const Name &name) -{ - typename TypedMetadata::Ptr m = getValidTypedMetadata(name); - return m->value(); -} - - -template -inline const T& -MetaMap::metaValue(const Name &name) const -{ - typename TypedMetadata::Ptr m = getValidTypedMetadata(name); - return m->value(); -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_METADATA_METAMAP_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/metadata/Metadata.cc b/openvdb_3_0_0_library/metadata/Metadata.cc deleted file mode 100755 index 52f2972..0000000 --- a/openvdb_3_0_0_library/metadata/Metadata.cc +++ /dev/null @@ -1,168 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Metadata.h" - -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -typedef tbb::mutex Mutex; -typedef Mutex::scoped_lock Lock; - -typedef Metadata::Ptr (*createMetadata)(); -typedef std::map MetadataFactoryMap; -typedef MetadataFactoryMap::const_iterator MetadataFactoryMapCIter; - -struct LockedMetadataTypeRegistry { - LockedMetadataTypeRegistry() {} - ~LockedMetadataTypeRegistry() {} - Mutex mMutex; - MetadataFactoryMap mMap; -}; - -// Declare this at file scope to ensure thread-safe initialization -static Mutex theInitMetadataTypeRegistryMutex; - -// Global function for accessing the regsitry -static LockedMetadataTypeRegistry* -getMetadataTypeRegistry() -{ - Lock lock(theInitMetadataTypeRegistryMutex); - - static LockedMetadataTypeRegistry *registry = NULL; - - if(registry == NULL) { -#if defined(__ICC) -__pragma(warning(disable:1711)) // disable ICC "assignment to static variable" warnings -#endif - registry = new LockedMetadataTypeRegistry(); -#if defined(__ICC) -__pragma(warning(default:1711)) -#endif - } - - return registry; -} - -bool -Metadata::isRegisteredType(const Name &typeName) -{ - LockedMetadataTypeRegistry *registry = getMetadataTypeRegistry(); - Lock lock(registry->mMutex); - - return (registry->mMap.find(typeName) != registry->mMap.end()); -} - -void -Metadata::registerType(const Name &typeName, Metadata::Ptr (*createMetadata)()) -{ - LockedMetadataTypeRegistry *registry = getMetadataTypeRegistry(); - Lock lock(registry->mMutex); - - if (registry->mMap.find(typeName) != registry->mMap.end()) { - OPENVDB_THROW(KeyError, - "Cannot register " << typeName << ". Type is already registered"); - } - - registry->mMap[typeName] = createMetadata; -} - -void -Metadata::unregisterType(const Name &typeName) -{ - LockedMetadataTypeRegistry *registry = getMetadataTypeRegistry(); - Lock lock(registry->mMutex); - - registry->mMap.erase(typeName); -} - -Metadata::Ptr -Metadata::createMetadata(const Name &typeName) -{ - LockedMetadataTypeRegistry *registry = getMetadataTypeRegistry(); - Lock lock(registry->mMutex); - - MetadataFactoryMapCIter iter = registry->mMap.find(typeName); - - if (iter == registry->mMap.end()) { - OPENVDB_THROW(LookupError, - "Cannot create metadata for unregistered type " << typeName); - } - - return (iter->second)(); -} - -void -Metadata::clearRegistry() -{ - LockedMetadataTypeRegistry *registry = getMetadataTypeRegistry(); - Lock lock(registry->mMutex); - - registry->mMap.clear(); -} - - -//////////////////////////////////////// - - -void -UnknownMetadata::readValue(std::istream& is, Index32 numBytes) -{ - // Read and discard the metadata (without seeking, because - // the stream might not be seekable). - const size_t BUFFER_SIZE = 1024; - std::vector buffer(BUFFER_SIZE); - for (Index32 bytesRemaining = numBytes; bytesRemaining > 0; ) { - const Index32 bytesToSkip = std::min(bytesRemaining, BUFFER_SIZE); - is.read(&buffer[0], bytesToSkip); - bytesRemaining -= bytesToSkip; - } -} - - -void -UnknownMetadata::writeValue(std::ostream&) const -{ - OPENVDB_THROW(TypeError, "Metadata has unknown type"); -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/metadata/Metadata.h b/openvdb_3_0_0_library/metadata/Metadata.h deleted file mode 100755 index 1b274c1..0000000 --- a/openvdb_3_0_0_library/metadata/Metadata.h +++ /dev/null @@ -1,414 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_METADATA_METADATA_HAS_BEEN_INCLUDED -#define OPENVDB_METADATA_METADATA_HAS_BEEN_INCLUDED - -#include -#include -#include -#include // for math::isZero() -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// @brief Base class for storing metadata information in a grid. -class OPENVDB_API Metadata -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - /// Constructor - Metadata() {} - - /// Destructor - virtual ~Metadata() {} - - /// @return the type name of the metadata. - virtual Name typeName() const = 0; - - /// @return a copy of the metadata. - virtual Metadata::Ptr copy() const = 0; - - /// Copy value from the given metadata into the curent metadata - virtual void copy(const Metadata &other) = 0; - - /// @return string representation of Metadata - virtual std::string str() const = 0; - - /// Return the boolean representation of this metadata (empty strings - /// and zeroVals evaluate to false; most other values evaluate to true). - virtual bool asBool() const = 0; - - /// @return the size of the attribute in bytes. - virtual Index32 size() const = 0; - - /// Read the attribute from a stream. - void read(std::istream&); - /// Write the attribute to a stream. - void write(std::ostream&) const; - - /// Creates a new Metadata from the metadata type registry. - static Metadata::Ptr createMetadata(const Name &typeName); - - /// Return @c true if the given type is known by the metadata type registry. - static bool isRegisteredType(const Name &typeName); - - /// Clear out the metadata registry. - static void clearRegistry(); - - /// Register the given metadata type along with a factory function. - static void registerType(const Name& typeName, Metadata::Ptr (*createMetadata)()); - static void unregisterType(const Name& typeName); - -protected: - /// Read the size of the attribute from a stream. - static Index32 readSize(std::istream&); - /// Write the size of the attribute to a stream. - void writeSize(std::ostream&) const; - - /// Read the attribute from a stream. - virtual void readValue(std::istream&, Index32 numBytes) = 0; - /// Write the attribute to a stream. - virtual void writeValue(std::ostream&) const = 0; - -private: - // Disallow copying of instances of this class. - Metadata(const Metadata&); - Metadata& operator=(const Metadata&); -}; - - -/// @brief Subclass to read (and ignore) data of an unregistered type -class OPENVDB_API UnknownMetadata: public Metadata -{ -public: - UnknownMetadata() {} - virtual ~UnknownMetadata() {} - virtual Name typeName() const { return ""; } - virtual Metadata::Ptr copy() const { OPENVDB_THROW(TypeError, "Metadata has unknown type"); } - virtual void copy(const Metadata&) { OPENVDB_THROW(TypeError, "Destination has unknown type"); } - virtual std::string str() const { return ""; } - virtual bool asBool() const { return false; } - virtual Index32 size() const { return 0; } - -protected: - virtual void readValue(std::istream&s, Index32 numBytes); - virtual void writeValue(std::ostream&) const; -}; - - -/// @brief Templated metadata class to hold specific types. -template -class TypedMetadata: public Metadata -{ -public: - typedef boost::shared_ptr > Ptr; - typedef boost::shared_ptr > ConstPtr; - - // Constructors & destructors - TypedMetadata(); - TypedMetadata(const T &value); - TypedMetadata(const TypedMetadata &other); - virtual ~TypedMetadata(); - - /// @return the type name of the metadata. - virtual Name typeName() const; - - /// @return a copy of the metadata - virtual Metadata::Ptr copy() const; - - /// Copy value from the given metadata into the curent metadata - virtual void copy(const Metadata &other); - - /// @return string representation of value - virtual std::string str() const; - - /// Return the boolean representation of this metadata (empty strings - /// and zeroVals evaluate to false; most other values evaluate to true). - virtual bool asBool() const; - - /// @return the size of the attribute in bytes. - virtual Index32 size() const { return static_cast(sizeof(T)); } - - /// Set this metadata's value. - void setValue(const T&); - /// @return this metadata's value. - T& value(); - const T& value() const; - - /// Static specialized function for the type name. This function must be - /// template specialized for each type T. - static Name staticTypeName() { return typeNameAsString(); } - - /// Creates a new metadata of this type. - static Metadata::Ptr createMetadata(); - - /// Register the given metadata type and a function that knows how to create - /// the metadata type. This way the registry will know how to create certain - /// metadata types. - static void registerType(); - static void unregisterType(); - - static bool isRegisteredType(); - -protected: - /// Read the attribute from a stream. - virtual void readValue(std::istream&, Index32 numBytes); - /// Write the attribute to a stream. - virtual void writeValue(std::ostream&) const; - -private: - T mValue; -}; - -/// Write a Metadata to an output stream -std::ostream& operator<<(std::ostream& ostr, const Metadata& metadata); - - -//////////////////////////////////////// - - -inline void -Metadata::writeSize(std::ostream& os) const -{ - const Index32 n = this->size(); - os.write(reinterpret_cast(&n), sizeof(Index32)); -} - - -inline Index32 -Metadata::readSize(std::istream& is) -{ - Index32 n = 0; - is.read(reinterpret_cast(&n), sizeof(Index32)); - return n; -} - - -inline void -Metadata::read(std::istream& is) -{ - const Index32 numBytes = this->readSize(is); - this->readValue(is, numBytes); -} - - -inline void -Metadata::write(std::ostream& os) const -{ - this->writeSize(os); - this->writeValue(os); -} - - -//////////////////////////////////////// - - -template -inline -TypedMetadata::TypedMetadata() : mValue(T()) -{ -} - -template -inline -TypedMetadata::TypedMetadata(const T &value) : mValue(value) -{ -} - -template -inline -TypedMetadata::TypedMetadata(const TypedMetadata &other) : - Metadata(), - mValue(other.mValue) -{ -} - -template -inline -TypedMetadata::~TypedMetadata() -{ -} - -template -inline Name -TypedMetadata::typeName() const -{ - return TypedMetadata::staticTypeName(); -} - -template -inline void -TypedMetadata::setValue(const T& val) -{ - mValue = val; -} - -template -inline T& -TypedMetadata::value() -{ - return mValue; -} - -template -inline const T& -TypedMetadata::value() const -{ - return mValue; -} - -template -inline Metadata::Ptr -TypedMetadata::copy() const -{ - Metadata::Ptr metadata(new TypedMetadata()); - metadata->copy(*this); - return metadata; -} - -template -inline void -TypedMetadata::copy(const Metadata &other) -{ - const TypedMetadata* t = dynamic_cast*>(&other); - if (t == NULL) OPENVDB_THROW(TypeError, "Incompatible type during copy"); - mValue = t->mValue; -} - - -template -inline void -TypedMetadata::readValue(std::istream& is, Index32 /*numBytes*/) -{ - //assert(this->size() == numBytes); - is.read(reinterpret_cast(&mValue), this->size()); -} - -template -inline void -TypedMetadata::writeValue(std::ostream& os) const -{ - os.write(reinterpret_cast(&mValue), this->size()); -} - -template -inline std::string -TypedMetadata::str() const -{ - std::ostringstream ostr; - ostr << mValue; - return ostr.str(); -} - -template -inline bool -TypedMetadata::asBool() const -{ - return !math::isZero(mValue); -} - -template -inline Metadata::Ptr -TypedMetadata::createMetadata() -{ - Metadata::Ptr ret(new TypedMetadata()); - return ret; -} - -template -inline void -TypedMetadata::registerType() -{ - Metadata::registerType(TypedMetadata::staticTypeName(), - TypedMetadata::createMetadata); -} - -template -inline void -TypedMetadata::unregisterType() -{ - Metadata::unregisterType(TypedMetadata::staticTypeName()); -} - -template -inline bool -TypedMetadata::isRegisteredType() -{ - return Metadata::isRegisteredType(TypedMetadata::staticTypeName()); -} - - -template<> -inline std::string -TypedMetadata::str() const -{ - return (mValue ? "true" : "false"); -} - - -inline std::ostream& -operator<<(std::ostream& ostr, const Metadata& metadata) -{ - ostr << metadata.str(); - return ostr; -} - - -typedef TypedMetadata BoolMetadata; -typedef TypedMetadata DoubleMetadata; -typedef TypedMetadata FloatMetadata; -typedef TypedMetadata Int32Metadata; -typedef TypedMetadata Int64Metadata; -typedef TypedMetadata Vec2DMetadata; -typedef TypedMetadata Vec2IMetadata; -typedef TypedMetadata Vec2SMetadata; -typedef TypedMetadata Vec3DMetadata; -typedef TypedMetadata Vec3IMetadata; -typedef TypedMetadata Vec3SMetadata; -typedef TypedMetadata Mat4SMetadata; -typedef TypedMetadata Mat4DMetadata; - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_METADATA_METADATA_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/metadata/StringMetadata.h b/openvdb_3_0_0_library/metadata/StringMetadata.h deleted file mode 100755 index e22a5d9..0000000 --- a/openvdb_3_0_0_library/metadata/StringMetadata.h +++ /dev/null @@ -1,75 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_METADATA_STRINGMETADATA_HAS_BEEN_INCLUDED -#define OPENVDB_METADATA_STRINGMETADATA_HAS_BEEN_INCLUDED - -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -typedef TypedMetadata StringMetadata; - - -template <> -inline Index32 -StringMetadata::size() const -{ - return Index32(mValue.size()); -} - - -template<> -inline void -StringMetadata::readValue(std::istream& is, Index32 size) -{ - mValue.resize(size, '\0'); - is.read(&mValue[0], size); -} - -template<> -inline void -StringMetadata::writeValue(std::ostream &os) const -{ - os.write(reinterpret_cast(&mValue[0]), this->size()); -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_METADATA_STRINGMETADATA_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/openvdb.cc b/openvdb_3_0_0_library/openvdb.cc deleted file mode 100755 index 34c26be..0000000 --- a/openvdb_3_0_0_library/openvdb.cc +++ /dev/null @@ -1,172 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "openvdb.h" -#include -#include -#ifdef OPENVDB_USE_LOG4CPLUS -#include -#include -#endif -#ifdef OPENVDB_USE_BLOSC -#include -#endif - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -typedef tbb::mutex Mutex; -typedef Mutex::scoped_lock Lock; - -// Declare this at file scope to ensure thread-safe initialization. -Mutex sInitMutex; -bool sIsInitialized = false; - -void -initialize() -{ - Lock lock(sInitMutex); - if (sIsInitialized) return; - -#ifdef OPENVDB_USE_LOG4CPLUS - { - // Configure log4cplus if it was not already configured (at least, - // if there are no appenders associated with the root logger). - log4cplus::Logger rootLogger = log4cplus::Logger::getRoot(); - if (rootLogger.getAllAppenders().empty()) { - log4cplus::BasicConfigurator::doConfigure(); - rootLogger.setLogLevel(log4cplus::WARN_LOG_LEVEL); // was DEBUG_LOG_LEVEL - } - } -#endif - - // Register metadata. - Metadata::clearRegistry(); - BoolMetadata::registerType(); - DoubleMetadata::registerType(); - FloatMetadata::registerType(); - Int32Metadata::registerType(); - Int64Metadata::registerType(); - StringMetadata::registerType(); - Vec2IMetadata::registerType(); - Vec2SMetadata::registerType(); - Vec2DMetadata::registerType(); - Vec3IMetadata::registerType(); - Vec3SMetadata::registerType(); - Vec3DMetadata::registerType(); - Mat4SMetadata::registerType(); - Mat4DMetadata::registerType(); - - // Register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::UnitaryMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Register common grid types. - GridBase::clearRegistry(); - BoolGrid::registerGrid(); - FloatGrid::registerGrid(); - DoubleGrid::registerGrid(); - Int32Grid::registerGrid(); - Int64Grid::registerGrid(); - HermiteGrid::registerGrid(); - StringGrid::registerGrid(); - Vec3IGrid::registerGrid(); - Vec3SGrid::registerGrid(); - Vec3DGrid::registerGrid(); - - // Register types associated with point index grids. - Metadata::registerType(typeNameAsString(), Int32Metadata::createMetadata); - Metadata::registerType(typeNameAsString(), Int64Metadata::createMetadata); - tools::PointIndexGrid::registerGrid(); - -#ifdef OPENVDB_USE_BLOSC - blosc_init(); - if (blosc_set_compressor("lz4") < 0) { - OPENVDB_LOG_WARN("Blosc LZ4 compressor is unavailable"); - } - /// @todo blosc_set_nthreads(int nthreads); -#endif - -#ifdef __ICC -// Disable ICC "assignment to statically allocated variable" warning. -// This assignment is mutex-protected and therefore thread-safe. -__pragma(warning(disable:1711)) -#endif - - sIsInitialized = true; - -#ifdef __ICC -__pragma(warning(default:1711)) -#endif -} - - -void -uninitialize() -{ - Lock lock(sInitMutex); - -#ifdef __ICC -// Disable ICC "assignment to statically allocated variable" warning. -// This assignment is mutex-protected and therefore thread-safe. -__pragma(warning(disable:1711)) -#endif - - sIsInitialized = false; - -#ifdef __ICC -__pragma(warning(default:1711)) -#endif - - Metadata::clearRegistry(); - GridBase::clearRegistry(); - math::MapRegistry::clear(); - -#ifdef OPENVDB_USE_BLOSC - // We don't want to destroy Blosc, because it might have been - // initialized by some other library. - //blosc_destroy(); -#endif -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/openvdb.h b/openvdb_3_0_0_library/openvdb.h deleted file mode 100755 index dc6652e..0000000 --- a/openvdb_3_0_0_library/openvdb.h +++ /dev/null @@ -1,98 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_INIT_HAS_BEEN_INCLUDED -#define OPENVDB_INIT_HAS_BEEN_INCLUDED - -#include "Platform.h" -#include "Types.h" -#include "Metadata.h" -#include "math/Maps.h" -#include "math/Transform.h" -#include "Grid.h" -#include "tree/Tree.h" -#include "io/File.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// Common tree types -typedef tree::Tree4::Type BoolTree; -typedef tree::Tree4::Type FloatTree; -typedef tree::Tree4::Type DoubleTree; -typedef tree::Tree4::Type Int32Tree; -typedef tree::Tree4::Type UInt32Tree; -typedef tree::Tree4::Type Int64Tree; -typedef tree::Tree4::Type HermiteTree; -typedef tree::Tree4::Type Vec2ITree; -typedef tree::Tree4::Type Vec2STree; -typedef tree::Tree4::Type Vec2DTree; -typedef tree::Tree4::Type Vec3ITree; -typedef tree::Tree4::Type Vec3STree; -typedef tree::Tree4::Type Vec3DTree; -typedef tree::Tree4::Type StringTree; -typedef Vec3STree Vec3fTree; -typedef Vec3DTree Vec3dTree; -typedef FloatTree ScalarTree; -typedef Vec3fTree VectorTree; - -/// Common grid types -typedef Grid BoolGrid; -typedef Grid FloatGrid; -typedef Grid DoubleGrid; -typedef Grid Int32Grid; -typedef Grid Int64Grid; -typedef Grid HermiteGrid; -typedef Grid Vec3IGrid; -typedef Grid Vec3SGrid; -typedef Grid Vec3DGrid; -typedef Grid StringGrid; -typedef Vec3SGrid Vec3fGrid; -typedef Vec3DGrid Vec3dGrid; -typedef FloatGrid ScalarGrid; -typedef Vec3fGrid VectorGrid; - - -/// Global registration of basic types -OPENVDB_API void initialize(); - -/// Global deregistration of basic types -OPENVDB_API void uninitialize(); - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_INIT_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyAccessor.h b/openvdb_3_0_0_library/python/pyAccessor.h deleted file mode 100755 index b4956af..0000000 --- a/openvdb_3_0_0_library/python/pyAccessor.h +++ /dev/null @@ -1,343 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_PYACCESSOR_HAS_BEEN_INCLUDED -#define OPENVDB_PYACCESSOR_HAS_BEEN_INCLUDED - -#include -#include "openvdb/openvdb.h" -#include "pyutil.h" - -namespace pyAccessor { - -namespace py = boost::python; -using namespace openvdb::OPENVDB_VERSION_NAME; - - -//@{ -/// Type traits for grid accessors -template -struct AccessorTraits -{ - typedef _GridT GridT; - typedef GridT NonConstGridT; - typedef typename NonConstGridT::Ptr GridPtrT; - typedef typename NonConstGridT::Accessor AccessorT; - typedef typename AccessorT::ValueType ValueT; - - static const bool IsConst = false; - - static const char* typeName() { return "Accessor"; } - - static void setActiveState(AccessorT& acc, const Coord& ijk, bool on) { - acc.setActiveState(ijk, on); - } - static void setValueOnly(AccessorT& acc, const Coord& ijk, const ValueT& val) { - acc.setValueOnly(ijk, val); - } - static void setValueOn(AccessorT& acc, const Coord& ijk) { acc.setValueOn(ijk); } - static void setValueOn(AccessorT& acc, const Coord& ijk, const ValueT& val) { - acc.setValueOn(ijk, val); - } - static void setValueOff(AccessorT& acc, const Coord& ijk) { acc.setValueOff(ijk); } - static void setValueOff(AccessorT& acc, const Coord& ijk, const ValueT& val) { - acc.setValueOff(ijk, val); - } -}; - -// Partial specialization for const accessors -template -struct AccessorTraits -{ - typedef const _GridT GridT; - typedef _GridT NonConstGridT; - typedef typename NonConstGridT::ConstPtr GridPtrT; - typedef typename NonConstGridT::ConstAccessor AccessorT; - typedef typename AccessorT::ValueType ValueT; - - static const bool IsConst = true; - - static const char* typeName() { return "ConstAccessor"; } - - static void setActiveState(AccessorT&, const Coord&, bool) { notWritable(); } - static void setValueOnly(AccessorT&, const Coord&, const ValueT&) { notWritable(); } - static void setValueOn(AccessorT&, const Coord&) { notWritable(); } - static void setValueOn(AccessorT&, const Coord&, const ValueT&) { notWritable(); } - static void setValueOff(AccessorT&, const Coord&) { notWritable(); } - static void setValueOff(AccessorT&, const Coord&, const ValueT&) { notWritable(); } - - static void notWritable() - { - PyErr_SetString(PyExc_TypeError, "accessor is read-only"); - py::throw_error_already_set(); - } -}; -//@} - - -//////////////////////////////////////// - - -/// Variant of pyutil::extractArg() that extracts a Coord from a py::object -/// argument to a given ValueAccessor method -template -inline Coord -extractCoordArg(py::object obj, const char* functionName, int argIdx = 0) -{ - return pyutil::extractArg(obj, functionName, - AccessorTraits::typeName(), argIdx, "tuple(int, int, int)"); -} - - -/// Variant of pyutil::extractArg() that extracts a value of type -/// ValueAccessor::ValueType from an argument to a ValueAccessor method -template -inline typename GridT::ValueType -extractValueArg( - py::object obj, - const char* functionName, - int argIdx = 0, // args are numbered starting from 1 - const char* expectedType = NULL) -{ - return pyutil::extractArg( - obj, functionName, AccessorTraits::typeName(), argIdx, expectedType); -} - - -//////////////////////////////////////// - - -/// @brief ValueAccessor wrapper class that also stores a grid pointer, -/// so that the grid doesn't get deleted as long as the accessor is live -/// -/// @internal This class could have just been made to inherit from ValueAccessor, -/// but the method wrappers allow for more Pythonic error messages. For example, -/// if we constructed the Python getValue() method directly from the corresponding -/// ValueAccessor method, as follows, -/// -/// .def("getValue", &Accessor::getValue, ...) -/// -/// then the conversion from a Python type to a Coord& would be done -/// automatically. But if the Python method were called with an object of -/// a type that is not convertible to a Coord, then the TypeError message -/// would say something like "TypeError: No registered converter was able to -/// produce a C++ rvalue of type openvdb::math::Coord...". -/// Handling the type conversion manually is more work, but it allows us to -/// instead generate messages like "TypeError: expected tuple(int, int, int), -/// found str as argument to FloatGridAccessor.getValue()". -template -class AccessorWrap -{ -public: - typedef AccessorTraits<_GridType> Traits; - typedef typename Traits::AccessorT Accessor; - typedef typename Traits::ValueT ValueType; - typedef typename Traits::NonConstGridT GridType; - typedef typename Traits::GridPtrT GridPtrType; - - AccessorWrap(GridPtrType grid): mGrid(grid), mAccessor(grid->getAccessor()) {} - - AccessorWrap copy() const { return *this; } - - void clear() { mAccessor.clear(); } - - GridPtrType parent() const { return mGrid; } - - ValueType getValue(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "getValue"); - return mAccessor.getValue(ijk); - } - - int getValueDepth(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "getValueDepth"); - return mAccessor.getValueDepth(ijk); - } - - int isVoxel(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "isVoxel"); - return mAccessor.isVoxel(ijk); - } - - py::tuple probeValue(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "probeValue"); - ValueType value; - bool on = mAccessor.probeValue(ijk, value); - return py::make_tuple(value, on); - } - - bool isValueOn(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "isValueOn"); - return mAccessor.isValueOn(ijk); - } - - void setActiveState(py::object coordObj, bool on) - { - const Coord ijk = extractCoordArg(coordObj, "setActiveState", /*argIdx=*/1); - Traits::setActiveState(mAccessor, ijk, on); - } - - void setValueOnly(py::object coordObj, py::object valObj) - { - Coord ijk = extractCoordArg(coordObj, "setValueOnly", 1); - ValueType val = extractValueArg(valObj, "setValueOnly", 2); - Traits::setValueOnly(mAccessor, ijk, val); - } - - void setValueOn(py::object coordObj, py::object valObj) - { - Coord ijk = extractCoordArg(coordObj, "setValueOn", 1); - if (valObj.is_none()) { - Traits::setValueOn(mAccessor, ijk); - } else { - ValueType val = extractValueArg(valObj, "setValueOn", 2); - Traits::setValueOn(mAccessor, ijk, val); - } - } - - void setValueOff(py::object coordObj, py::object valObj) - { - Coord ijk = extractCoordArg(coordObj, "setValueOff", 1); - if (valObj.is_none()) { - Traits::setValueOff(mAccessor, ijk); - } else { - ValueType val = extractValueArg(valObj, "setValueOff", 2); - Traits::setValueOff(mAccessor, ijk, val); - } - } - - int isCached(py::object coordObj) - { - const Coord ijk = extractCoordArg(coordObj, "isCached"); - return mAccessor.isCached(ijk); - } - - /// @brief Define a Python wrapper class for this C++ class. - static void wrap() - { - const std::string - pyGridTypeName = pyutil::GridTraits::name(), - pyValueTypeName = openvdb::typeNameAsString(), - pyAccessorTypeName = Traits::typeName(); - - py::class_ clss( - pyAccessorTypeName.c_str(), - (std::string(Traits::IsConst ? "Read-only" : "Read/write") - + " access by (i, j, k) index coordinates to the voxels\nof a " - + pyGridTypeName).c_str(), - py::no_init); - - clss.def("copy", &AccessorWrap::copy, - ("copy() -> " + pyAccessorTypeName + "\n\n" - "Return a copy of this accessor.").c_str()) - - .def("clear", &AccessorWrap::clear, - "clear()\n\n" - "Clear this accessor of all cached data.") - - .add_property("parent", &AccessorWrap::parent, - ("this accessor's parent " + pyGridTypeName).c_str()) - - // - // Voxel access - // - .def("getValue", &AccessorWrap::getValue, - py::arg("ijk"), - ("getValue(ijk) -> " + pyValueTypeName + "\n\n" - "Return the value of the voxel at coordinates (i, j, k).").c_str()) - - .def("getValueDepth", &AccessorWrap::getValueDepth, - py::arg("ijk"), - "getValueDepth(ijk) -> int\n\n" - "Return the tree depth (0 = root) at which the value of voxel\n" - "(i, j, k) resides. If (i, j, k) isn't explicitly represented in\n" - "the tree (i.e., it is implicitly a background voxel), return -1.") - - .def("isVoxel", &AccessorWrap::isVoxel, - py::arg("ijk"), - "isVoxel(ijk) -> bool\n\n" - "Return True if voxel (i, j, k) resides at the leaf level of the tree.") - - .def("probeValue", &AccessorWrap::probeValue, - py::arg("ijk"), - "probeValue(ijk) -> value, bool\n\n" - "Return the value of the voxel at coordinates (i, j, k)\n" - "together with the voxel's active state.") - - .def("isValueOn", &AccessorWrap::isValueOn, - py::arg("ijk"), - "isValueOn(ijk) -> bool\n\n" - "Return the active state of the voxel at coordinates (i, j, k).") - .def("setActiveState", &AccessorWrap::setActiveState, - (py::arg("ijk"), py::arg("on")), - "setActiveState(ijk, on)\n\n" - "Mark voxel (i, j, k) as either active or inactive (True or False),\n" - "but don't change its value.") - - .def("setValueOnly", &AccessorWrap::setValueOnly, - (py::arg("ijk"), py::arg("value")), - "setValueOnly(ijk, value)\n\n" - "Set the value of voxel (i, j, k), but don't change its active state.") - - .def("setValueOn", &AccessorWrap::setValueOn, - (py::arg("ijk"), py::arg("value") = py::object()), - "setValueOn(ijk, value=None)\n\n" - "Mark voxel (i, j, k) as active and, if the given value\n" - "is not None, set the voxel's value.\n") - .def("setValueOff", &AccessorWrap::setValueOff, - (py::arg("ijk"), py::arg("value") = py::object()), - "setValueOff(ijk, value=None)\n\n" - "Mark voxel (i, j, k) as inactive and, if the given value\n" - "is not None, set the voxel's value.") - - .def("isCached", &AccessorWrap::isCached, - py::arg("ijk"), - "isCached(ijk) -> bool\n\n" - "Return True if this accessor has cached the path to voxel (i, j, k).") - - ; // py::class_ - } - -private: - const GridPtrType mGrid; - Accessor mAccessor; -}; // class AccessorWrap - -} // namespace pyAccessor - -#endif // OPENVDB_PYACCESSOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyFloatGrid.cc b/openvdb_3_0_0_library/python/pyFloatGrid.cc deleted file mode 100755 index 56e2b84..0000000 --- a/openvdb_3_0_0_library/python/pyFloatGrid.cc +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file pyFloatGrid.cc -/// @author Peter Cucka -/// @brief Boost.Python wrappers for scalar, floating-point openvdb::Grid types - -#include "pyGrid.h" - - -/// Create a Python wrapper for each supported Grid type. -void -exportFloatGrid() -{ - // Add a module-level list that gives the types of all supported Grid classes. - py::scope().attr("GridTypes") = py::list(); - - // Specify that py::numeric::array should refer to the Python type numpy.ndarray - // (rather than the older Numeric.array). - py::numeric::array::set_module_and_type("numpy", "ndarray"); - - pyGrid::exportGrid(); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES - pyGrid::exportGrid(); -#endif - - py::def("createLevelSetSphere", - &pyGrid::createLevelSetSphere, - (py::arg("radius"), py::arg("center")=openvdb::Coord(), py::arg("voxelSize")=1.0, - py::arg("halfWidth")=openvdb::LEVEL_SET_HALF_WIDTH), - "createLevelSetSphere(radius, center, voxelSize, halfWidth) -> FloatGrid\n\n" - "Return a grid containing a narrow-band level set representation\n" - "of a sphere."); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyGrid.h b/openvdb_3_0_0_library/python/pyGrid.h deleted file mode 100755 index 8479065..0000000 --- a/openvdb_3_0_0_library/python/pyGrid.h +++ /dev/null @@ -1,2298 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file pyGrid.h -/// @author Peter Cucka -/// @brief Boost.Python wrapper for openvdb::Grid - -#ifndef OPENVDB_PYGRID_HAS_BEEN_INCLUDED -#define OPENVDB_PYGRID_HAS_BEEN_INCLUDED - -#include -#include -#include -#ifdef PY_OPENVDB_USE_NUMPY -#define PY_ARRAY_UNIQUE_SYMBOL PY_OPENVDB_ARRAY_API -#define NO_IMPORT_ARRAY // NumPy gets initialized during module initialization -#include // for PyArrayObject -#include "openvdb/tools/MeshToVolume.h" -#include "openvdb/tools/VolumeToMesh.h" // for tools::volumeToMesh() -#endif -#include "openvdb/openvdb.h" -#include "openvdb/io/Stream.h" -#include "openvdb/math/Math.h" // for math::isExactlyEqual() -#include "openvdb/tools/LevelSetSphere.h" -#include "openvdb/tools/Dense.h" -#include "openvdb/tools/ChangeBackground.h" -#include "openvdb/tools/Prune.h" -#include "openvdb/tools/SignedFloodFill.h" -#include "pyutil.h" -#include "pyAccessor.h" // for pyAccessor::AccessorWrap -#include "pyopenvdb.h" -#include // for memcpy() -#include - -namespace py = boost::python; -using namespace openvdb::OPENVDB_VERSION_NAME; - - -namespace pyopenvdb { - -inline py::object -getPyObjectFromGrid(const GridBase::Ptr& grid) -{ - if (!grid) return py::object(); - -#define CONVERT_BASE_TO_GRID(GridType, grid) \ - if (grid->isType()) { \ - return py::object(gridPtrCast(grid)); \ - } - - CONVERT_BASE_TO_GRID(FloatGrid, grid); - CONVERT_BASE_TO_GRID(Vec3SGrid, grid); - CONVERT_BASE_TO_GRID(BoolGrid, grid); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES - CONVERT_BASE_TO_GRID(DoubleGrid, grid); - CONVERT_BASE_TO_GRID(Int32Grid, grid); - CONVERT_BASE_TO_GRID(Int64Grid, grid); - CONVERT_BASE_TO_GRID(Vec3IGrid, grid); - CONVERT_BASE_TO_GRID(Vec3DGrid, grid); -#endif -#undef CONVERT_BASE_TO_GRID - - OPENVDB_THROW(TypeError, grid->type() + " is not a supported OpenVDB grid type"); -} - - -inline openvdb::GridBase::Ptr -getGridFromPyObject(const boost::python::object& gridObj) -{ - if (!gridObj) return GridBase::Ptr(); - -#define CONVERT_GRID_TO_BASE(GridPtrType) \ - { \ - py::extract x(gridObj); \ - if (x.check()) return x(); \ - } - - // Extract a grid pointer of one of the supported types - // from the input object, then cast it to a base pointer. - CONVERT_GRID_TO_BASE(FloatGrid::Ptr); - CONVERT_GRID_TO_BASE(Vec3SGrid::Ptr); - CONVERT_GRID_TO_BASE(BoolGrid::Ptr); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES - CONVERT_GRID_TO_BASE(DoubleGrid::Ptr); - CONVERT_GRID_TO_BASE(Int32Grid::Ptr); - CONVERT_GRID_TO_BASE(Int64Grid::Ptr); - CONVERT_GRID_TO_BASE(Vec3IGrid::Ptr); - CONVERT_GRID_TO_BASE(Vec3DGrid::Ptr); -#endif -#undef CONVERT_GRID_TO_BASE - - OPENVDB_THROW(TypeError, - pyutil::className(gridObj) + " is not a supported OpenVDB grid type"); -} - - -inline openvdb::GridBase::Ptr -getGridFromPyObject(PyObject* gridObj) -{ - return getGridFromPyObject(pyutil::pyBorrow(gridObj)); -} - -} // namespace pyopenvdb - - -//////////////////////////////////////// - - -namespace pyGrid { - -inline py::object -getGridFromGridBase(GridBase::Ptr grid) -{ - py::object obj; - try { - obj = pyopenvdb::getPyObjectFromGrid(grid); - } catch (openvdb::TypeError& e) { - PyErr_SetString(PyExc_TypeError, e.what()); - py::throw_error_already_set(); - return py::object(); - } - return obj; -} - - -/// GridBase is not exposed in Python because it isn't really needed -/// (and because exposing it would be complicated, requiring wrapping -/// pure virtual functions like GridBase::baseTree()), but there are -/// a few cases where, internally, we need to extract a GridBase::Ptr -/// from a py::object. Hence this converter. -inline GridBase::Ptr -getGridBaseFromGrid(py::object gridObj) -{ - GridBase::Ptr grid; - try { - grid = pyopenvdb::getGridFromPyObject(gridObj); - } catch (openvdb::TypeError& e) { - PyErr_SetString(PyExc_TypeError, e.what()); - py::throw_error_already_set(); - return GridBase::Ptr(); - } - return grid; -} - - -//////////////////////////////////////// - - -/// Variant of pyutil::extractArg() that uses the class name of a given grid type -template -inline T -extractValueArg( - py::object obj, - const char* functionName, - int argIdx = 0, // args are numbered starting from 1 - const char* expectedType = NULL) -{ - return pyutil::extractArg(obj, - functionName, pyutil::GridTraits::name(), argIdx, expectedType); -} - - -/// @brief Variant of pyutil::extractArg() that uses the class name -/// and @c ValueType of a given grid type -template -inline typename GridType::ValueType -extractValueArg( - py::object obj, - const char* functionName, - int argIdx = 0, // args are numbered starting from 1 - const char* expectedType = NULL) -{ - return extractValueArg( - obj, functionName, argIdx, expectedType); -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -copyGrid(const GridType& grid) -{ - return grid.copy(); -} - - -template -inline bool -sharesWith(const GridType& grid, py::object other) -{ - py::extract x(other); - if (x.check()) { - typename GridType::ConstPtr otherGrid = x(); - return (&otherGrid->tree() == &grid.tree()); - } - return false; -} - - -//////////////////////////////////////// - - -template -inline std::string -getValueType() -{ - return pyutil::GridTraits::valueTypeName(); -} - - -template -inline typename GridType::ValueType -getZeroValue() -{ - return openvdb::zeroVal(); -} - - -template -inline typename GridType::ValueType -getOneValue() -{ - typedef typename GridType::ValueType ValueT; - return ValueT(openvdb::zeroVal() + 1); -} - - -template -inline bool -notEmpty(const GridType& grid) -{ - return !grid.empty(); -} - - -template -inline typename GridType::ValueType -getGridBackground(const GridType& grid) -{ - return grid.background(); -} - - -template -inline void -setGridBackground(GridType& grid, py::object obj) -{ - tools::changeBackground(grid.tree(), extractValueArg(obj, "setBackground")); -} - - -inline void -setGridName(GridBase::Ptr grid, py::object strObj) -{ - if (grid) { - if (!strObj) { // if name is None - grid->removeMeta(GridBase::META_GRID_NAME); - } else { - const std::string name = pyutil::extractArg( - strObj, "setName", /*className=*/NULL, /*argIdx=*/1, "str"); - grid->setName(name); - } - } -} - - -inline void -setGridCreator(GridBase::Ptr grid, py::object strObj) -{ - if (grid) { - if (!strObj) { // if name is None - grid->removeMeta(GridBase::META_GRID_CREATOR); - } else { - const std::string name = pyutil::extractArg( - strObj, "setCreator", /*className=*/NULL, /*argIdx=*/1, "str"); - grid->setCreator(name); - } - } -} - - -inline std::string -getGridClass(GridBase::ConstPtr grid) -{ - return GridBase::gridClassToString(grid->getGridClass()); -} - - -inline void -setGridClass(GridBase::Ptr grid, py::object strObj) -{ - if (!strObj) { - grid->clearGridClass(); - } else { - const std::string name = pyutil::extractArg( - strObj, "setGridClass", /*className=*/NULL, /*argIdx=*/1, "str"); - grid->setGridClass(GridBase::stringToGridClass(name)); - } -} - - -inline std::string -getVecType(GridBase::ConstPtr grid) -{ - return GridBase::vecTypeToString(grid->getVectorType()); -} - - -inline void -setVecType(GridBase::Ptr grid, py::object strObj) -{ - if (!strObj) { - grid->clearVectorType(); - } else { - const std::string name = pyutil::extractArg( - strObj, "setVectorType", /*className=*/NULL, /*argIdx=*/1, "str"); - grid->setVectorType(GridBase::stringToVecType(name)); - } -} - - -inline std::string -gridInfo(GridBase::ConstPtr grid, int verbosity) -{ - std::ostringstream ostr; - grid->print(ostr, std::max(1, verbosity)); - return ostr.str(); -} - - -//////////////////////////////////////// - - -inline void -setGridTransform(GridBase::Ptr grid, py::object xformObj) -{ - if (grid) { - if (math::Transform::Ptr xform = pyutil::extractArg( - xformObj, "setTransform", /*className=*/NULL, /*argIdx=*/1, "Transform")) - { - grid->setTransform(xform); - } else { - PyErr_SetString(PyExc_ValueError, "null transform"); - py::throw_error_already_set(); - } - } -} - - -//////////////////////////////////////// - - -// Helper class to construct a pyAccessor::AccessorWrap for a given grid, -// permitting partial specialization for const vs. non-const grids -template -struct AccessorHelper -{ - typedef typename pyAccessor::AccessorWrap Wrapper; - static Wrapper wrap(typename GridType::Ptr grid) - { - if (!grid) { - PyErr_SetString(PyExc_ValueError, "null grid"); - py::throw_error_already_set(); - } - return Wrapper(grid); - } -}; - -// Specialization for const grids -template -struct AccessorHelper -{ - typedef typename pyAccessor::AccessorWrap Wrapper; - static Wrapper wrap(typename GridType::ConstPtr grid) - { - if (!grid) { - PyErr_SetString(PyExc_ValueError, "null grid"); - py::throw_error_already_set(); - } - return Wrapper(grid); - } -}; - - -/// Return a non-const accessor (wrapped in a pyAccessor::AccessorWrap) for the given grid. -template -inline typename AccessorHelper::Wrapper -getAccessor(typename GridType::Ptr grid) -{ - return AccessorHelper::wrap(grid); -} - -/// @brief Return a const accessor (wrapped in a pyAccessor::AccessorWrap) for the given grid. -/// @internal Note that the grid pointer is non-const, even though the grid is -/// treated as const. This is because we don't expose a const grid type in Python. -template -inline typename AccessorHelper::Wrapper -getConstAccessor(typename GridType::Ptr grid) -{ - return AccessorHelper::wrap(grid); -} - - -//////////////////////////////////////// - - -template -inline py::tuple -evalLeafBoundingBox(const GridType& grid) -{ - CoordBBox bbox; - grid.tree().evalLeafBoundingBox(bbox); - return py::make_tuple(bbox.min(), bbox.max()); -} - - -template -inline Coord -evalLeafDim(const GridType& grid) -{ - Coord dim; - grid.tree().evalLeafDim(dim); - return dim; -} - - -template -inline py::tuple -evalActiveVoxelBoundingBox(const GridType& grid) -{ - CoordBBox bbox = grid.evalActiveVoxelBoundingBox(); - return py::make_tuple(bbox.min(), bbox.max()); -} - - -template -inline py::tuple -getNodeLog2Dims(const GridType& grid) -{ - std::vector dims; - grid.tree().getNodeLog2Dims(dims); - py::list lst; - for (size_t i = 0, N = dims.size(); i < N; ++i) { - lst.append(dims[i]); - } - return py::tuple(lst); -} - - -template -inline Index -treeDepth(const GridType& grid) -{ - return grid.tree().treeDepth(); -} - - -template -inline Index32 -leafCount(const GridType& grid) -{ - return grid.tree().leafCount(); -} - - -template -inline Index32 -nonLeafCount(const GridType& grid) -{ - return grid.tree().nonLeafCount(); -} - - -template -inline Index64 -activeLeafVoxelCount(const GridType& grid) -{ - return grid.tree().activeLeafVoxelCount(); -} - - -template -inline py::tuple -evalMinMax(const GridType& grid) -{ - typename GridType::ValueType vmin, vmax; - grid.tree().evalMinMax(vmin, vmax); - return py::make_tuple(vmin, vmax); -} - - -template -inline py::tuple -getIndexRange(const GridType& grid) -{ - CoordBBox bbox; - grid.tree().getIndexRange(bbox); - return py::make_tuple(bbox.min(), bbox.max()); -} - - -//template -//inline void -//expandIndexRange(GridType& grid, py::object coordObj) -//{ -// Coord xyz = extractValueArg( -// coordObj, "expand", 0, "tuple(int, int, int)"); -// grid.tree().expand(xyz); -//} - - -//////////////////////////////////////// - - -inline py::dict -getAllMetadata(GridBase::ConstPtr grid) -{ - if (grid) return py::dict(static_cast(*grid)); - return py::dict(); -} - - -inline void -replaceAllMetadata(GridBase::Ptr grid, const MetaMap& metadata) -{ - if (grid) { - grid->clearMetadata(); - for (MetaMap::ConstMetaIterator it = metadata.beginMeta(); - it != metadata.endMeta(); ++it) - { - if (it->second) grid->insertMeta(it->first, *it->second); - } - } -} - - -inline void -updateMetadata(GridBase::Ptr grid, const MetaMap& metadata) -{ - if (grid) { - for (MetaMap::ConstMetaIterator it = metadata.beginMeta(); - it != metadata.endMeta(); ++it) - { - if (it->second) { - grid->removeMeta(it->first); - grid->insertMeta(it->first, *it->second); - } - } - } -} - - -inline py::dict -getStatsMetadata(GridBase::ConstPtr grid) -{ - MetaMap::ConstPtr metadata; - if (grid) metadata = grid->getStatsMetadata(); - if (metadata) return py::dict(*metadata); - return py::dict(); -} - - -inline py::object -getMetadataKeys(GridBase::ConstPtr grid) -{ - if (grid) return py::dict(static_cast(*grid)).iterkeys(); - return py::object(); -} - - -inline py::object -getMetadata(GridBase::ConstPtr grid, py::object nameObj) -{ - if (!grid) return py::object(); - - const std::string name = pyutil::extractArg( - nameObj, "__getitem__", NULL, /*argIdx=*/1, "str"); - - Metadata::ConstPtr metadata = (*grid)[name]; - if (!metadata) { - PyErr_SetString(PyExc_KeyError, name.c_str()); - py::throw_error_already_set(); - } - - // Use the MetaMap-to-dict converter (see pyOpenVDBModule.cc) to convert - // the Metadata value to a Python object of the appropriate type. - /// @todo Would be more efficient to convert the Metadata object - /// directly to a Python object. - MetaMap metamap; - metamap.insertMeta(name, *metadata); - return py::dict(metamap)[name]; -} - - -inline void -setMetadata(GridBase::Ptr grid, py::object nameObj, py::object valueObj) -{ - if (!grid) return; - - const std::string name = pyutil::extractArg( - nameObj, "__setitem__", NULL, /*argIdx=*/1, "str"); - - // Insert the Python object into a Python dict, then use the dict-to-MetaMap - // converter (see pyOpenVDBModule.cc) to convert the dict to a MetaMap - // containing a Metadata object of the appropriate type. - /// @todo Would be more efficient to convert the Python object - /// directly to a Metadata object. - py::dict dictObj; - dictObj[name] = valueObj; - MetaMap metamap = py::extract(dictObj); - - if (Metadata::Ptr metadata = metamap[name]) { - grid->removeMeta(name); - grid->insertMeta(name, *metadata); - } -} - - -inline void -removeMetadata(GridBase::Ptr grid, const std::string& name) -{ - if (grid) { - Metadata::Ptr metadata = (*grid)[name]; - if (!metadata) { - PyErr_SetString(PyExc_KeyError, name.c_str()); - py::throw_error_already_set(); - } - grid->removeMeta(name); - } -} - - -inline bool -hasMetadata(GridBase::ConstPtr grid, const std::string& name) -{ - if (grid) return ((*grid)[name].get() != NULL); - return false; -} - - -//////////////////////////////////////// - - -template -inline void -prune(GridType& grid, py::object tolerance) -{ - tools::prune(grid.tree(), extractValueArg(tolerance, "prune")); -} - - -template -inline void -pruneInactive(GridType& grid, py::object valObj) -{ - if (valObj.is_none()) { - tools::pruneInactive(grid.tree()); - } else { - tools::pruneInactiveWithValue( - grid.tree(), extractValueArg(valObj, "pruneInactive")); - } -} - - -template -inline void -fill(GridType& grid, py::object minObj, py::object maxObj, - py::object valObj, bool active) -{ - const Coord - bmin = extractValueArg(minObj, "fill", 1, "tuple(int, int, int)"), - bmax = extractValueArg(maxObj, "fill", 2, "tuple(int, int, int)"); - grid.fill(CoordBBox(bmin, bmax), extractValueArg(valObj, "fill", 3), active); -} - - -template -inline void -signedFloodFill(GridType& grid) -{ - tools::signedFloodFill(grid.tree()); -} - - -//////////////////////////////////////// - - -#ifndef PY_OPENVDB_USE_NUMPY - -template -inline void -copyFromArray(GridType&, const py::object&, py::object, py::object) -{ - PyErr_SetString(PyExc_NotImplementedError, "this module was built without NumPy support"); - boost::python::throw_error_already_set(); -} - -template -inline void -copyToArray(GridType&, const py::object&, py::object) -{ - PyErr_SetString(PyExc_NotImplementedError, "this module was built without NumPy support"); - boost::python::throw_error_already_set(); -} - -#else // if defined(PY_OPENVDB_USE_NUMPY) - -template struct NumPyToCpp {}; -//template<> struct NumPyToCpp { typedef half type; }; -template<> struct NumPyToCpp { typedef float type; }; -template<> struct NumPyToCpp { typedef double type; }; -template<> struct NumPyToCpp { typedef bool type; }; -template<> struct NumPyToCpp { typedef Int16 type; }; -template<> struct NumPyToCpp { typedef Int32 type; }; -template<> struct NumPyToCpp { typedef Int64 type; }; -template<> struct NumPyToCpp { typedef Index32 type; }; -template<> struct NumPyToCpp { typedef Index64 type; }; - -#if 0 -template struct CppToNumPy {}; -//template<> struct NumPyToCpp { enum { typenum = NPY_HALF }; }; -template<> struct CppToNumPy { enum { typenum = NPY_FLOAT }; }; -template<> struct CppToNumPy { enum { typenum = NPY_DOUBLE }; }; -template<> struct CppToNumPy { enum { typenum = NPY_BOOL }; }; -template<> struct CppToNumPy { enum { typenum = NPY_INT16 }; }; -template<> struct CppToNumPy { enum { typenum = NPY_INT32 }; }; -template<> struct CppToNumPy { enum { typenum = NPY_INT64 }; }; -template<> struct CppToNumPy { enum { typenum = NPY_UINT32 }; }; -template<> struct CppToNumPy { enum { typenum = NPY_UINT64 }; }; -#endif - - -// Abstract base class for helper classes that copy data between -// NumPy arrays of various types and grids of various types -template -class CopyOpBase -{ -public: - typedef typename GridType::ValueType ValueT; - - CopyOpBase(bool toGrid, GridType& grid, py::object arrObj, - py::object coordObj, py::object tolObj) - : mToGrid(toGrid) - , mGrid(&grid) - { - const char* const opName[2] = { "copyToArray", "copyFromArray" }; - - // Extract the coordinates (i, j, k) of the voxel at which to start populating data. - // Voxel (i, j, k) will correspond to array element (0, 0, 0). - const Coord origin = extractValueArg( - coordObj, opName[toGrid], 1, "tuple(int, int, int)"); - - // Extract a reference to (not a copy of) the NumPy array, - // or throw an exception if arrObj is not a NumPy array object. - const py::numeric::array arrayObj = pyutil::extractArg( - arrObj, opName[toGrid], pyutil::GridTraits::name(), - /*argIdx=*/1, "numpy.ndarray"); - - PyArrayObject* arrayObjPtr = reinterpret_cast(arrayObj.ptr()); - - const PyArray_Descr* dtype = PyArray_DESCR(arrayObjPtr); - const py::object shape = arrayObj.attr("shape"); - - if (PyObject_HasAttrString(arrayObj.ptr(), "dtype")) { - mArrayTypeName = pyutil::str(arrayObj.attr("dtype")); - } else { - mArrayTypeName = "'_'"; - mArrayTypeName[1] = dtype->kind; - } - - mArray = PyArray_DATA(arrayObjPtr); - mArrayTypeNum = dtype->type_num; - mTolerance = extractValueArg(tolObj, opName[toGrid], 2); - for (long i = 0, N = py::len(shape); i < N; ++i) { - mArrayDims.push_back(py::extract(shape[i])); - } - // Compute the bounding box of the region of the grid that is to be copied from or to. - mBBox.reset(origin, origin.offsetBy(mArrayDims[0]-1, mArrayDims[1]-1, mArrayDims[2]-1)); - } - virtual ~CopyOpBase() {} - - void operator()() const - { - try { - if (mToGrid) { - copyFromArray(); // copy data from the array to the grid - } else { - copyToArray(); // copy data from the grid to the array - } - } catch (openvdb::TypeError&) { - PyErr_Format(PyExc_TypeError, - "unsupported NumPy data type %s", mArrayTypeName.c_str()); - boost::python::throw_error_already_set(); - } - } - -protected: - virtual void validate() const = 0; - virtual void copyFromArray() const = 0; - virtual void copyToArray() const = 0; - - template - void fromArray() const - { - validate(); - tools::Dense valArray(mBBox, static_cast(mArray)); - tools::copyFromDense(valArray, *mGrid, mTolerance); - } - - template - void toArray() const - { - validate(); - tools::Dense valArray(mBBox, static_cast(mArray)); - tools::copyToDense(*mGrid, valArray); - } - - - bool mToGrid; // if true, copy from the array to the grid, else vice-versa - void* mArray; - GridType* mGrid; - int mArrayTypeNum; - std::vector mArrayDims; - std::string mArrayTypeName; - CoordBBox mBBox; - ValueT mTolerance; -}; // class CopyOpBase - - -// Helper subclass that can be specialized for various grid and NumPy array types -template class CopyOp: public CopyOpBase {}; - -// Specialization for scalar grids -template -class CopyOp: public CopyOpBase -{ -public: - CopyOp(bool toGrid, GridType& grid, py::object arrObj, py::object coordObj, - py::object tolObj = py::object(zeroVal())): - CopyOpBase(toGrid, grid, arrObj, coordObj, tolObj) - { - } - -protected: - virtual void validate() const - { - if (this->mArrayDims.size() != 3) { - std::ostringstream os; - os << "expected 3-dimensional array, found " - << this->mArrayDims.size() << "-dimensional array"; - PyErr_SetString(PyExc_ValueError, os.str().c_str()); - boost::python::throw_error_already_set(); - } - } - - virtual void copyFromArray() const - { - switch (this->mArrayTypeNum) { - case NPY_FLOAT: this->template fromArray::type>(); break; - case NPY_DOUBLE: this->template fromArray::type>(); break; - case NPY_BOOL: this->template fromArray::type>(); break; - case NPY_INT16: this->template fromArray::type>(); break; - case NPY_INT32: this->template fromArray::type>(); break; - case NPY_INT64: this->template fromArray::type>(); break; - case NPY_UINT32: this->template fromArray::type>(); break; - case NPY_UINT64: this->template fromArray::type>(); break; - default: throw openvdb::TypeError(); break; - } - } - - virtual void copyToArray() const - { - switch (this->mArrayTypeNum) { - case NPY_FLOAT: this->template toArray::type>(); break; - case NPY_DOUBLE: this->template toArray::type>(); break; - case NPY_BOOL: this->template toArray::type>(); break; - case NPY_INT16: this->template toArray::type>(); break; - case NPY_INT32: this->template toArray::type>(); break; - case NPY_INT64: this->template toArray::type>(); break; - case NPY_UINT32: this->template toArray::type>(); break; - case NPY_UINT64: this->template toArray::type>(); break; - default: throw openvdb::TypeError(); break; - } - } -}; // class CopyOp - -// Specialization for Vec3 grids -template -class CopyOp: public CopyOpBase -{ -public: - CopyOp(bool toGrid, GridType& grid, py::object arrObj, py::object coordObj, - py::object tolObj = py::object(zeroVal())): - CopyOpBase(toGrid, grid, arrObj, coordObj, tolObj) - { - } - -protected: - virtual void validate() const - { - if (this->mArrayDims.size() != 4) { - std::ostringstream os; - os << "expected 4-dimensional array, found " - << this->mArrayDims.size() << "-dimensional array"; - PyErr_SetString(PyExc_ValueError, os.str().c_str()); - boost::python::throw_error_already_set(); - } - if (this->mArrayDims[3] != 3) { - std::ostringstream os; - os << "expected " << this->mArrayDims[0] << "x" << this->mArrayDims[1] - << "x" << this->mArrayDims[2] << "x3 array, found " << this->mArrayDims[0] - << "x" << this->mArrayDims[1] << "x" << this->mArrayDims[2] - << "x" << this->mArrayDims[3] << " array"; - PyErr_SetString(PyExc_ValueError, os.str().c_str()); - boost::python::throw_error_already_set(); - } - } - - virtual void copyFromArray() const - { - switch (this->mArrayTypeNum) { - case NPY_FLOAT: - this->template fromArray::type> >(); break; - case NPY_DOUBLE: - this->template fromArray::type> >(); break; - case NPY_BOOL: - this->template fromArray::type> >(); break; - case NPY_INT16: - this->template fromArray::type> >(); break; - case NPY_INT32: - this->template fromArray::type> >(); break; - case NPY_INT64: - this->template fromArray::type> >(); break; - case NPY_UINT32: - this->template fromArray::type> >(); break; - case NPY_UINT64: - this->template fromArray::type> >(); break; - default: throw openvdb::TypeError(); break; - } - } - - virtual void copyToArray() const - { - switch (this->mArrayTypeNum) { - case NPY_FLOAT: - this->template toArray::type> >(); break; - case NPY_DOUBLE: - this->template toArray::type> >(); break; - case NPY_BOOL: - this->template toArray::type> >(); break; - case NPY_INT16: - this->template toArray::type> >(); break; - case NPY_INT32: - this->template toArray::type> >(); break; - case NPY_INT64: - this->template toArray::type> >(); break; - case NPY_UINT32: - this->template toArray::type> >(); break; - case NPY_UINT64: - this->template toArray::type> >(); break; - default: throw openvdb::TypeError(); break; - } - } -}; // class CopyOp - - -template -inline void -copyFromArray(GridType& grid, py::object arrayObj, py::object coordObj, py::object toleranceObj) -{ - typedef typename GridType::ValueType ValueT; - CopyOp::Size> - op(/*toGrid=*/true, grid, arrayObj, coordObj, toleranceObj); - op(); -} - - -template -inline void -copyToArray(GridType& grid, py::object arrayObj, py::object coordObj) -{ - typedef typename GridType::ValueType ValueT; - CopyOp::Size> - op(/*toGrid=*/false, grid, arrayObj, coordObj); - op(); -} - -#endif // defined(PY_OPENVDB_USE_NUMPY) - - -//////////////////////////////////////// - - -#ifndef PY_OPENVDB_USE_NUMPY - -template -inline typename GridType::Ptr -meshToLevelSet(py::object, py::object, py::object, py::object, py::object) -{ - PyErr_SetString(PyExc_NotImplementedError, "this module was built without NumPy support"); - boost::python::throw_error_already_set(); -} - -template -inline py::object -volumeToQuadMesh(const GridType&, py::object) -{ - PyErr_SetString(PyExc_NotImplementedError, "this module was built without NumPy support"); - boost::python::throw_error_already_set(); -} - -template -inline py::object -volumeToMesh(const GridType&, py::object, py::object) -{ - PyErr_SetString(PyExc_NotImplementedError, "this module was built without NumPy support"); - boost::python::throw_error_already_set(); -} - -#else // if defined(PY_OPENVDB_USE_NUMPY) - -// Helper class for meshToLevelSet() -template -struct CopyVecOp { - void operator()(const void* srcPtr, DstT* dst, size_t count) { - const SrcT* src = static_cast(srcPtr); - for (size_t i = count; i > 0; --i, ++src, ++dst) { - *dst = static_cast(*src); - } - } -}; -// Partial specialization for source and destination arrays of the same type -template -struct CopyVecOp { - void operator()(const void* srcPtr, T* dst, size_t count) { - const T* src = static_cast(srcPtr); - ::memcpy(dst, src, count * sizeof(T)); - } -}; - -// Helper function for use with meshToLevelSet() to copy vectors of various types -// and sizes from NumPy arrays to STL vectors -template -inline void -copyVecArray(py::numeric::array& arrayObj, std::vector& vec) -{ - typedef typename VecT::ValueType ValueT; - - // Get the input array dimensions. - PyArrayObject* arrayObjPtr = reinterpret_cast(arrayObj.ptr()); - const PyArray_Descr* dtype = PyArray_DESCR(arrayObjPtr); - const size_t M = py::extract(arrayObj.attr("shape")[0]); - const size_t N = VecT().numElements(); - if (M == 0 || N == 0) return; - - // Preallocate the output vector. - vec.resize(M); - - // Copy values from the input array to the output vector (with type conversion, if necessary). - const void* src = PyArray_DATA(arrayObjPtr); - ValueT* dst = &vec[0][0]; - switch (dtype->type_num) { - case NPY_FLOAT: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_DOUBLE: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_INT16: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_INT32: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_INT64: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_UINT32: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - case NPY_UINT64: CopyVecOp::type, ValueT>()(src, dst, M*N); break; - default: break; - } -} - - -/// @brief Given NumPy arrays of points, triangle indices and quad indices, -/// call tools::meshToLevelSet() to generate a level set grid. -template -inline typename GridType::Ptr -meshToLevelSet(py::object pointsObj, py::object trianglesObj, py::object quadsObj, - py::object xformObj, py::object halfWidthObj) -{ - struct Local { - // Return the name of the Python grid method (for use in error messages). - static const char* methodName() { return "createLevelSetFromPolygons"; } - - // Raise a Python exception if the given NumPy array does not have dimensions M x N - // or does not have an integer or floating-point data type. - static void validate2DNumPyArray(py::numeric::array arrayObj, - const int N, const char* desiredType) - { - PyArrayObject* arrayObjPtr = reinterpret_cast(arrayObj.ptr()); - - const PyArray_Descr* dtype = PyArray_DESCR(arrayObjPtr); - const py::object shape = arrayObj.attr("shape"); - const int numDims = int(py::len(shape)); - - bool wrongArrayType = false; - // Check array dimensions. - if (numDims != 2 || py::extract(shape[1]) != N) { - wrongArrayType = true; - } else { - // Check array data type. - switch (dtype->type_num) { - case NPY_FLOAT: case NPY_DOUBLE: case NPY_INT16: //case NPY_HALF: - case NPY_INT32: case NPY_INT64: case NPY_UINT32: case NPY_UINT64: break; - default: wrongArrayType = true; break; - } - } - if (wrongArrayType) { - // Generate an error message and raise a Python TypeError. - std::string arrayTypeName; - if (PyObject_HasAttrString(arrayObj.ptr(), "dtype")) { - arrayTypeName = pyutil::str(arrayObj.attr("dtype")); - } else { - arrayTypeName = "'_'"; - arrayTypeName[1] = dtype->kind; - } - std::ostringstream os; - os << "expected N x 3 numpy.ndarray of " << desiredType << ", found "; - switch (numDims) { - case 0: os << "zero-dimensional"; break; - case 1: os << "one-dimensional"; break; - default: - os << py::extract(shape[0]); - for (int i = 1; i < numDims; ++i) { - os << " x " << py::extract(shape[i]); - } - break; - } - os << " " << arrayTypeName << " array as argument 1 to " - << pyutil::GridTraits::name() << "." << methodName() << "()"; - PyErr_SetString(PyExc_TypeError, os.str().c_str()); - py::throw_error_already_set(); - } - } - }; - - // Extract the narrow band half width from the arguments to this method. - const float halfWidth = extractValueArg( - halfWidthObj, Local::methodName(), /*argIdx=*/5, "float"); - - // Extract the transform from the arguments to this method. - math::Transform::Ptr xform = math::Transform::createLinearTransform(); - if (!xformObj.is_none()) { - xform = extractValueArg( - xformObj, Local::methodName(), /*argIdx=*/4, "Transform"); - } - - // Extract the list of mesh vertices from the arguments to this method. - std::vector points; - if (!pointsObj.is_none()) { - // Extract a reference to (not a copy of) a NumPy array argument, - // or throw an exception if the argument is not a NumPy array object. - py::numeric::array arrayObj = extractValueArg( - pointsObj, Local::methodName(), /*argIdx=*/1, "numpy.ndarray"); - - // Throw an exception if the array has the wrong type or dimensions. - Local::validate2DNumPyArray(arrayObj, /*N=*/3, /*desiredType=*/"float"); - - // Copy values from the array to the vector. - copyVecArray(arrayObj, points); - } - - // Extract the list of triangle indices from the arguments to this method. - std::vector triangles; - if (!trianglesObj.is_none()) { - py::numeric::array arrayObj = extractValueArg( - trianglesObj, Local::methodName(), /*argIdx=*/2, "numpy.ndarray"); - Local::validate2DNumPyArray(arrayObj, /*N=*/3, /*desiredType=*/"int"); - copyVecArray(arrayObj, triangles); - } - - // Extract the list of quad indices from the arguments to this method. - std::vector quads; - if (!quadsObj.is_none()) { - py::numeric::array arrayObj = extractValueArg( - quadsObj, Local::methodName(), /*argIdx=*/3, "numpy.ndarray"); - Local::validate2DNumPyArray(arrayObj, /*N=*/4, /*desiredType=*/"int"); - copyVecArray(arrayObj, quads); - } - - // Generate and return a level set grid. - return tools::meshToLevelSet(*xform, points, triangles, quads, halfWidth); -} - - -template -inline py::object -volumeToQuadMesh(const GridType& grid, py::object isovalueObj) -{ - const double isovalue = pyutil::extractArg( - isovalueObj, "convertToQuads", /*className=*/NULL, /*argIdx=*/2, "float"); - - // Mesh the input grid and populate lists of mesh vertices and face vertex indices. - std::vector points; - std::vector quads; - tools::volumeToMesh(grid, points, quads, isovalue); - - // Copy vertices into an N x 3 NumPy array. - py::object pointArrayObj = py::numeric::array(py::list(), "float32"); - if (!points.empty()) { - npy_intp dims[2] = { npy_intp(points.size()), 3 }; - // Construct a NumPy array that wraps the point vector. - if (PyArrayObject* arrayObj = reinterpret_cast( - PyArray_SimpleNewFromData(/*nd=*/2, dims, NPY_FLOAT, &points[0]))) - { - // Create a deep copy of the array (because the point vector will be - // destroyed when this function returns). - pointArrayObj = pyutil::pyBorrow(PyArray_NewCopy(arrayObj, NPY_CORDER)); - } - } - - // Copy face indices into an N x 4 NumPy array. - py::object quadArrayObj = py::numeric::array(py::list(), "uint32"); - if (!quads.empty()) { - npy_intp dims[2] = { npy_intp(quads.size()), 4 }; - if (PyArrayObject* arrayObj = reinterpret_cast( - PyArray_SimpleNewFromData(/*dims=*/2, dims, NPY_UINT32, &quads[0]))) - { - quadArrayObj = pyutil::pyBorrow(PyArray_NewCopy(arrayObj, NPY_CORDER)); - } - } - - return py::make_tuple(pointArrayObj, quadArrayObj); -} - - -template -inline py::object -volumeToMesh(const GridType& grid, py::object isovalueObj, py::object adaptivityObj) -{ - const double isovalue = pyutil::extractArg( - isovalueObj, "convertToPolygons", /*className=*/NULL, /*argIdx=*/2, "float"); - const double adaptivity = pyutil::extractArg( - adaptivityObj, "convertToPolygons", /*className=*/NULL, /*argIdx=*/3, "float"); - - // Mesh the input grid and populate lists of mesh vertices and face vertex indices. - std::vector points; - std::vector triangles; - std::vector quads; - tools::volumeToMesh(grid, points, triangles, quads, isovalue, adaptivity); - - // Copy vertices into an N x 3 NumPy array. - py::object pointArrayObj = py::numeric::array(py::list(), "float32"); - if (!points.empty()) { - npy_intp dims[2] = { npy_intp(points.size()), 3 }; - // Construct a NumPy array that wraps the point vector. - if (PyArrayObject* arrayObj = reinterpret_cast( - PyArray_SimpleNewFromData(/*dims=*/2, dims, NPY_FLOAT, &points[0]))) - { - // Create a deep copy of the array (because the point vector will be - // destroyed when this function returns). - pointArrayObj = pyutil::pyBorrow(PyArray_NewCopy(arrayObj, NPY_CORDER)); - } - } - - // Copy triangular face indices into an N x 3 NumPy array. - py::object triangleArrayObj = py::numeric::array(py::list(), "uint32"); - if (!triangles.empty()) { - npy_intp dims[2] = { npy_intp(triangles.size()), 3 }; - if (PyArrayObject* arrayObj = reinterpret_cast( - PyArray_SimpleNewFromData(/*dims=*/2, dims, NPY_UINT32, &triangles[0]))) - { - triangleArrayObj = pyutil::pyBorrow(PyArray_NewCopy(arrayObj, NPY_CORDER)); - } - } - - // Copy quadrilateral face indices into an N x 4 NumPy array. - py::object quadArrayObj = py::numeric::array(py::list(), "uint32"); - if (!quads.empty()) { - npy_intp dims[2] = { npy_intp(quads.size()), 4 }; - if (PyArrayObject* arrayObj = reinterpret_cast( - PyArray_SimpleNewFromData(/*dims=*/2, dims, NPY_UINT32, &quads[0]))) - { - quadArrayObj = pyutil::pyBorrow(PyArray_NewCopy(arrayObj, NPY_CORDER)); - } - } - - return py::make_tuple(pointArrayObj, triangleArrayObj, quadArrayObj); -} - -#endif // defined(PY_OPENVDB_USE_NUMPY) - - -//////////////////////////////////////// - - -template -inline void -applyMap(const char* methodName, GridType& grid, py::object funcObj) -{ - typedef typename GridType::ValueType ValueT; - - for (IterType it = grid.tree().template begin(); it; ++it) { - // Evaluate the functor. - py::object result = funcObj(*it); - - // Verify that the result is of type GridType::ValueType. - py::extract val(result); - if (!val.check()) { - PyErr_Format(PyExc_TypeError, - "expected callable argument to %s.%s() to return %s, found %s", - pyutil::GridTraits::name(), - methodName, - openvdb::typeNameAsString(), - pyutil::className(result).c_str()); - py::throw_error_already_set(); - } - - it.setValue(val()); - } -} - - -template -inline void -mapOn(GridType& grid, py::object funcObj) -{ - applyMap("mapOn", grid, funcObj); -} - - -template -inline void -mapOff(GridType& grid, py::object funcObj) -{ - applyMap("mapOff", grid, funcObj); -} - - -template -inline void -mapAll(GridType& grid, py::object funcObj) -{ - applyMap("mapAll", grid, funcObj); -} - - -//////////////////////////////////////// - - -template -struct TreeCombineOp -{ - typedef typename GridType::TreeType TreeT; - typedef typename GridType::ValueType ValueT; - - TreeCombineOp(py::object _op): op(_op) {} - void operator()(const ValueT& a, const ValueT& b, ValueT& result) - { - py::object resultObj = op(a, b); - - py::extract val(resultObj); - if (!val.check()) { - PyErr_Format(PyExc_TypeError, - "expected callable argument to %s.combine() to return %s, found %s", - pyutil::GridTraits::name(), - openvdb::typeNameAsString(), - pyutil::className(resultObj).c_str()); - py::throw_error_already_set(); - } - - result = val(); - } - py::object op; -}; - - -template -inline void -combine(GridType& grid, py::object otherGridObj, py::object funcObj) -{ - typedef typename GridType::Ptr GridPtr; - GridPtr otherGrid = extractValueArg(otherGridObj, - "combine", 1, pyutil::GridTraits::name()); - TreeCombineOp op(funcObj); - grid.tree().combine(otherGrid->tree(), op, /*prune=*/true); -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -createLevelSetSphere(float radius, const openvdb::Vec3f& center, float voxelSize, float halfWidth) -{ - return tools::createLevelSetSphere(radius, center, voxelSize, halfWidth); -} - - -//////////////////////////////////////// - - -template class IterWrap; // forward declaration - -// -// Type traits for various iterators -// -template struct IterTraits -{ - // IterT the type of the iterator - // name() function returning the base name of the iterator type (e.g., "ValueOffIter") - // descr() function returning a string describing the iterator - // begin() function returning a begin iterator for a given grid -}; - -template struct IterTraits -{ - typedef typename GridT::ValueOnCIter IterT; - static std::string name() { return "ValueOnCIter"; } - static std::string descr() - { - return std::string("Read-only iterator over the active values (tile and voxel)\nof a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->cbeginValueOn()); - } -}; // IterTraits - -template struct IterTraits -{ - typedef typename GridT::ValueOffCIter IterT; - static std::string name() { return "ValueOffCIter"; } - static std::string descr() - { - return std::string("Read-only iterator over the inactive values (tile and voxel)\nof a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->cbeginValueOff()); - } -}; // IterTraits - -template struct IterTraits -{ - typedef typename GridT::ValueAllCIter IterT; - static std::string name() { return "ValueAllCIter"; } - static std::string descr() - { - return std::string("Read-only iterator over all tile and voxel values of a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->cbeginValueAll()); - } -}; // IterTraits - -template struct IterTraits -{ - typedef typename GridT::ValueOnIter IterT; - static std::string name() { return "ValueOnIter"; } - static std::string descr() - { - return std::string("Read/write iterator over the active values (tile and voxel)\nof a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->beginValueOn()); - } -}; // IterTraits - -template struct IterTraits -{ - typedef typename GridT::ValueOffIter IterT; - static std::string name() { return "ValueOffIter"; } - static std::string descr() - { - return std::string("Read/write iterator over the inactive values (tile and voxel)\nof a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->beginValueOff()); - } -}; // IterTraits - -template struct IterTraits -{ - typedef typename GridT::ValueAllIter IterT; - static std::string name() { return "ValueAllIter"; } - static std::string descr() - { - return std::string("Read/write iterator over all tile and voxel values of a ") - + pyutil::GridTraits::type>::name(); - } - static IterWrap begin(typename GridT::Ptr g) - { - return IterWrap(g, g->beginValueAll()); - } -}; // IterTraits - - -//////////////////////////////////////// - - -// Helper class to modify a grid through a non-const iterator -template -struct IterItemSetter -{ - typedef typename GridT::ValueType ValueT; - static void setValue(const IterT& iter, const ValueT& val) { iter.setValue(val); } - static void setActive(const IterT& iter, bool on) { iter.setActiveState(on); } -}; - -// Partial specialization for const iterators -template -struct IterItemSetter -{ - typedef typename GridT::ValueType ValueT; - static void setValue(const IterT&, const ValueT&) - { - PyErr_SetString(PyExc_AttributeError, "can't set attribute 'value'"); - py::throw_error_already_set(); - } - static void setActive(const IterT&, bool /*on*/) - { - PyErr_SetString(PyExc_AttributeError, "can't set attribute 'active'"); - py::throw_error_already_set(); - } -}; - - -/// @brief Value returned by the next() method of a grid's value iterator -/// @details This class allows both dictionary-style (e.g., items["depth"]) and -/// attribute access (e.g., items.depth) to the items returned by an iterator. -/// @todo Create a reusable base class for "named dicts" like this? -template -class IterValueProxy -{ -public: - typedef _GridT GridT; - typedef _IterT IterT; - typedef typename GridT::ValueType ValueT; - typedef IterItemSetter SetterT; - - IterValueProxy(typename GridT::ConstPtr grid, const IterT& iter): mGrid(grid), mIter(iter) {} - - IterValueProxy copy() const { return *this; } - - typename GridT::ConstPtr parent() const { return mGrid; } - - ValueT getValue() const { return *mIter; } - bool getActive() const { return mIter.isValueOn(); } - Index getDepth() const { return mIter.getDepth(); } - Coord getBBoxMin() const { return mIter.getBoundingBox().min(); } - Coord getBBoxMax() const { return mIter.getBoundingBox().max(); } - Index64 getVoxelCount() const { return mIter.getVoxelCount(); } - - void setValue(const ValueT& val) { SetterT::setValue(mIter, val); } - void setActive(bool on) { SetterT::setActive(mIter, on); } - - /// Return this dictionary's keys as a list of C strings. - static const char* const * keys() - { - static const char* const sKeys[] = { - "value", "active", "depth", "min", "max", "count", NULL - }; - return sKeys; - } - - /// Return @c true if the given string is a valid key. - static bool hasKey(const std::string& key) - { - for (int i = 0; keys()[i] != NULL; ++i) { - if (key == keys()[i]) return true; - } - return false; - } - - /// Return this dictionary's keys as a Python list of Python strings. - static py::list getKeys() - { - py::list keyList; - for (int i = 0; keys()[i] != NULL; ++i) keyList.append(keys()[i]); - return keyList; - } - - /// @brief Return the value for the given key. - /// @throw KeyError if the key is invalid - py::object getItem(py::object keyObj) const - { - py::extract x(keyObj); - if (x.check()) { - const std::string key = x(); - if (key == "value") return py::object(this->getValue()); - else if (key == "active") return py::object(this->getActive()); - else if (key == "depth") return py::object(this->getDepth()); - else if (key == "min") return py::object(this->getBBoxMin()); - else if (key == "max") return py::object(this->getBBoxMax()); - else if (key == "count") return py::object(this->getVoxelCount()); - } - PyErr_SetObject(PyExc_KeyError, ("%s" % keyObj.attr("__repr__")()).ptr()); - py::throw_error_already_set(); - return py::object(); - } - - /// @brief Set the value for the given key. - /// @throw KeyError if the key is invalid - /// @throw AttributeError if the key refers to a read-only item - void setItem(py::object keyObj, py::object valObj) - { - py::extract x(keyObj); - if (x.check()) { - const std::string key = x(); - if (key == "value") { - this->setValue(py::extract(valObj)); return; - } else if (key == "active") { - this->setActive(py::extract(valObj)); return; - } else if (this->hasKey(key)) { - PyErr_SetObject(PyExc_AttributeError, - ("can't set attribute '%s'" % keyObj.attr("__repr__")()).ptr()); - py::throw_error_already_set(); - } - } - PyErr_SetObject(PyExc_KeyError, - ("'%s'" % keyObj.attr("__repr__")()).ptr()); - py::throw_error_already_set(); - } - - bool operator==(const IterValueProxy& other) const - { - return (other.getActive() == this->getActive() - && other.getDepth() == this->getDepth() - && math::isExactlyEqual(other.getValue(), this->getValue()) - && other.getBBoxMin() == this->getBBoxMin() - && other.getBBoxMax() == this->getBBoxMax() - && other.getVoxelCount() == this->getVoxelCount()); - } - bool operator!=(const IterValueProxy& other) const { return !(*this == other); } - - /// Print this dictionary to a stream. - std::ostream& put(std::ostream& os) const - { - // valuesAsStrings = ["%s: %s" % key, repr(this[key]) for key in this.keys()] - py::list valuesAsStrings; - for (int i = 0; this->keys()[i] != NULL; ++i) { - py::str - key(this->keys()[i]), - val(this->getItem(key).attr("__repr__")()); - valuesAsStrings.append("'%s': %s" % py::make_tuple(key, val)); - } - // print ", ".join(valuesAsStrings) - py::object joined = py::str(", ").attr("join")(valuesAsStrings); - std::string s = py::extract(joined); - os << "{" << s << "}"; - return os; - } - /// Return a string describing this dictionary. - std::string info() const { std::ostringstream os; os << *this; return os.str(); } - -private: - // To keep the iterator's grid from being deleted (leaving the iterator dangling), - // store a shared pointer to the grid. - const typename GridT::ConstPtr mGrid; - const IterT mIter; // the iterator may not be incremented -}; // class IterValueProxy - - -template -inline std::ostream& -operator<<(std::ostream& os, const IterValueProxy& iv) { return iv.put(os); } - - -//////////////////////////////////////// - - -/// Wrapper for a grid's value iterator classes -template -class IterWrap -{ -public: - typedef _GridT GridT; - typedef _IterT IterT; - typedef typename GridT::ValueType ValueT; - typedef IterValueProxy IterValueProxyT; - typedef IterTraits Traits; - - IterWrap(typename GridT::ConstPtr grid, const IterT& iter): mGrid(grid), mIter(iter) {} - - typename GridT::ConstPtr parent() const { return mGrid; } - - /// Return an IterValueProxy for the current iterator position. - IterValueProxyT next() - { - if (!mIter) { - PyErr_SetString(PyExc_StopIteration, "no more values"); - py::throw_error_already_set(); - } - IterValueProxyT result(mGrid, mIter); - ++mIter; - return result; - } - - static py::object returnSelf(const py::object& obj) { return obj; } - - /// @brief Define a Python wrapper class for this C++ class and another for - /// the IterValueProxy class returned by iterators of this type. - static void wrap() - { - const std::string - gridClassName = pyutil::GridTraits::type>::name(), - iterClassName = /*gridClassName +*/ Traits::name(), - valueClassName = /*gridClassName +*/ "Value"; - - py::class_( - iterClassName.c_str(), - /*docstring=*/Traits::descr().c_str(), - /*ctor=*/py::no_init) // can only be instantiated from C++, not from Python - - .add_property("parent", &IterWrap::parent, - ("the " + gridClassName + " over which to iterate").c_str()) - - .def("next", &IterWrap::next, ("next() -> " + valueClassName).c_str()) - .def("__iter__", &returnSelf); - - py::class_( - valueClassName.c_str(), - /*docstring=*/("Proxy for a tile or voxel value in a " + gridClassName).c_str(), - /*ctor=*/py::no_init) // can only be instantiated from C++, not from Python - - .def("copy", &IterValueProxyT::copy, - ("copy() -> " + valueClassName + "\n\n" - "Return a shallow copy of this value, i.e., one that shares\n" - "its data with the original.").c_str()) - - .add_property("parent", &IterValueProxyT::parent, - ("the " + gridClassName + " to which this value belongs").c_str()) - - .def("__str__", &IterValueProxyT::info) - .def("__repr__", &IterValueProxyT::info) - - .def("__eq__", &IterValueProxyT::operator==) - .def("__ne__", &IterValueProxyT::operator!=) - - .add_property("value", &IterValueProxyT::getValue, &IterValueProxyT::setValue, - "value of this tile or voxel") - .add_property("active", &IterValueProxyT::getActive, &IterValueProxyT::setActive, - "active state of this tile or voxel") - .add_property("depth", &IterValueProxyT::getDepth, - "tree depth at which this value is stored") - .add_property("min", &IterValueProxyT::getBBoxMin, - "lower bound of the axis-aligned bounding box of this tile or voxel") - .add_property("max", &IterValueProxyT::getBBoxMax, - "upper bound of the axis-aligned bounding box of this tile or voxel") - .add_property("count", &IterValueProxyT::getVoxelCount, - "number of voxels spanned by this value") - - .def("keys", &IterValueProxyT::getKeys, - "keys() -> list\n\n" - "Return a list of keys for this tile or voxel.") - .staticmethod("keys") - .def("__contains__", &IterValueProxyT::hasKey, - "__contains__(key) -> bool\n\n" - "Return True if the given key exists.") - .staticmethod("__contains__") - .def("__getitem__", &IterValueProxyT::getItem, - "__getitem__(key) -> value\n\n" - "Return the value of the item with the given key.") - .def("__setitem__", &IterValueProxyT::getItem, - "__setitem__(key, value)\n\n" - "Set the value of the item with the given key."); - } - -private: - // To keep this iterator's grid from being deleted, leaving the iterator dangling, - // store a shared pointer to the grid. - const typename GridT::ConstPtr mGrid; - IterT mIter; -}; // class IterWrap - - -//////////////////////////////////////// - - -template -struct PickleSuite: public py::pickle_suite -{ - typedef typename GridT::Ptr GridPtrT; - - /// Return @c true, indicating that this pickler preserves a Grid's __dict__. - static bool getstate_manages_dict() { return true; } - - /// Return a tuple representing the state of the given Grid. - static py::tuple getstate(py::object gridObj) - { - py::tuple state; - - // Extract a Grid from the Python object. - GridPtrT grid; - py::extract x(gridObj); - if (x.check()) grid = x(); - - if (grid) { - // Serialize the Grid to a string. - std::ostringstream ostr(std::ios_base::binary); - { - openvdb::io::Stream strm(ostr); - strm.setGridStatsMetadataEnabled(false); - strm.write(openvdb::GridPtrVec(1, grid)); - } - // Construct a state tuple comprising the Python object's __dict__ - // and the serialized Grid. - state = py::make_tuple(gridObj.attr("__dict__"), ostr.str()); - } - return state; - } - - /// Restore the given Grid to a saved state. - static void setstate(py::object gridObj, py::object stateObj) - { - GridPtrT grid; - { - py::extract x(gridObj); - if (x.check()) grid = x(); - } - if (!grid) return; - - py::tuple state; - { - py::extract x(stateObj); - if (x.check()) state = x(); - } - bool badState = (py::len(state) != 2); - - if (!badState) { - // Restore the object's __dict__. - py::extract x(state[0]); - if (x.check()) { - py::dict d = py::extract(gridObj.attr("__dict__"))(); - d.update(x()); - } else { - badState = true; - } - } - - std::string serialized; - if (!badState) { - // Extract the string containing the serialized Grid. - py::extract x(state[1]); - if (x.check()) serialized = x(); - else badState = true; - } - - if (badState) { - PyErr_SetObject(PyExc_ValueError, - ("expected (dict, str) tuple in call to __setstate__; found %s" - % stateObj.attr("__repr__")()).ptr()); - py::throw_error_already_set(); - } - - // Restore the internal state of the C++ object. - GridPtrVecPtr grids; - { - std::istringstream istr(serialized, std::ios_base::binary); - io::Stream strm(istr); - grids = strm.getGrids(); // (note: file-level metadata is ignored) - } - if (grids && !grids->empty()) { - if (GridPtrT savedGrid = gridPtrCast((*grids)[0])) { - grid->MetaMap::operator=(*savedGrid); ///< @todo add a Grid::setMetadata() method? - grid->setTransform(savedGrid->transformPtr()); - grid->setTree(savedGrid->treePtr()); - } - } - } -}; // struct PickleSuite - - -//////////////////////////////////////// - - -/// Create a Python wrapper for a particular template instantiation of Grid. -template -inline void -exportGrid() -{ - typedef typename GridType::ValueType ValueT; - typedef typename GridType::Ptr GridPtr; - typedef pyutil::GridTraits Traits; - - typedef typename GridType::ValueOnCIter ValueOnCIterT; - typedef typename GridType::ValueOffCIter ValueOffCIterT; - typedef typename GridType::ValueAllCIter ValueAllCIterT; - typedef typename GridType::ValueOnIter ValueOnIterT; - typedef typename GridType::ValueOffIter ValueOffIterT; - typedef typename GridType::ValueAllIter ValueAllIterT; - - math::Transform::Ptr (GridType::*getTransform)() = &GridType::transformPtr; - - const std::string pyGridTypeName = Traits::name(); - const std::string defaultCtorDescr = "Initialize with a background value of " - + pyutil::str(pyGrid::getZeroValue()) + "."; - - // Define the Grid wrapper class and make it the current scope. - { - py::class_ clss( - /*classname=*/pyGridTypeName.c_str(), - /*docstring=*/(Traits::descr()).c_str(), - /*ctor=*/py::init<>(defaultCtorDescr.c_str()) - ); - - py::scope gridClassScope = clss; - - clss.def(py::init(py::args("background"), - "Initialize with the given background value.")) - - .def("copy", &pyGrid::copyGrid, - ("copy() -> " + pyGridTypeName + "\n\n" - "Return a shallow copy of this grid, i.e., a grid\n" - "that shares its voxel data with this grid.").c_str()) - .def("deepCopy", &GridType::deepCopy, - ("deepCopy() -> " + pyGridTypeName + "\n\n" - "Return a deep copy of this grid.\n").c_str()) - - .def_pickle(pyGrid::PickleSuite()) - - .def("sharesWith", &pyGrid::sharesWith, - ("sharesWith(" + pyGridTypeName + ") -> bool\n\n" - "Return True if this grid shares its voxel data with the given grid.").c_str()) - - /// @todo Any way to set a docstring for a class property? - .add_static_property("valueTypeName", &pyGrid::getValueType) - /// @todo docstring = "name of this grid's value type" - .add_static_property("zeroValue", &pyGrid::getZeroValue) - /// @todo docstring = "zero, as expressed in this grid's value type" - .add_static_property("oneValue", &pyGrid::getOneValue) - /// @todo docstring = "one, as expressed in this grid's value type" - /// @todo Is Grid.typeName ever needed? - //.add_static_property("typeName", &GridType::gridType) - /// @todo docstring = to "name of this grid's type" - - .add_property("background", - &pyGrid::getGridBackground, &pyGrid::setGridBackground, - "value of this grid's background voxels") - .add_property("name", &GridType::getName, &pyGrid::setGridName, - "this grid's name") - .add_property("creator", &GridType::getCreator, &pyGrid::setGridCreator, - "description of this grid's creator") - - .add_property("transform", getTransform, &pyGrid::setGridTransform, - "transform associated with this grid") - - .add_property("gridClass", &pyGrid::getGridClass, &pyGrid::setGridClass, - "the class of volumetric data (level set, fog volume, etc.)\nstored in this grid") - - .add_property("vectorType", &pyGrid::getVecType, &pyGrid::setVecType, - "how transforms are applied to values stored in this grid") - - .def("getAccessor", &pyGrid::getAccessor, - ("getAccessor() -> " + pyGridTypeName + "Accessor\n\n" - "Return an accessor that provides random read and write access\n" - "to this grid's voxels.").c_str()) - .def("getConstAccessor", &pyGrid::getConstAccessor, - ("getConstAccessor() -> " + pyGridTypeName + "Accessor\n\n" - "Return an accessor that provides random read-only access\n" - "to this grid's voxels.").c_str()) - - // - // Metadata - // - .add_property("metadata", &pyGrid::getAllMetadata, &pyGrid::replaceAllMetadata, - "dict of this grid's metadata\n\n" - "Setting this attribute replaces all of this grid's metadata,\n" - "but mutating it in place has no effect on the grid, since\n" - "the value of this attribute is a only a copy of the metadata.\n" - "Use either indexing or updateMetadata() to mutate metadata in place.") - .def("updateMetadata", &pyGrid::updateMetadata, - "updateMetadata(dict)\n\n" - "Add metadata to this grid, replacing any existing items\n" - "having the same names as the new items.") - - .def("addStatsMetadata", &GridType::addStatsMetadata, - "addStatsMetadata()\n\n" - "Add metadata to this grid comprising the current values\n" - "of statistics like the active voxel count and bounding box.\n" - "(This metadata is not automatically kept up-to-date with\n" - "changes to this grid.)") - .def("getStatsMetadata", &pyGrid::getStatsMetadata, - "getStatsMetadata() -> dict\n\n" - "Return a (possibly empty) dict containing just the metadata\n" - "that was added to this grid with addStatsMetadata().") - - .def("__getitem__", &pyGrid::getMetadata, - "__getitem__(name) -> value\n\n" - "Return the metadata value associated with the given name.") - .def("__setitem__", &pyGrid::setMetadata, - "__setitem__(name, value)\n\n" - "Add metadata to this grid, replacing any existing item having\n" - "the same name as the new item.") - .def("__delitem__", &pyGrid::removeMetadata, - "__delitem__(name)\n\n" - "Remove the metadata with the given name.") - .def("__contains__", &pyGrid::hasMetadata, - "__contains__(name) -> bool\n\n" - "Return True if this grid contains metadata with the given name.") - .def("__iter__", &pyGrid::getMetadataKeys, - "__iter__() -> iterator\n\n" - "Return an iterator over this grid's metadata keys.") - .def("iterkeys", &pyGrid::getMetadataKeys, - "iterkeys() -> iterator\n\n" - "Return an iterator over this grid's metadata keys.") - - .add_property("saveFloatAsHalf", - &GridType::saveFloatAsHalf, &GridType::setSaveFloatAsHalf, - "if True, write floating-point voxel values as 16-bit half floats") - - // - // Statistics - // - .def("memUsage", &GridType::memUsage, - "memUsage() -> int\n\n" - "Return the memory usage of this grid in bytes.") - - .def("evalLeafBoundingBox", &pyGrid::evalLeafBoundingBox, - "evalLeafBoundingBox() -> xyzMin, xyzMax\n\n" - "Return the coordinates of opposite corners of the axis-aligned\n" - "bounding box of all leaf nodes.") - .def("evalLeafDim", &pyGrid::evalLeafDim, - "evalLeafDim() -> x, y, z\n\n" - "Return the dimensions of the axis-aligned bounding box\n" - "of all leaf nodes.") - - .def("evalActiveVoxelBoundingBox", &pyGrid::evalActiveVoxelBoundingBox, - "evalActiveVoxelBoundingBox() -> xyzMin, xyzMax\n\n" - "Return the coordinates of opposite corners of the axis-aligned\n" - "bounding box of all active voxels.") - .def("evalActiveVoxelDim", &GridType::evalActiveVoxelDim, - "evalActiveVoxelDim() -> x, y, z\n\n" - "Return the dimensions of the axis-aligned bounding box of all\n" - "active voxels.") - - .add_property("treeDepth", &pyGrid::treeDepth, - "depth of this grid's tree from root node to leaf node") - .def("nodeLog2Dims", &pyGrid::getNodeLog2Dims, - "list of Log2Dims of the nodes of this grid's tree\n" - "in order from root to leaf") - - .def("leafCount", &pyGrid::leafCount, - "leafCount() -> int\n\n" - "Return the number of leaf nodes in this grid's tree.") - .def("nonLeafCount", &pyGrid::nonLeafCount, - "nonLeafCount() -> int\n\n" - "Return the number of non-leaf nodes in this grid's tree.") - - .def("activeVoxelCount", &GridType::activeVoxelCount, - "activeVoxelCount() -> int\n\n" - "Return the number of active voxels in this grid.") - .def("activeLeafVoxelCount", &pyGrid::activeLeafVoxelCount, - "activeLeafVoxelCount() -> int\n\n" - "Return the number of active voxels that are stored\n" - "in the leaf nodes of this grid's tree.") - - .def("evalMinMax", &pyGrid::evalMinMax, - "evalMinMax() -> min, max\n\n" - "Return the minimum and maximum active values in this grid.") - - .def("getIndexRange", &pyGrid::getIndexRange, - "getIndexRange() -> min, max\n\n" - "Return the minimum and maximum coordinates that are represented\n" - "in this grid. These might include background voxels.") - //.def("expand", &pyGrid::expandIndexRange, - // py::arg("xyz"), - // "expand(xyz)\n\n" - // "Expand this grid's index range to include the given coordinates.") - - .def("info", &pyGrid::gridInfo, - py::arg("verbosity")=1, - "info(verbosity=1) -> str\n\n" - "Return a string containing information about this grid\n" - "with a specified level of verbosity.\n") - - // - // Tools - // - .def("fill", &pyGrid::fill, - (py::arg("min"), py::arg("max"), py::arg("value"), py::arg("active")=true), - "fill(min, max, value, active=True)\n\n" - "Set all voxels within a given axis-aligned box to\n" - "a constant value (either active or inactive).") - .def("signedFloodFill", &pyGrid::signedFloodFill, - "signedFloodFill()\n\n" - "Propagate the sign from a narrow-band level set into inactive\n" - "voxels and tiles.") - - .def("copyFromArray", &pyGrid::copyFromArray, - (py::arg("array"), py::arg("ijk")=Coord(0), - py::arg("tolerance")=pyGrid::getZeroValue()), - ("copyFromArray(array, ijk=(0, 0, 0), tolerance=0)\n\n" - "Populate this grid, starting at voxel (i, j, k), with values\nfrom a " - + std::string(openvdb::VecTraits::IsVec ? "four" : "three") - + "-dimensional array. Mark voxels as inactive\n" - "if and only if their values are equal to this grid's\n" - "background value within the given tolerance.").c_str()) - .def("copyToArray", &pyGrid::copyToArray, - (py::arg("array"), py::arg("ijk")=Coord(0)), - ("copyToArray(array, ijk=(0, 0, 0))\n\nPopulate a " - + std::string(openvdb::VecTraits::IsVec ? "four" : "three") - + "-dimensional array with values\n" - "from this grid, starting at voxel (i, j, k).").c_str()) - - .def("convertToQuads", - &pyGrid::volumeToQuadMesh, - (py::arg("isovalue")=0), - "convertToQuads(isovalue=0) -> points, quads\n\n" - "Uniformly mesh a scalar grid that has a continuous isosurface\n" - "at the given isovalue. Return a NumPy array of world-space\n" - "points and a NumPy array of 4-tuples of point indices, which\n" - "specify the vertices of the quadrilaterals that form the mesh.") - .def("convertToPolygons", - &pyGrid::volumeToMesh, - (py::arg("isovalue")=0, py::arg("adaptivity")=0), - "convertToPolygons(isovalue=0, adaptivity=0) -> points, triangles, quads\n\n" - "Adaptively mesh a scalar grid that has a continuous isosurface\n" - "at the given isovalue. Return a NumPy array of world-space\n" - "points and NumPy arrays of 3- and 4-tuples of point indices,\n" - "which specify the vertices of the triangles and quadrilaterals\n" - "that form the mesh. Adaptivity can vary from 0 to 1, where 0\n" - "produces a high-polygon-count mesh that closely approximates\n" - "the isosurface, and 1 produces a lower-polygon-count mesh\n" - "with some loss of surface detail.") - .def("createLevelSetFromPolygons", - &pyGrid::meshToLevelSet, - (py::arg("points"), - py::arg("triangles")=py::object(), - py::arg("quads")=py::object(), - py::arg("transform")=py::object(), - py::arg("halfWidth")=openvdb::LEVEL_SET_HALF_WIDTH), - ("createLevelSetFromPolygons(points, triangles=None, quads=None,\n" - " transform=None, halfWidth=" - + boost::lexical_cast(openvdb::LEVEL_SET_HALF_WIDTH) + ") -> " - + pyGridTypeName + "\n\n" - "Convert a triangle and/or quad mesh to a narrow-band level set volume.\n" - "The mesh must form a closed surface, but the surface need not be\n" - "manifold and may have self intersections and degenerate faces.\n" - "The mesh is described by a NumPy array of world-space points\n" - "and NumPy arrays of 3- and 4-tuples of point indices that specify\n" - "the vertices of the triangles and quadrilaterals that form the mesh.\n" - "Either the triangle or the quad array may be empty or None.\n" - "The resulting volume will have the given transform (or the identity\n" - "transform if no transform is given) and a narrow band width of\n" - "2 x halfWidth voxels.").c_str()) - .staticmethod("createLevelSetFromPolygons") - - .def("prune", &pyGrid::prune, - (py::arg("tolerance")=0), - "prune(tolerance=0)\n\n" - "Remove nodes whose values all have the same active state\n" - "and are equal to within a given tolerance.") - .def("pruneInactive", &pyGrid::pruneInactive, - (py::arg("value")=py::object()), - "pruneInactive(value=None)\n\n" - "Remove nodes whose values are all inactive and replace them\n" - "with either background tiles or tiles of the given value\n" - "(if the value is not None).") - - .def("empty", &GridType::empty, - "empty() -> bool\n\n" - "Return True if this grid contains only background voxels.") - .def("__nonzero__", &pyGrid::notEmpty) - - .def("clear", &GridType::clear, - "clear()\n\n" - "Remove all tiles from this grid and all nodes other than the root node.") - - .def("merge", &GridType::merge, - ("merge(" + pyGridTypeName + ")\n\n" - "Move child nodes from the other grid into this grid wherever\n" - "those nodes correspond to constant-value tiles in this grid,\n" - "and replace leaf-level inactive voxels in this grid with\n" - "corresponding voxels in the other grid that are active.\n\n" - "Note: this operation always empties the other grid.").c_str()) - - .def("mapOn", &pyGrid::mapOn, - py::arg("function"), - "mapOn(function)\n\n" - "Iterate over all the active (\"on\") values (tile and voxel)\n" - "of this grid and replace each value with function(value).\n\n" - "Example: grid.mapOn(lambda x: x * 2 if x < 0.5 else x)") - - .def("mapOff", &pyGrid::mapOff, - py::arg("function"), - "mapOff(function)\n\n" - "Iterate over all the inactive (\"off\") values (tile and voxel)\n" - "of this grid and replace each value with function(value).\n\n" - "Example: grid.mapOff(lambda x: x * 2 if x < 0.5 else x)") - - .def("mapAll", &pyGrid::mapAll, - py::arg("function"), - "mapAll(function)\n\n" - "Iterate over all values (tile and voxel) of this grid\n" - "and replace each value with function(value).\n\n" - "Example: grid.mapAll(lambda x: x * 2 if x < 0.5 else x)") - - .def("combine", &pyGrid::combine, - (py::arg("grid"), py::arg("function")), - "combine(grid, function)\n\n" - "Compute function(self, other) over all corresponding pairs\n" - "of values (tile or voxel) of this grid and the other grid\n" - "and store the result in this grid.\n\n" - "Note: this operation always empties the other grid.\n\n" - "Example: grid.combine(otherGrid, lambda a, b: min(a, b))") - - // - // Iterators - // - .def("citerOnValues", &pyGrid::IterTraits::begin, - "citerOnValues() -> iterator\n\n" - "Return a read-only iterator over this grid's active\ntile and voxel values.") - .def("citerOffValues", &pyGrid::IterTraits::begin, - "iterOffValues() -> iterator\n\n" - "Return a read-only iterator over this grid's inactive\ntile and voxel values.") - .def("citerAllValues", &pyGrid::IterTraits::begin, - "iterAllValues() -> iterator\n\n" - "Return a read-only iterator over all of this grid's\ntile and voxel values.") - - .def("iterOnValues", &pyGrid::IterTraits::begin, - "iterOnValues() -> iterator\n\n" - "Return a read/write iterator over this grid's active\ntile and voxel values.") - .def("iterOffValues", &pyGrid::IterTraits::begin, - "iterOffValues() -> iterator\n\n" - "Return a read/write iterator over this grid's inactive\ntile and voxel values.") - .def("iterAllValues", &pyGrid::IterTraits::begin, - "iterAllValues() -> iterator\n\n" - "Return a read/write iterator over all of this grid's\ntile and voxel values.") - - ; // py::class_ - - py::implicitly_convertible(); - py::implicitly_convertible(); - /// @todo Is there a way to implicitly convert GridType references to GridBase - /// references without wrapping the GridBase class? The following doesn't compile, - /// because GridBase has pure virtual functions: - /// @code - /// py::implicitly_convertible(); - /// @endcode - - // Wrap const and non-const value accessors and expose them - // as nested classes of the Grid class. - pyAccessor::AccessorWrap::wrap(); - pyAccessor::AccessorWrap::wrap(); - - // Wrap tree value iterators and expose them as nested classes of the Grid class. - IterWrap::wrap(); - IterWrap::wrap(); - IterWrap::wrap(); - IterWrap::wrap(); - IterWrap::wrap(); - IterWrap::wrap(); - - } // gridClassScope - - // Add the Python type object for this grid type to the module-level list. - py::extract(py::scope().attr("GridTypes"))().append( - py::scope().attr(pyGridTypeName.c_str())); -} - -} // namespace pyGrid - -#endif // OPENVDB_PYGRID_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyIntGrid.cc b/openvdb_3_0_0_library/python/pyIntGrid.cc deleted file mode 100755 index be875bc..0000000 --- a/openvdb_3_0_0_library/python/pyIntGrid.cc +++ /dev/null @@ -1,49 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file pyIntGrid.cc -/// @brief Boost.Python wrappers for scalar, integer-valued openvdb::Grid types - -#include "pyGrid.h" - - -void -exportIntGrid() -{ - pyGrid::exportGrid(); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES - pyGrid::exportGrid(); - pyGrid::exportGrid(); -#endif -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyMetadata.cc b/openvdb_3_0_0_library/python/pyMetadata.cc deleted file mode 100755 index 0a30257..0000000 --- a/openvdb_3_0_0_library/python/pyMetadata.cc +++ /dev/null @@ -1,92 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include "openvdb/openvdb.h" - -namespace py = boost::python; -using namespace openvdb::OPENVDB_VERSION_NAME; - -namespace { - -class MetadataWrap: public Metadata, public py::wrapper -{ -public: - Name typeName() const { return static_cast(this->get_override("typeName")()); } - Metadata::Ptr copy() const { - return static_cast(this->get_override("copy")()); - } - void copy(const Metadata& other) { this->get_override("copy")(other); } - std::string str() const {return static_cast(this->get_override("str")());} - bool asBool() const { return static_cast(this->get_override("asBool")()); } - Index32 size() const { return static_cast(this->get_override("size")()); } - -protected: - void readValue(std::istream& is, Index32 numBytes) { - this->get_override("readValue")(is, numBytes); - } - void writeValue(std::ostream& os) const { - this->get_override("writeValue")(os); - } -}; - -// aliases disambiguate the different versions of copy -Metadata::Ptr (MetadataWrap::*copy0)() const = &MetadataWrap::copy; -void (MetadataWrap::*copy1)(const Metadata&) = &MetadataWrap::copy; - -} // end anonymous namespace - - -void exportMetadata() -{ - py::class_ clss( - /*classname=*/"Metadata", - /*docstring=*/ - "Class that holds the value of a single item of metadata of a type\n" - "for which no Python equivalent exists (typically a custom type)", - /*ctor=*/py::no_init // can only be instantiated from C++, not from Python - ); - clss.def("copy", py::pure_virtual(copy0), - "copy() -> Metadata\n\nReturn a copy of this value.") - .def("copy", py::pure_virtual(copy1), - "copy() -> Metadata\n\nReturn a copy of this value.") - .def("type", py::pure_virtual(&Metadata::typeName), - "type() -> str\n\nReturn the name of this value's type.") - .def("size", py::pure_virtual(&Metadata::size), - "size() -> int\n\nReturn the size of this value in bytes.") - .def("__nonzero__", py::pure_virtual(&Metadata::asBool)) - .def("__str__", py::pure_virtual(&Metadata::str)) - ; - py::register_ptr_to_python(); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyOpenVDBModule.cc b/openvdb_3_0_0_library/python/pyOpenVDBModule.cc deleted file mode 100755 index b0926ee..0000000 --- a/openvdb_3_0_0_library/python/pyOpenVDBModule.cc +++ /dev/null @@ -1,702 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include // for strncmp(), strrchr(), etc. -#include -#include -#include -#include -#ifdef PY_OPENVDB_USE_NUMPY -#define PY_ARRAY_UNIQUE_SYMBOL PY_OPENVDB_ARRAY_API -#include // for import_array() -#endif -#include "openvdb/openvdb.h" -#include "pyopenvdb.h" -#include "pyGrid.h" -#include "pyutil.h" - -namespace py = boost::python; - - -// Forward declarations -void exportTransform(); -void exportMetadata(); -void exportFloatGrid(); -void exportIntGrid(); -void exportVec3Grid(); - - -namespace _openvdbmodule { - -using namespace openvdb; - - -/// Helper class to convert between a Python numeric sequence -/// (tuple, list, etc.) and an openvdb::Coord -struct CoordConverter -{ - /// @return a Python tuple object equivalent to the given Coord. - static PyObject* convert(const openvdb::Coord& xyz) - { - py::object obj = py::make_tuple(xyz[0], xyz[1], xyz[2]); - Py_INCREF(obj.ptr()); - ///< @todo is this the right way to ensure that the object - ///< doesn't get freed on exit? - return obj.ptr(); - } - - /// @return NULL if the given Python object is not convertible to a Coord. - static void* convertible(PyObject* obj) - { - if (!PySequence_Check(obj)) return NULL; // not a Python sequence - - Py_ssize_t len = PySequence_Length(obj); - if (len != 3 && len != 1) return NULL; // not the right length - - return obj; - } - - /// Convert from a Python object to a Coord. - static void construct(PyObject* obj, - py::converter::rvalue_from_python_stage1_data* data) - { - // Construct a Coord in the provided memory location. - typedef py::converter::rvalue_from_python_storage - StorageT; - void* storage = reinterpret_cast(data)->storage.bytes; - new (storage) openvdb::Coord; // placement new - data->convertible = storage; - - openvdb::Coord* xyz = static_cast(storage); - - // Populate the Coord. - switch (PySequence_Length(obj)) { - case 1: - xyz->reset(pyutil::getSequenceItem(obj, 0)); - break; - case 3: - xyz->reset( - pyutil::getSequenceItem(obj, 0), - pyutil::getSequenceItem(obj, 1), - pyutil::getSequenceItem(obj, 2)); - break; - default: - PyErr_Format(PyExc_ValueError, - "expected a sequence of three integers"); - py::throw_error_already_set(); - break; - } - } - - /// Register both the Coord-to-tuple and the sequence-to-Coord converters. - static void registerConverter() - { - py::to_python_converter(); - py::converter::registry::push_back( - &CoordConverter::convertible, - &CoordConverter::construct, - py::type_id()); - } -}; // struct CoordConverter - -/// @todo CoordBBoxConverter? - - -//////////////////////////////////////// - - -/// Helper class to convert between a Python numeric sequence -/// (tuple, list, etc.) and an openvdb::Vec -template -struct VecConverter -{ - static PyObject* convert(const VecT& v) - { - py::object obj; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - switch (VecT::size) { // compile-time constant - case 2: obj = py::make_tuple(v[0], v[1]); break; - case 3: obj = py::make_tuple(v[0], v[1], v[2]); break; - case 4: obj = py::make_tuple(v[0], v[1], v[2], v[3]); break; - default: - { - py::list lst; - for (int n = 0; n < VecT::size; ++n) lst.append(v[n]); - obj = lst; - } - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - Py_INCREF(obj.ptr()); - return obj.ptr(); - } - - static void* convertible(PyObject* obj) - { - if (!PySequence_Check(obj)) return NULL; // not a Python sequence - - Py_ssize_t len = PySequence_Length(obj); - if (len != VecT::size) return NULL; - - // Check that all elements of the Python sequence are convertible - // to the Vec's value type. - py::object seq = pyutil::pyBorrow(obj); - for (int i = 0; i < VecT::size; ++i) { - if (!py::extract(seq[i]).check()) { - return NULL; - } - } - return obj; - } - - static void construct(PyObject* obj, - py::converter::rvalue_from_python_stage1_data* data) - { - // Construct a Vec in the provided memory location. - typedef py::converter::rvalue_from_python_storage StorageT; - void* storage = reinterpret_cast(data)->storage.bytes; - new (storage) VecT; // placement new - data->convertible = storage; - VecT* v = static_cast(storage); - - // Populate the vector. - for (int n = 0; n < VecT::size; ++n) { - (*v)[n] = pyutil::getSequenceItem(obj, n); - } - } - - static void registerConverter() - { - py::to_python_converter >(); - py::converter::registry::push_back( - &VecConverter::convertible, - &VecConverter::construct, - py::type_id()); - } -}; // struct VecConverter - - -//////////////////////////////////////// - - -/// Helper class to convert between a Python dict and an openvdb::MetaMap -/// @todo Consider implementing a separate, templated converter for -/// the various Metadata types. -struct MetaMapConverter -{ - static PyObject* convert(const MetaMap& metaMap) - { - py::dict ret; - for (MetaMap::ConstMetaIterator it = metaMap.beginMeta(); - it != metaMap.endMeta(); ++it) - { - if (Metadata::Ptr meta = it->second) { - py::object obj(meta); - const std::string typeName = meta->typeName(); - if (typeName == StringMetadata::staticTypeName()) { - obj = py::str(static_cast(*meta).value()); - } else if (typeName == DoubleMetadata::staticTypeName()) { - obj = py::object(static_cast(*meta).value()); - } else if (typeName == FloatMetadata::staticTypeName()) { - obj = py::object(static_cast(*meta).value()); - } else if (typeName == Int32Metadata::staticTypeName()) { - obj = py::object(static_cast(*meta).value()); - } else if (typeName == Int64Metadata::staticTypeName()) { - obj = py::object(static_cast(*meta).value()); - } else if (typeName == BoolMetadata::staticTypeName()) { - obj = py::object(static_cast(*meta).value()); - } else if (typeName == Vec2DMetadata::staticTypeName()) { - const Vec2d v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1]); - } else if (typeName == Vec2IMetadata::staticTypeName()) { - const Vec2i v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1]); - } else if (typeName == Vec2SMetadata::staticTypeName()) { - const Vec2s v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1]); - } else if (typeName == Vec3DMetadata::staticTypeName()) { - const Vec3d v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1], v[2]); - } else if (typeName == Vec3IMetadata::staticTypeName()) { - const Vec3i v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1], v[2]); - } else if (typeName == Vec3SMetadata::staticTypeName()) { - const Vec3s v = static_cast(*meta).value(); - obj = py::make_tuple(v[0], v[1], v[2]); - } - ret[it->first] = obj; - } - } - Py_INCREF(ret.ptr()); - return ret.ptr(); - } - - static void* convertible(PyObject* obj) - { - return (PyMapping_Check(obj) ? obj : NULL); - } - - static void construct(PyObject* obj, - py::converter::rvalue_from_python_stage1_data* data) - { - // Construct a MetaMap in the provided memory location. - typedef py::converter::rvalue_from_python_storage StorageT; - void* storage = reinterpret_cast(data)->storage.bytes; - new (storage) MetaMap; // placement new - data->convertible = storage; - MetaMap* metaMap = static_cast(storage); - - // Populate the map. - py::dict pyDict(pyutil::pyBorrow(obj)); - py::list keys = pyDict.keys(); - for (size_t i = 0, N = py::len(keys); i < N; ++i) { - std::string name; - py::object key = keys[i]; - if (py::extract(key).check()) { - name = py::extract(key); - } else { - const std::string - keyAsStr = py::extract(key.attr("__str__")()), - keyType = pyutil::className(key); - PyErr_Format(PyExc_TypeError, - "expected string as metadata name, found object" - " \"%s\" of type %s", keyAsStr.c_str(), keyType.c_str()); - py::throw_error_already_set(); - } - - // Note: the order of the following tests is significant, as it - // avoids unnecessary type promotion (e.g., of ints to floats). - py::object val = pyDict[keys[i]]; - Metadata::Ptr value; - if (py::extract(val).check()) { - value.reset( - new StringMetadata(py::extract(val))); - } else if (PyInt_Check(val.ptr()) - && PyInt_AsLong(val.ptr()) <= std::numeric_limits::max() - && PyInt_AsLong(val.ptr()) >= std::numeric_limits::min()) - { - value.reset(new Int32Metadata(py::extract(val))); - } else if (PyInt_Check(val.ptr()) || PyLong_Check(val.ptr())) { - value.reset(new Int64Metadata(py::extract(val))); - //} else if (py::extract(val).check()) { - // value.reset(new FloatMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new DoubleMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec2IMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec2DMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec2SMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec3IMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec3DMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value.reset(new Vec3SMetadata(py::extract(val))); - } else if (py::extract(val).check()) { - value = py::extract(val); - } else { - const std::string - valAsStr = py::extract(val.attr("__str__")()), - valType = pyutil::className(val); - PyErr_Format(PyExc_TypeError, - "metadata value \"%s\" of type %s is not allowed", - valAsStr.c_str(), valType.c_str()); - py::throw_error_already_set(); - } - if (value) metaMap->insertMeta(name, *value); - } - } - - static void registerConverter() - { - py::to_python_converter(); - py::converter::registry::push_back( - &MetaMapConverter::convertible, - &MetaMapConverter::construct, - py::type_id()); - } -}; // struct MetaMapConverter - - -//////////////////////////////////////// - - -template void translateException(const T&) {} - -/// @brief Define a function that translates an OpenVDB exception into -/// the equivalent Python exception. -/// @details openvdb::Exception::what() typically returns a string of the form -/// ": ". To avoid duplication of the exception name in Python -/// stack traces, the function strips off the ": " prefix. To do that, -/// it needs the class name in the form of a string, hence the preprocessor macro. -#define PYOPENVDB_CATCH(_openvdbname, _pyname) \ - template<> \ - void translateException<_openvdbname>(const _openvdbname& e) \ - { \ - const char* name = #_openvdbname; \ - if (const char* c = std::strrchr(name, ':')) name = c + 1; \ - const int namelen = int(std::strlen(name)); \ - const char* msg = e.what(); \ - if (0 == std::strncmp(msg, name, namelen)) msg += namelen; \ - if (0 == std::strncmp(msg, ": ", 2)) msg += 2; \ - PyErr_SetString(_pyname, msg); \ - } - - -/// Define an overloaded function that translate all OpenVDB exceptions into -/// their Python equivalents. -/// @todo IllegalValueException and LookupError are redundant and should someday be removed. -PYOPENVDB_CATCH(openvdb::ArithmeticError, PyExc_ArithmeticError) -PYOPENVDB_CATCH(openvdb::IllegalValueException, PyExc_ValueError) -PYOPENVDB_CATCH(openvdb::IndexError, PyExc_IndexError) -PYOPENVDB_CATCH(openvdb::IoError, PyExc_IOError) -PYOPENVDB_CATCH(openvdb::KeyError, PyExc_KeyError) -PYOPENVDB_CATCH(openvdb::LookupError, PyExc_LookupError) -PYOPENVDB_CATCH(openvdb::NotImplementedError, PyExc_NotImplementedError) -PYOPENVDB_CATCH(openvdb::ReferenceError, PyExc_ReferenceError) -PYOPENVDB_CATCH(openvdb::RuntimeError, PyExc_RuntimeError) -PYOPENVDB_CATCH(openvdb::TypeError, PyExc_TypeError) -PYOPENVDB_CATCH(openvdb::ValueError, PyExc_ValueError) - -#undef PYOPENVDB_CATCH - - -//////////////////////////////////////// - - -py::object -readFromFile(const std::string& filename, const std::string& gridName) -{ - io::File vdbFile(filename); - vdbFile.open(); - - if (!vdbFile.hasGrid(gridName)) { - PyErr_Format(PyExc_KeyError, - "file %s has no grid named \"%s\"", - filename.c_str(), gridName.c_str()); - py::throw_error_already_set(); - } - - return pyGrid::getGridFromGridBase(vdbFile.readGrid(gridName)); -} - - -py::tuple -readAllFromFile(const std::string& filename) -{ - io::File vdbFile(filename); - vdbFile.open(); - - GridPtrVecPtr grids = vdbFile.getGrids(); - MetaMap::Ptr metadata = vdbFile.getMetadata(); - vdbFile.close(); - - py::list gridList; - for (GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { - gridList.append(pyGrid::getGridFromGridBase(*it)); - } - - return py::make_tuple(gridList, py::dict(*metadata)); -} - - -py::dict -readFileMetadata(const std::string& filename) -{ - io::File vdbFile(filename); - vdbFile.open(); - - MetaMap::Ptr metadata = vdbFile.getMetadata(); - vdbFile.close(); - - return py::dict(*metadata); -} - - -py::object -readGridMetadataFromFile(const std::string& filename, const std::string& gridName) -{ - io::File vdbFile(filename); - vdbFile.open(); - - if (!vdbFile.hasGrid(gridName)) { - PyErr_Format(PyExc_KeyError, - "file %s has no grid named \"%s\"", - filename.c_str(), gridName.c_str()); - py::throw_error_already_set(); - } - - return pyGrid::getGridFromGridBase(vdbFile.readGridMetadata(gridName)); -} - - -py::list -readAllGridMetadataFromFile(const std::string& filename) -{ - io::File vdbFile(filename); - vdbFile.open(); - GridPtrVecPtr grids = vdbFile.readAllGridMetadata(); - vdbFile.close(); - - py::list gridList; - for (GridPtrVec::const_iterator it = grids->begin(); it != grids->end(); ++it) { - gridList.append(pyGrid::getGridFromGridBase(*it)); - } - return gridList; -} - - -void -writeToFile(const std::string& filename, py::object gridOrSeqObj, py::object dictObj) -{ - GridPtrVec gridVec; - try { - GridBase::Ptr base = pyopenvdb::getGridFromPyObject(gridOrSeqObj); - gridVec.push_back(base); - } catch (openvdb::TypeError&) { - for (py::stl_input_iterator it(gridOrSeqObj), end; it != end; ++it) { - if (GridBase::Ptr base = pyGrid::getGridBaseFromGrid(*it)) { - gridVec.push_back(base); - } - } - } - - io::File vdbFile(filename); - if (dictObj.is_none()) { - vdbFile.write(gridVec); - } else { - MetaMap metadata = py::extract(dictObj); - vdbFile.write(gridVec, metadata); - } - vdbFile.close(); -} - - -//////////////////////////////////////// - - -// Descriptor for the openvdb::GridClass enum (for use with pyutil::StringEnum) -struct GridClassDescr -{ - static const char* name() { return "GridClass"; } - static const char* doc() - { - return "Classes of volumetric data (level set, fog volume, etc.)"; - } - static pyutil::CStringPair item(int i) - { - static const int sCount = 4; - static const char* const sStrings[sCount][2] = { - { "UNKNOWN", strdup(GridBase::gridClassToString(GRID_UNKNOWN).c_str()) }, - { "LEVEL_SET", strdup(GridBase::gridClassToString(GRID_LEVEL_SET).c_str()) }, - { "FOG_VOLUME", strdup(GridBase::gridClassToString(GRID_FOG_VOLUME).c_str()) }, - { "STAGGERED", strdup(GridBase::gridClassToString(GRID_STAGGERED).c_str()) } - }; - if (i >= 0 && i < sCount) return pyutil::CStringPair(&sStrings[i][0], &sStrings[i][1]); - return pyutil::CStringPair(static_cast(NULL), static_cast(NULL)); - } -}; - - -// Descriptor for the openvdb::VecType enum (for use with pyutil::StringEnum) -struct VecTypeDescr -{ - static const char* name() { return "VectorType"; } - static const char* doc() - { - return - "The type of a vector determines how transforms are applied to it.\n" - "- INVARIANT:\n" - " does not transform (e.g., tuple, uvw, color)\n" - "- COVARIANT:\n" - " apply inverse-transpose transformation with w = 0\n" - " and ignore translation (e.g., gradient/normal)\n" - "- COVARIANT_NORMALIZE:\n" - " apply inverse-transpose transformation with w = 0\n" - " and ignore translation, vectors are renormalized\n" - " (e.g., unit normal)\n" - "- CONTRAVARIANT_RELATIVE:\n" - " apply \"regular\" transformation with w = 0 and ignore\n" - " translation (e.g., displacement, velocity, acceleration)\n" - "- CONTRAVARIANT_ABSOLUTE:\n" - " apply \"regular\" transformation with w = 1 so that\n" - " vector translates (e.g., position)"; - } - static pyutil::CStringPair item(int i) - { - static const int sCount = 5; - static const char* const sStrings[sCount][2] = { - { "INVARIANT", strdup(GridBase::vecTypeToString(openvdb::VEC_INVARIANT).c_str()) }, - { "COVARIANT", strdup(GridBase::vecTypeToString(openvdb::VEC_COVARIANT).c_str()) }, - { "COVARIANT_NORMALIZE", - strdup(GridBase::vecTypeToString(openvdb::VEC_COVARIANT_NORMALIZE).c_str()) }, - { "CONTRAVARIANT_RELATIVE", - strdup(GridBase::vecTypeToString(openvdb::VEC_CONTRAVARIANT_RELATIVE).c_str()) }, - { "CONTRAVARIANT_ABSOLUTE", - strdup(GridBase::vecTypeToString(openvdb::VEC_CONTRAVARIANT_ABSOLUTE).c_str()) } - }; - if (i >= 0 && i < sCount) return std::make_pair(&sStrings[i][0], &sStrings[i][1]); - return pyutil::CStringPair(static_cast(NULL), static_cast(NULL)); - } -}; - -} // namespace _openvdbmodule - - -//////////////////////////////////////// - - -#ifdef DWA_OPENVDB -#define PY_OPENVDB_MODULE_NAME _openvdb -#else -#define PY_OPENVDB_MODULE_NAME pyopenvdb -#endif - -BOOST_PYTHON_MODULE(PY_OPENVDB_MODULE_NAME) -{ - // Don't auto-generate ugly, C++-style function signatures. - py::docstring_options docOptions; - docOptions.disable_signatures(); - docOptions.enable_user_defined(); - -#ifdef PY_OPENVDB_USE_NUMPY - // Initialize NumPy. - import_array(); -#endif - - using namespace openvdb::OPENVDB_VERSION_NAME; - - // Initialize OpenVDB. - initialize(); - - _openvdbmodule::CoordConverter::registerConverter(); - - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - _openvdbmodule::VecConverter::registerConverter(); - - _openvdbmodule::MetaMapConverter::registerConverter(); - -#define PYOPENVDB_TRANSLATE_EXCEPTION(_classname) \ - py::register_exception_translator<_classname>(&_openvdbmodule::translateException<_classname>) - - PYOPENVDB_TRANSLATE_EXCEPTION(ArithmeticError); - PYOPENVDB_TRANSLATE_EXCEPTION(IllegalValueException); - PYOPENVDB_TRANSLATE_EXCEPTION(IndexError); - PYOPENVDB_TRANSLATE_EXCEPTION(IoError); - PYOPENVDB_TRANSLATE_EXCEPTION(KeyError); - PYOPENVDB_TRANSLATE_EXCEPTION(LookupError); - PYOPENVDB_TRANSLATE_EXCEPTION(NotImplementedError); - PYOPENVDB_TRANSLATE_EXCEPTION(ReferenceError); - PYOPENVDB_TRANSLATE_EXCEPTION(RuntimeError); - PYOPENVDB_TRANSLATE_EXCEPTION(TypeError); - PYOPENVDB_TRANSLATE_EXCEPTION(ValueError); - -#undef PYOPENVDB_TRANSLATE_EXCEPTION - - - // Export the python bindings. - exportTransform(); - exportMetadata(); - exportFloatGrid(); - exportIntGrid(); - exportVec3Grid(); - - - py::def("read", - &_openvdbmodule::readFromFile, - (py::arg("filename"), py::arg("gridname")), - "read(filename, gridname) -> Grid\n\n" - "Read a single grid from a .vdb file."); - - py::def("readAll", - &_openvdbmodule::readAllFromFile, - py::arg("filename"), - "readAll(filename) -> list, dict\n\n" - "Read a .vdb file and return a list of grids and\n" - "a dict of file-level metadata."); - - py::def("readMetadata", - &_openvdbmodule::readFileMetadata, - py::arg("filename"), - "readMetadata(filename) -> dict\n\n" - "Read file-level metadata from a .vdb file."); - - py::def("readGridMetadata", - &_openvdbmodule::readGridMetadataFromFile, - (py::arg("filename"), py::arg("gridname")), - "readGridMetadata(filename, gridname) -> Grid\n\n" - "Read a single grid's metadata and transform (but not its tree)\n" - "from a .vdb file."); - - py::def("readAllGridMetadata", - &_openvdbmodule::readAllGridMetadataFromFile, - py::arg("filename"), - "readAllGridMetadata(filename) -> list\n\n" - "Read a .vdb file and return a list of grids populated with\n" - "their metadata and transforms, but not their trees."); - - py::def("write", - &_openvdbmodule::writeToFile, - (py::arg("filename"), py::arg("grids"), py::arg("metadata") = py::object()), - "write(filename, grids, metadata=None)\n\n" - "Write a grid or a sequence of grids and, optionally, a dict\n" - "of (name, value) metadata pairs to a .vdb file."); - - // Add some useful module-level constants. - py::scope().attr("LIBRARY_VERSION") = py::make_tuple( - openvdb::OPENVDB_LIBRARY_MAJOR_VERSION, - openvdb::OPENVDB_LIBRARY_MINOR_VERSION, - openvdb::OPENVDB_LIBRARY_PATCH_VERSION); - py::scope().attr("FILE_FORMAT_VERSION") = openvdb::OPENVDB_FILE_VERSION; - py::scope().attr("COORD_MIN") = openvdb::Coord::min(); - py::scope().attr("COORD_MAX") = openvdb::Coord::max(); - py::scope().attr("LEVEL_SET_HALF_WIDTH") = openvdb::LEVEL_SET_HALF_WIDTH; - - pyutil::StringEnum<_openvdbmodule::GridClassDescr>::wrap(); - pyutil::StringEnum<_openvdbmodule::VecTypeDescr>::wrap(); - -} // BOOST_PYTHON_MODULE - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyTransform.cc b/openvdb_3_0_0_library/python/pyTransform.cc deleted file mode 100755 index 31b4be9..0000000 --- a/openvdb_3_0_0_library/python/pyTransform.cc +++ /dev/null @@ -1,328 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include "openvdb/openvdb.h" -#include "pyutil.h" - -namespace py = boost::python; -using namespace openvdb::OPENVDB_VERSION_NAME; - -namespace pyTransform { - -inline void scale1(math::Transform& t, double s) { t.preScale(s); } -inline void scale3(math::Transform& t, const Vec3d& xyz) { t.preScale(xyz); } - -inline Vec3d voxelDim0(math::Transform& t) { return t.voxelSize(); } -inline Vec3d voxelDim1(math::Transform& t, const Vec3d& p) { return t.voxelSize(p); } - -inline double voxelVolume0(math::Transform& t) { return t.voxelVolume(); } -inline double voxelVolume1(math::Transform& t, const Vec3d& p) { return t.voxelVolume(p); } - -inline Vec3d indexToWorld(math::Transform& t, const Vec3d& p) { return t.indexToWorld(p); } -inline Vec3d worldToIndex(math::Transform& t, const Vec3d& p) { return t.worldToIndex(p); } - -inline Coord worldToIndexCellCentered(math::Transform& t, const Vec3d& p) { - return t.worldToIndexCellCentered(p); -} -inline Coord worldToIndexNodeCentered(math::Transform& t, const Vec3d& p) { - return t.worldToIndexNodeCentered(p); -} - - -inline std::string -info(math::Transform& t) -{ - std::ostringstream ostr; - t.print(ostr); - return ostr.str(); -} - - -inline math::Transform::Ptr -createLinearFromDim(double dim) -{ - return math::Transform::createLinearTransform(dim); -} - - -inline math::Transform::Ptr -createLinearFromMat(py::object obj) -{ - Mat4R m; - - // Verify that obj is a four-element sequence. - bool is4x4Seq = (PySequence_Check(obj.ptr()) && PySequence_Length(obj.ptr()) == 4); - if (is4x4Seq) { - for (int row = 0; is4x4Seq && row < 4; ++row) { - // Verify that each element of obj is itself a four-element sequence. - py::object rowObj = obj[row]; - if (PySequence_Check(rowObj.ptr()) && PySequence_Length(rowObj.ptr()) == 4) { - // Extract four numeric values from this row of the sequence. - for (int col = 0; is4x4Seq && col < 4; ++col) { - if (py::extract(rowObj[col]).check()) { - m[row][col] = py::extract(rowObj[col]); - } else { - is4x4Seq = false; - } - } - } else { - is4x4Seq = false; - } - } - } - if (!is4x4Seq) { - PyErr_Format(PyExc_ValueError, "expected a 4 x 4 sequence of numeric values"); - py::throw_error_already_set(); - } - - return math::Transform::createLinearTransform(m); -} - - -inline math::Transform::Ptr -createFrustum(const Coord& xyzMin, const Coord& xyzMax, - double taper, double depth, double voxelDim = 1.0) -{ - return math::Transform::createFrustumTransform( - BBoxd(xyzMin.asVec3d(), xyzMax.asVec3d()), taper, depth, voxelDim); -} - - -//////////////////////////////////////// - - -struct PickleSuite: public py::pickle_suite -{ - enum { STATE_DICT = 0, STATE_MAJOR, STATE_MINOR, STATE_FORMAT, STATE_XFORM }; - - /// Return @c true, indicating that this pickler preserves a Transform's __dict__. - static bool getstate_manages_dict() { return true; } - - /// Return a tuple representing the state of the given Transform. - static py::tuple getstate(py::object xformObj) - { - py::tuple state; - py::extract x(xformObj); - if (x.check()) { - // Extract a Transform from the Python object. - math::Transform xform = x(); - std::ostringstream ostr(std::ios_base::binary); - // Serialize the Transform to a string. - xform.write(ostr); - - // Construct a state tuple comprising the Python object's __dict__, - // the version numbers of the serialization format, - // and the serialized Transform. - state = py::make_tuple( - xformObj.attr("__dict__"), - uint32_t(OPENVDB_LIBRARY_MAJOR_VERSION), - uint32_t(OPENVDB_LIBRARY_MINOR_VERSION), - uint32_t(OPENVDB_FILE_VERSION), - ostr.str()); - } - return state; - } - - /// Restore the given Transform to a saved state. - static void setstate(py::object xformObj, py::object stateObj) - { - math::Transform::Ptr xform; - { - py::extract x(xformObj); - if (x.check()) xform = x(); - else return; - } - - py::tuple state; - { - py::extract x(stateObj); - if (x.check()) state = x(); - } - bool badState = (py::len(state) != 5); - - if (!badState) { - // Restore the object's __dict__. - py::extract x(state[int(STATE_DICT)]); - if (x.check()) { - py::dict d = py::extract(xformObj.attr("__dict__"))(); - d.update(x()); - } else { - badState = true; - } - } - - openvdb::VersionId libVersion; - uint32_t formatVersion = 0; - if (!badState) { - // Extract the serialization format version numbers. - const int idx[3] = { STATE_MAJOR, STATE_MINOR, STATE_FORMAT }; - uint32_t version[3] = { 0, 0, 0 }; - for (int i = 0; i < 3 && !badState; ++i) { - py::extract x(state[idx[i]]); - if (x.check()) version[i] = x(); - else badState = true; - } - libVersion.first = version[0]; - libVersion.second = version[1]; - formatVersion = version[2]; - } - - std::string serialized; - if (!badState) { - // Extract the string containing the serialized Transform. - py::extract x(state[int(STATE_XFORM)]); - if (x.check()) serialized = x(); - else badState = true; - } - - if (badState) { - PyErr_SetObject(PyExc_ValueError, - ("expected (dict, int, int, int, str) tuple in call to __setstate__; found %s" - % stateObj.attr("__repr__")()).ptr()); - py::throw_error_already_set(); - } - - // Restore the internal state of the C++ object. - std::istringstream istr(serialized, std::ios_base::binary); - io::setVersion(istr, libVersion, formatVersion); - xform->read(istr); - } -}; // struct PickleSuite - -} // namespace pyTransform - - -void -exportTransform() -{ - py::enum_("Axis") - .value("X", math::X_AXIS) - .value("Y", math::Y_AXIS) - .value("Z", math::Z_AXIS); - - py::class_("Transform", py::init<>()) - - .def("deepCopy", &math::Transform::copy, - "deepCopy() -> Transform\n\n" - "Return a copy of this transform.") - - /// @todo Should this also be __str__()? - .def("info", &pyTransform::info, - "info() -> str\n\n" - "Return a string containing a description of this transform.\n") - - .def_pickle(pyTransform::PickleSuite()) - - .add_property("typeName", &math::Transform::mapType, - "name of this transform's type") - .add_property("isLinear", &math::Transform::isLinear, - "True if this transform is linear") - - .def("rotate", &math::Transform::preRotate, - (py::arg("radians"), py::arg("axis") = math::X_AXIS), - "rotate(radians, axis)\n\n" - "Accumulate a rotation about either Axis.X, Axis.Y or Axis.Z.") - .def("translate", &math::Transform::postTranslate, py::arg("xyz"), - "translate((x, y, z))\n\n" - "Accumulate a translation.") - .def("scale", &pyTransform::scale1, py::arg("s"), - "scale(s)\n\n" - "Accumulate a uniform scale.") - .def("scale", &pyTransform::scale3, py::arg("sxyz"), - "scale((sx, sy, sz))\n\n" - "Accumulate a nonuniform scale.") - .def("shear", &math::Transform::preShear, - (py::arg("s"), py::arg("axis0"), py::arg("axis1")), - "shear(s, axis0, axis1)\n\n" - "Accumulate a shear (axis0 and axis1 are either\n" - "Axis.X, Axis.Y or Axis.Z).") - - .def("voxelSize", &pyTransform::voxelDim0, - "voxelSize() -> (dx, dy, dz)\n\n" - "Return the size of voxels of the linear component of this transform.") - .def("voxelSize", &pyTransform::voxelDim1, py::arg("xyz"), - "voxelSize((x, y, z)) -> (dx, dy, dz)\n\n" - "Return the size of the voxel at position (x, y, z).") - - .def("voxelVolume", &pyTransform::voxelVolume0, - "voxelVolume() -> float\n\n" - "Return the voxel volume of the linear component of this transform.") - .def("voxelVolume", &pyTransform::voxelVolume1, py::arg("xyz"), - "voxelVolume((x, y, z)) -> float\n\n" - "Return the voxel volume at position (x, y, z).") - - .def("indexToWorld", &pyTransform::indexToWorld, py::arg("xyz"), - "indexToWorld((x, y, z)) -> (x', y', z')\n\n" - "Apply this transformation to the given coordinates.") - .def("worldToIndex", &pyTransform::worldToIndex, py::arg("xyz"), - "worldToIndex((x, y, z)) -> (x', y', z')\n\n" - "Apply the inverse of this transformation to the given coordinates.") - .def("worldToIndexCellCentered", &pyTransform::worldToIndexCellCentered, - py::arg("xyz"), - "worldToIndexCellCentered((x, y, z)) -> (i, j, k)\n\n" - "Apply the inverse of this transformation to the given coordinates\n" - "and round the result to the nearest integer coordinates.") - .def("worldToIndexNodeCentered", &pyTransform::worldToIndexNodeCentered, - py::arg("xyz"), - "worldToIndexNodeCentered((x, y, z)) -> (i, j, k)\n\n" - "Apply the inverse of this transformation to the given coordinates\n" - "and round the result down to the nearest integer coordinates.") - - // Allow Transforms to be compared for equality and inequality. - .def(py::self == py::other()) - .def(py::self != py::other()) - ; - - py::def("createLinearTransform", &pyTransform::createLinearFromMat, py::arg("matrix"), - "createLinearTransform(matrix) -> Transform\n\n" - "Create a new linear transform from a 4 x 4 matrix given as a sequence\n" - "of the form [[a, b, c, d], [e, f, g, h], [i, j, k, l], [m, n, o, p]],\n" - "where [m, n, o, p] is the translation component."); - - py::def("createLinearTransform", &pyTransform::createLinearFromDim, - (py::arg("voxelSize") = 1.0), - "createLinearTransform(voxelSize) -> Transform\n\n" - "Create a new linear transform with the given uniform voxel size."); - - py::def("createFrustumTransform", &pyTransform::createFrustum, - (py::arg("xyzMin"), py::arg("xyzMax"), - py::arg("taper"), py::arg("depth"), py::arg("voxelSize") = 1.0), - "createFrustumTransform(xyzMin, xyzMax, taper, depth, voxelSize) -> Transform\n\n" - "Create a new frustum transform with unit bounding box (xyzMin, xyzMax)\n" - "and the given taper, depth and uniform voxel size."); - - // allows Transform::Ptr Grid::getTransform() to work - py::register_ptr_to_python(); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyVec3Grid.cc b/openvdb_3_0_0_library/python/pyVec3Grid.cc deleted file mode 100755 index 2cd6756..0000000 --- a/openvdb_3_0_0_library/python/pyVec3Grid.cc +++ /dev/null @@ -1,49 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file pyVec3Grid.cc -/// @brief Boost.Python wrappers for vector-valued openvdb::Grid types - -#include "pyGrid.h" - - -void -exportVec3Grid() -{ - pyGrid::exportGrid(); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES - pyGrid::exportGrid(); - pyGrid::exportGrid(); -#endif -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyopenvdb.h b/openvdb_3_0_0_library/python/pyopenvdb.h deleted file mode 100755 index 705d7ba..0000000 --- a/openvdb_3_0_0_library/python/pyopenvdb.h +++ /dev/null @@ -1,113 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file pyopenvdb.h -/// -/// @brief Glue functions for access to pyOpenVDB objects from C++ code -/// @details Use these functions in your own Python function implementations -/// to extract an OpenVDB grid from or wrap a grid in a @c PyObject. -/// For example (using Boost.Python), -/// @code -/// #include -/// #include -/// #include -/// -/// // Implementation of a Python function that processes pyOpenVDB grids -/// boost::python::object -/// processGrid(boost::python::object inObj) -/// { -/// boost::python::object outObj; -/// try { -/// // Extract an OpenVDB grid from the input argument. -/// if (openvdb::GridBase::Ptr grid = -/// pyopenvdb::getGridFromPyObject(inObj)) -/// { -/// grid = grid->deepCopyGrid(); -/// -/// // Process the grid... -/// -/// // Wrap the processed grid in a PyObject. -/// outObj = pyopenvdb::getPyObjectFromGrid(grid); -/// } -/// } catch (openvdb::TypeError& e) { -/// PyErr_Format(PyExc_TypeError, e.what()); -/// boost::python::throw_error_already_set(); -/// } -/// return outObj; -/// } -/// -/// BOOST_PYTHON_MODULE(mymodule) -/// { -/// openvdb::initialize(); -/// -/// // Definition of a Python function that processes pyOpenVDB grids -/// boost::python::def(/*name=*/"processGrid", &processGrid, /*argname=*/"grid"); -/// } -/// @endcode -/// Then, from Python, -/// @code -/// import openvdb -/// import mymodule -/// -/// grid = openvdb.read('myGrid.vdb', 'MyGrid') -/// grid = mymodule.processGrid(grid) -/// openvdb.write('myProcessedGrid.vdb', [grid]) -/// @endcode - -#ifndef PYOPENVDB_HAS_BEEN_INCLUDED -#define PYOPENVDB_HAS_BEEN_INCLUDED - -#include -#include "openvdb/Grid.h" - - -namespace pyopenvdb { - -//@{ -/// @brief Return a pointer to the OpenVDB grid held by the given Python object. -/// @throw openvdb::TypeError if the Python object is not one of the pyOpenVDB grid types. -/// (See the Python module's GridTypes global variable for the list of supported grid types.) -openvdb::GridBase::Ptr getGridFromPyObject(PyObject*); -openvdb::GridBase::Ptr getGridFromPyObject(const boost::python::object&); -//@} - -/// @brief Return a new Python object that holds the given OpenVDB grid. -/// @return @c None if the given grid pointer is null. -/// @throw openvdb::TypeError if the grid is not of a supported type. -/// (See the Python module's GridTypes global variable for the list of supported grid types.) -boost::python::object getPyObjectFromGrid(const openvdb::GridBase::Ptr&); - -} // namespace pyopenvdb - -#endif // PYOPENVDB_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/pyutil.h b/openvdb_3_0_0_library/python/pyutil.h deleted file mode 100755 index db0a1c4..0000000 --- a/openvdb_3_0_0_library/python/pyutil.h +++ /dev/null @@ -1,284 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_PYUTIL_HAS_BEEN_INCLUDED -#define OPENVDB_PYUTIL_HAS_BEEN_INCLUDED - -#include "openvdb/openvdb.h" -#include -#include -#include // for std::pair -#include -#include - - -namespace pyutil { - -/// Return a new @c boost::python::object that borrows (i.e., doesn't -/// take over ownership of) the given @c PyObject's reference. -inline boost::python::object -pyBorrow(PyObject* obj) -{ - return boost::python::object(boost::python::handle<>(boost::python::borrowed(obj))); -} - - -/// @brief Given a @c PyObject that implements the sequence protocol -/// (e.g., a @c PyListObject), return the value of type @c ValueT -/// at index @a idx in the sequence. -/// @details Raise a Python @c TypeError exception if the value -/// at index @a idx is not convertible to type @c ValueT. -template -inline ValueT -getSequenceItem(PyObject* obj, int idx) -{ - return boost::python::extract(pyBorrow(obj)[idx]); -} - - -//////////////////////////////////////// - - -template -struct GridTraitsBase -{ - /// @brief Return the name of the Python class that wraps this grid type - /// (e.g., "FloatGrid" for openvdb::FloatGrid). - /// - /// @note This name is not the same as GridType::type(). - /// The latter returns a name like "Tree_float_5_4_3". - static const char* name(); - - /// Return the name of this grid type's value type ("bool", "float", "vec3s", etc.). - static const char* valueTypeName() - { - return openvdb::typeNameAsString(); - } - - /// @brief Return a description of this grid type. - /// - /// @note This name is generated at runtime for each call to descr(). - static const std::string descr() - { - return std::string("OpenVDB grid with voxels of type ") + valueTypeName(); - } -}; // struct GridTraitsBase - - -template -struct GridTraits: public GridTraitsBase -{ -}; - -/// Map a grid type to a traits class that derives from GridTraitsBase -/// and that defines a name() method. -#define GRID_TRAITS(_typ, _name) \ - template<> struct GridTraits<_typ>: public GridTraitsBase<_typ> { \ - static const char* name() { return _name; } \ - } - -GRID_TRAITS(openvdb::FloatGrid, "FloatGrid"); -GRID_TRAITS(openvdb::Vec3SGrid, "Vec3SGrid"); -GRID_TRAITS(openvdb::BoolGrid, "BoolGrid"); -#ifdef PY_OPENVDB_WRAP_ALL_GRID_TYPES -GRID_TRAITS(openvdb::DoubleGrid, "DoubleGrid"); -GRID_TRAITS(openvdb::Int32Grid, "Int32Grid"); -GRID_TRAITS(openvdb::Int64Grid, "Int64Grid"); -GRID_TRAITS(openvdb::Vec3IGrid, "Vec3IGrid"); -GRID_TRAITS(openvdb::Vec3DGrid, "Vec3DGrid"); -#endif - -#undef GRID_TRAITS - - -//////////////////////////////////////// - - -// Note that the elements are pointers to C strings (char**), because -// boost::python::class_::def_readonly() requires a pointer to a static member. -typedef std::pair CStringPair; - - -/// @brief Enum-like mapping from string keys to string values, with characteristics -/// of both (Python) classes and class instances (as well as NamedTuples) -/// @details -/// - (@e key, @e value) pairs can be accessed as class attributes (\"MyClass.MY_KEY\") -/// - (@e key, @e value) pairs can be accessed via dict lookup on instances -/// (\"MyClass()['MY_KEY']\") -/// - (@e key, @e value) pairs can't be modified or reassigned -/// - instances are iterable (\"for key in MyClass(): ...\") -/// -/// A @c Descr class must implement the following interface: -/// @code -/// struct MyDescr -/// { -/// // Return the Python name for the enum class. -/// static const char* name(); -/// // Return the docstring for the enum class. -/// static const char* doc(); -/// // Return the ith (key, value) pair, in the form of -/// // a pair of *pointers* to C strings -/// static CStringPair item(int i); -/// }; -/// @endcode -template -struct StringEnum -{ - /// Return the (key, value) map as a Python dict. - static boost::python::dict items() - { - static tbb::mutex sMutex; - static boost::python::dict itemDict; - if (!itemDict) { - // The first time this function is called, populate - // the static dict with (key, value) pairs. - tbb::mutex::scoped_lock lock(sMutex); - if (!itemDict) { - for (int i = 0; ; ++i) { - const CStringPair item = Descr::item(i); - OPENVDB_START_THREADSAFE_STATIC_WRITE - if (item.first) { - itemDict[boost::python::str(*item.first)] = - boost::python::str(*item.second); - } - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - else break; - } - } - } - return itemDict; - } - - /// Return the keys as a Python list of strings. - static boost::python::object keys() { return items().attr("keys")(); } - /// Return the number of keys as a Python int. - boost::python::object numItems() const - { - return boost::python::object(boost::python::len(items())); - } - /// Return the value (as a Python string) for the given key. - boost::python::object getItem(boost::python::object keyObj) const { return items()[keyObj]; } - /// Return a Python iterator over the keys. - boost::python::object iter() const { return items().attr("__iter__")(); } - - /// Register this enum. - static void wrap() - { - boost::python::class_ cls( - /*classname=*/Descr::name(), - /*docstring=*/Descr::doc()); - cls.def("keys", &StringEnum::keys, "keys() -> list") - .staticmethod("keys") - .def("__len__", &StringEnum::numItems, "__len__() -> int") - .def("__iter__", &StringEnum::iter, "__iter__() -> iterator") - .def("__getitem__", &StringEnum::getItem, "__getitem__(str) -> str") - /*end*/; - // Add a read-only, class-level attribute for each (key, value) pair. - for (int i = 0; ; ++i) { - const CStringPair item = Descr::item(i); - if (item.first) cls.def_readonly(*item.first, item.second); - else break; - } - } -}; - - -//////////////////////////////////////// - - -/// @brief From the given Python object, extract a value of type @c T. -/// -/// If the object cannot be converted to type @c T, raise a @c TypeError with a more -/// Pythonic error message (incorporating the provided class and function names, etc.) -/// than the one that would be generated by boost::python::extract(), e.g., -/// "TypeError: expected float, found str as argument 2 to FloatGrid.prune()" instead of -/// "TypeError: No registered converter was able to produce a C++ rvalue of type -/// boost::shared_ptr -inline T -extractArg( - boost::python::object obj, - const char* functionName, - const char* className = NULL, - int argIdx = 0, // args are numbered starting from 1 - const char* expectedType = NULL) -{ - boost::python::extract val(obj); - if (!val.check()) { - // Generate an error string of the form - // "expected , found as argument - // to .()", where and - // are optional. - std::ostringstream os; - os << "expected "; - if (expectedType) os << expectedType; else os << openvdb::typeNameAsString(); - const std::string actualType = - boost::python::extract(obj.attr("__class__").attr("__name__")); - os << ", found " << actualType << " as argument"; - if (argIdx > 0) os << " " << argIdx; - os << " to "; - if (className) os << className << "."; - os << functionName << "()"; - - PyErr_SetString(PyExc_TypeError, os.str().c_str()); - boost::python::throw_error_already_set(); - } - return val(); -} - - -//////////////////////////////////////// - - -/// Return str(val) for the given value. -template -inline std::string -str(const T& val) -{ - return boost::python::extract(boost::python::str(val)); -} - - -/// Return the name of the given Python object's class. -inline std::string -className(boost::python::object obj) -{ - std::string s = boost::python::extract( - obj.attr("__class__").attr("__name__")); - return s; -} - -} // namespace pyutil - -#endif // OPENVDB_PYUTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/python/test/TestOpenVDB.py b/openvdb_3_0_0_library/python/test/TestOpenVDB.py deleted file mode 100755 index 0ac95f0..0000000 --- a/openvdb_3_0_0_library/python/test/TestOpenVDB.py +++ /dev/null @@ -1,798 +0,0 @@ -#!/usr/local/bin/python -# Copyright (c) 2012-2014 DreamWorks Animation LLC -# -# All rights reserved. This software is distributed under the -# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -# -# Redistributions of source code must retain the above copyright -# and license notice and the following restrictions and disclaimer. -# -# * Neither the name of DreamWorks Animation nor the names of -# its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. - -""" -Unit tests for the OpenVDB Python module - -These are intended primarily to test the Python-to-C++ and -C++-to-Python bindings, not the OpenVDB library itself. -""" - -import os, os.path -import sys -import unittest -try: - import pyopenvdb as openvdb -except ImportError: - import studioenv - from studio.ani import Ani - from studio import logging - from studio import openvdb - - -def valueFactory(zeroValue, elemValue): - """ - Return elemValue converted to a value of the same type as zeroValue. - If zeroValue is a sequence, return a sequence of the same type and length, - with each element set to elemValue. - """ - val = zeroValue - typ = type(val) - try: - # If the type is a sequence type, return a sequence of the appropriate length. - size = len(val) - val = typ([elemValue]) * size - except TypeError: - # Return a scalar value of the appropriate type. - val = typ(elemValue) - return val - - -class TestOpenVDB(unittest.TestCase): - - def run(self, result=None, *args, **kwargs): - super(TestOpenVDB, self).run(result, *args, **kwargs) - - def setUp(self): - # Make output files and directories world-writable. - self.umask = os.umask(0) - - def tearDown(self): - os.umask(self.umask) - - - def testModule(self): - # At a minimum, BoolGrid, FloatGrid and Vec3SGrid should exist. - self.assert_(openvdb.BoolGrid in openvdb.GridTypes) - self.assert_(openvdb.FloatGrid in openvdb.GridTypes) - self.assert_(openvdb.Vec3SGrid in openvdb.GridTypes) - - # Verify that it is possible to construct a grid of each supported type. - for cls in openvdb.GridTypes: - grid = cls() - acc = grid.getAccessor() - acc.setValueOn((-1, -2, 3)) - self.assertEqual(grid.activeVoxelCount(), 1) - - - def testTransform(self): - xform1 = openvdb.createLinearTransform( - [[.5, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 2, 0], - [1, 2, 3, 1]]) - self.assert_(xform1.typeName != '') - self.assertEqual(xform1.indexToWorld((1, 1, 1)), (1.5, 3, 5)) - xform2 = xform1 - self.assertEqual(xform2, xform1) - xform2 = xform1.deepCopy() - self.assertEqual(xform2, xform1) - xform2 = openvdb.createFrustumTransform(taper=0.5, depth=100, - xyzMin=(0, 0, 0), xyzMax=(100, 100, 100), voxelSize=0.25) - self.assertNotEqual(xform2, xform1) - worldp = xform2.indexToWorld((10, 10, 10)) - worldp = map(lambda x: int(round(x * 1000000)), worldp) - self.assertEqual(worldp, [-110000, -110000, 2500000]) - - grid = openvdb.FloatGrid() - self.assertEqual(grid.transform, openvdb.createLinearTransform()) - grid.transform = openvdb.createLinearTransform(2.0) - self.assertEqual(grid.transform, openvdb.createLinearTransform(2.0)) - - - def testGridCopy(self): - grid = openvdb.FloatGrid() - self.assert_(grid.sharesWith(grid)) - self.assertFalse(grid.sharesWith([])) # wrong type; Grid expected - - copyOfGrid = grid.copy() - self.assert_(copyOfGrid.sharesWith(grid)) - - deepCopyOfGrid = grid.deepCopy() - self.assertFalse(deepCopyOfGrid.sharesWith(grid)) - self.assertFalse(deepCopyOfGrid.sharesWith(copyOfGrid)) - - - def testGridProperties(self): - expected = { - openvdb.BoolGrid: ('bool', False, True), - openvdb.FloatGrid: ('float', 0.0, 1.0), - openvdb.Vec3SGrid: ('vec3s', (0, 0, 0), (-1, 0, 1)), - } - - for factory in expected: - valType, bg, newbg = expected[factory] - - grid = factory() - - self.assertEqual(grid.valueTypeName, valType) - def setValueType(obj): - obj.valueTypeName = 'double' - # Grid.valueTypeName is read-only, so setting it raises an exception. - self.assertRaises(AttributeError, lambda obj=grid: setValueType(obj)) - - self.assertEqual(grid.background, bg) - grid.background = newbg - self.assertEqual(grid.background, newbg) - - self.assertEqual(grid.name, '') - grid.name = 'test' - self.assertEqual(grid.name, 'test') - - self.assertFalse(grid.saveFloatAsHalf) - grid.saveFloatAsHalf = True - self.assert_(grid.saveFloatAsHalf) - - self.assert_(grid.treeDepth > 2) - - - def testGridMetadata(self): - grid = openvdb.BoolGrid() - - self.assertEqual(grid.metadata, {}) - - meta = { 'name': 'test', 'saveFloatAsHalf': True, 'xyz': (-1, 0, 1) } - grid.metadata = meta - self.assertEqual(grid.metadata, meta) - - meta['xyz'] = (-100, 100, 0) - grid.updateMetadata(meta) - self.assertEqual(grid.metadata, meta) - - self.assertEqual(set(grid.iterkeys()), set(meta.iterkeys())) - - for name in meta: - self.assert_(name in grid) - self.assertEqual(grid[name], meta[name]) - - for name in grid: - self.assert_(name in grid) - self.assertEqual(grid[name], meta[name]) - - self.assert_('xyz' in grid) - del grid['xyz'] - self.assertFalse('xyz' in grid) - grid['xyz'] = meta['xyz'] - self.assert_('xyz' in grid) - - grid.addStatsMetadata() - meta = grid.getStatsMetadata() - self.assertEqual(0, meta["file_voxel_count"]) - - - def testGridFill(self): - grid = openvdb.FloatGrid() - acc = grid.getAccessor() - ijk = (1, 1, 1) - - self.assertRaises(TypeError, lambda: grid.fill("", (7, 7, 7), 1, False)) - self.assertRaises(TypeError, lambda: grid.fill((0, 0, 0), "", 1, False)) - self.assertRaises(TypeError, lambda: grid.fill((0, 0, 0), (7, 7, 7), "", False)) - - self.assertFalse(acc.isValueOn(ijk)) - grid.fill((0, 0, 0), (7, 7, 7), 1, active=False) - self.assertEqual(acc.getValue(ijk), 1) - self.assertFalse(acc.isValueOn(ijk)) - - grid.fill((0, 0, 0), (7, 7, 7), 2, active=True) - self.assertEqual(acc.getValue(ijk), 2) - self.assert_(acc.isValueOn(ijk)) - - activeCount = grid.activeVoxelCount() - acc.setValueOn(ijk, 2.125) - self.assertEqual(grid.activeVoxelCount(), activeCount) - - grid.fill(ijk, ijk, 2.125, active=True) - self.assertEqual(acc.getValue(ijk), 2.125) - self.assert_(acc.isValueOn(ijk)) - self.assertEqual(grid.activeVoxelCount(), activeCount) - leafCount = grid.leafCount() - - grid.prune() - self.assertAlmostEqual(acc.getValue(ijk), 2.125) - self.assert_(acc.isValueOn(ijk)) - self.assertEqual(grid.leafCount(), leafCount) - self.assertEqual(grid.activeVoxelCount(), activeCount) - - grid.prune(tolerance=0.2) - self.assertEqual(grid.activeVoxelCount(), activeCount) - self.assertEqual(acc.getValue(ijk), 2) - self.assert_(acc.isValueOn(ijk)) - self.assert_(grid.leafCount() < leafCount) - - - def testGridIterators(self): - onCoords = set([(-10, -10, -10), (0, 0, 0), (1, 1, 1)]) - - for factory in openvdb.GridTypes: - grid = factory() - acc = grid.getAccessor() - for c in onCoords: - acc.setValueOn(c) - - coords = set(value.min for value in grid.iterOnValues()) - self.assertEqual(coords, onCoords) - - n = 0 - for _ in grid.iterAllValues(): - n += 1 - for _ in grid.iterOffValues(): - n -= 1 - self.assertEqual(n, len(onCoords)) - - grid = factory() - grid.fill((0, 0, 1), (18, 18, 18), grid.oneValue) # make active - activeCount = grid.activeVoxelCount() - - # Iterate over active values (via a const iterator) and verify - # that the cumulative active voxel count matches the grid's. - count = 0 - for value in grid.citerOnValues(): - count += value.count - self.assertEqual(count, activeCount) - - # Via a non-const iterator, turn off every other active value. - # Then verify that the cumulative active voxel count is half the original count. - state = True - for value in grid.iterOnValues(): - count -= value.count - value.active = state - state = not state - self.assertEqual(grid.activeVoxelCount(), activeCount / 2) - - # Verify that writing through a const iterator is not allowed. - value = grid.citerOnValues().next() - self.assertRaises(AttributeError, lambda: setattr(value, 'active', 0)) - self.assertRaises(AttributeError, lambda: setattr(value, 'depth', 0)) - # Verify that some value attributes are immutable, even given a non-const iterator. - value = grid.iterOnValues().next() - self.assertRaises(AttributeError, lambda: setattr(value, 'min', (0, 0, 0))) - self.assertRaises(AttributeError, lambda: setattr(value, 'max', (0, 0, 0))) - self.assertRaises(AttributeError, lambda: setattr(value, 'count', 1)) - - - def testMap(self): - grid = openvdb.BoolGrid() - grid.fill((-4, -4, -4), (5, 5, 5), grid.zeroValue) # make active - grid.mapOn(lambda x: not x) # replace active False values with True - n = sum(item.value for item in grid.iterOnValues()) - self.assertEqual(n, 10 * 10 * 10) - - grid = openvdb.FloatGrid() - grid.fill((-4, -4, -4), (5, 5, 5), grid.oneValue) - grid.mapOn(lambda x: x * 2) - n = sum(item.value for item in grid.iterOnValues()) - self.assertEqual(n, 10 * 10 * 10 * 2) - - grid = openvdb.Vec3SGrid() - grid.fill((-4, -4, -4), (5, 5, 5), grid.zeroValue) - grid.mapOn(lambda x: (0, 1, 0)) - n = sum(item.value[1] for item in grid.iterOnValues()) - self.assertEqual(n, 10 * 10 * 10) - - - def testValueAccessor(self): - coords = set([(-10, -10, -10), (0, 0, 0), (1, 1, 1)]) - - for factory in openvdb.GridTypes: - grid = factory() - zero, one = grid.zeroValue, grid.oneValue - acc = grid.getAccessor() - cacc = grid.getConstAccessor() - leafDepth = grid.treeDepth - 1 - - self.assertRaises(TypeError, lambda: cacc.setValueOn((5, 5, 5), zero)) - self.assertRaises(TypeError, lambda: cacc.setValueOff((5, 5, 5), zero)) - self.assertRaises(TypeError, lambda: cacc.setActiveState((5, 5, 5), True)) - self.assertRaises(TypeError, lambda: acc.setValueOn("", zero)) - self.assertRaises(TypeError, lambda: acc.setValueOff("", zero)) - if grid.valueTypeName != "bool": - self.assertRaises(TypeError, lambda: acc.setValueOn((5, 5, 5), object())) - self.assertRaises(TypeError, lambda: acc.setValueOff((5, 5, 5), object())) - - for c in coords: - grid.clear() - - # All voxels are inactive, background (0), and stored at the root. - self.assertEqual(acc.getValue(c), zero) - self.assertEqual(cacc.getValue(c), zero) - self.assertFalse(acc.isValueOn(c)) - self.assertFalse(cacc.isValueOn(c)) - self.assertEqual(acc.getValueDepth(c), -1) - self.assertEqual(cacc.getValueDepth(c), -1) - - acc.setValueOn(c) # active / 0 / leaf - self.assertEqual(acc.getValue(c), zero) - self.assertEqual(cacc.getValue(c), zero) - self.assert_(acc.isValueOn(c)) - self.assert_(cacc.isValueOn(c)) - self.assertEqual(acc.getValueDepth(c), leafDepth) - self.assertEqual(cacc.getValueDepth(c), leafDepth) - - acc.setValueOff(c, grid.oneValue) # inactive / 1 / leaf - self.assertEqual(acc.getValue(c), one) - self.assertEqual(cacc.getValue(c), one) - self.assertFalse(acc.isValueOn(c)) - self.assertFalse(cacc.isValueOn(c)) - self.assertEqual(acc.getValueDepth(c), leafDepth) - self.assertEqual(cacc.getValueDepth(c), leafDepth) - - # Verify that an accessor remains valid even after its grid is deleted - # (because the C++ wrapper retains a reference to the C++ grid). - def scoped(): - grid = factory() - acc = grid.getAccessor() - cacc = grid.getConstAccessor() - one = grid.oneValue - acc.setValueOn((0, 0, 0), one) - del grid - self.assertEqual(acc.getValue((0, 0, 0)), one) - self.assertEqual(cacc.getValue((0, 0, 0)), one) - scoped() - - - def testValueAccessorCopy(self): - xyz = (0, 0, 0) - grid = openvdb.BoolGrid() - - acc = grid.getAccessor() - self.assertEqual(acc.getValue(xyz), False) - self.assertFalse(acc.isValueOn(xyz)) - - copyOfAcc = acc.copy() - self.assertEqual(copyOfAcc.getValue(xyz), False) - self.assertFalse(copyOfAcc.isValueOn(xyz)) - - # Verify that changes made to the grid through one accessor are reflected in the other. - acc.setValueOn(xyz, True) - self.assertEqual(acc.getValue(xyz), True) - self.assert_(acc.isValueOn(xyz)) - self.assertEqual(copyOfAcc.getValue(xyz), True) - self.assert_(copyOfAcc.isValueOn(xyz)) - - copyOfAcc.setValueOff(xyz) - self.assertEqual(acc.getValue(xyz), True) - self.assertFalse(acc.isValueOn(xyz)) - self.assertEqual(copyOfAcc.getValue(xyz), True) - self.assertFalse(copyOfAcc.isValueOn(xyz)) - - # Verify that the two accessors are distinct, by checking that they - # have cached different sets of nodes. - xyz2 = (-1, -1, -1) - copyOfAcc.setValueOn(xyz2) - self.assert_(copyOfAcc.isCached(xyz2)) - self.assertFalse(copyOfAcc.isCached(xyz)) - self.assert_(acc.isCached(xyz)) - self.assertFalse(acc.isCached(xyz2)) - - - def testPickle(self): - import pickle - - # Test pickling of transforms of various types. - testXforms = [ - openvdb.createLinearTransform(voxelSize=0.1), - openvdb.createLinearTransform(matrix=[[1,0,0,0],[0,2,0,0],[0,0,3,0],[4,3,2,1]]), - openvdb.createFrustumTransform((0,0,0), (10,10,10), taper=0.8, depth=10.0), - ] - for xform in testXforms: - s = pickle.dumps(xform) - restoredXform = pickle.loads(s) - self.assertEqual(restoredXform, xform) - - # Test pickling of grids of various types. - for factory in openvdb.GridTypes: - - # Construct a grid. - grid = factory() - # Add some metadata to the grid. - meta = { 'name': 'test', 'saveFloatAsHalf': True, 'xyz': (-1, 0, 1) } - grid.metadata = meta - # Add some voxel data to the grid. - active = True - for width in range(63, 0, -10): - val = valueFactory(grid.zeroValue, width) - grid.fill((0, 0, 0), (width,)*3, val, active) - active = not active - - # Pickle the grid to a string, then unpickle the string. - s = pickle.dumps(grid) - restoredGrid = pickle.loads(s) - - # Verify that the original and unpickled grids' metadata are equal. - self.assertEqual(restoredGrid.metadata, meta) - - # Verify that the original and unpickled grids have the same active values. - for restored, original in zip(restoredGrid.iterOnValues(), grid.iterOnValues()): - self.assertEqual(restored, original) - # Verify that the original and unpickled grids have the same inactive values. - for restored, original in zip(restoredGrid.iterOffValues(), grid.iterOffValues()): - self.assertEqual(restored, original) - - - def testGridCombine(self): - # Construct two grids and add some voxel data to each. - aGrid, bGrid = openvdb.FloatGrid(), openvdb.FloatGrid(background=1.0) - for width in range(63, 1, -10): - aGrid.fill((0, 0, 0), (width,)*3, width) - bGrid.fill((0, 0, 0), (width,)*3, 2 * width) - - # Save a copy of grid A. - copyOfAGrid = aGrid.deepCopy() - - # Combine corresponding values of the two grids, storing the result in grid A. - # (Since the grids have the same topology and B's active values are twice A's, - # the function computes 2*min(a, 2*a) + 3*max(a, 2*a) = 2*a + 3*(2*a) = 8*a - # for active values, and 2*min(0, 1) + 3*max(0, 1) = 2*0 + 3*1 = 3 - # for inactive values.) - aGrid.combine(bGrid, lambda a, b: 2 * min(a, b) + 3 * max(a, b)) - - self.assert_(bGrid.empty()) - - # Verify that the resulting grid's values are as expected. - for original, combined in zip(copyOfAGrid.iterOnValues(), aGrid.iterOnValues()): - self.assertEqual(combined.min, original.min) - self.assertEqual(combined.max, original.max) - self.assertEqual(combined.depth, original.depth) - self.assertEqual(combined.value, 8 * original.value) - for original, combined in zip(copyOfAGrid.iterOffValues(), aGrid.iterOffValues()): - self.assertEqual(combined.min, original.min) - self.assertEqual(combined.max, original.max) - self.assertEqual(combined.depth, original.depth) - self.assertEqual(combined.value, 3) - - - def testLevelSetSphere(self): - HALF_WIDTH = 4 - sphere = openvdb.createLevelSetSphere(halfWidth=HALF_WIDTH, voxelSize=1.0, radius=100.0) - lo, hi = sphere.evalMinMax() - self.assert_(lo >= -HALF_WIDTH) - self.assert_(hi <= HALF_WIDTH) - - - def testCopyFromArray(self): - import random - import time - - # Skip this test if NumPy is not available. - try: - import numpy as np - except ImportError: - return - - # Skip this test if the OpenVDB module was built without NumPy support. - arr = np.ndarray((1, 2, 1)) - grid = openvdb.FloatGrid() - try: - grid.copyFromArray(arr) - except NotImplementedError: - return - - # Verify that a non-three-dimensional array can't be copied into a grid. - grid = openvdb.FloatGrid() - self.assertRaises(TypeError, lambda: grid.copyFromArray('abc')) - arr = np.ndarray((1, 2)) - self.assertRaises(ValueError, lambda: grid.copyFromArray(arr)) - - # Verify that complex-valued arrays are not supported. - arr = np.ndarray((1, 2, 1), dtype = complex) - grid = openvdb.FloatGrid() - self.assertRaises(TypeError, lambda: grid.copyFromArray(arr)) - - ARRAY_DIM = 201 - BG, FG = 0, 1 - - # Generate some random voxel coordinates. - random.seed(0) - def randCoord(): - return tuple(random.randint(0, ARRAY_DIM-1) for i in range(3)) - coords = set(randCoord() for i in range(200)) - - def createArrays(): - # Test both scalar- and vec3-valued (i.e., four-dimensional) arrays. - for shape in ( - (ARRAY_DIM, ARRAY_DIM, ARRAY_DIM), # scalar array - (ARRAY_DIM, ARRAY_DIM, ARRAY_DIM, 3) # vec3 array - ): - for dtype in (np.float32, np.int32, np.float64, np.int64, np.uint32, np.bool): - # Create a NumPy array, fill it with the background value, - # then set some elements to the foreground value. - arr = np.ndarray(shape, dtype) - arr.fill(BG) - bg = arr[0, 0, 0] - for c in coords: - arr[c] = FG - - yield arr - - # Test copying from arrays of various types to grids of various types. - for cls in openvdb.GridTypes: - for arr in createArrays(): - isScalarArray = (len(arr.shape) == 3) - isScalarGrid = False - try: - len(cls.zeroValue) # values of vector grids are sequences, which have a length - except TypeError: - isScalarGrid = True # values of scalar grids have no length - - gridBG = valueFactory(cls.zeroValue, BG) - gridFG = valueFactory(cls.zeroValue, FG) - - # Create an empty grid. - grid = cls(gridBG) - acc = grid.getAccessor() - - # Verify that scalar arrays can't be copied into vector grids - # and vector arrays can't be copied into scalar grids. - if isScalarGrid != isScalarArray: - self.assertRaises(ValueError, lambda: grid.copyFromArray(arr)) - continue - - # Copy values from the NumPy array to the grid, marking - # background values as inactive and all other values as active. - now = time.clock() - grid.copyFromArray(arr) - elapsed = time.clock() - now - #print 'copied %d voxels from %s array to %s in %f sec' % ( - # arr.shape[0] * arr.shape[1] * arr.shape[2], - # str(arr.dtype) + ('' if isScalarArray else '[]'), - # grid.__class__.__name__, elapsed) - - # Verify that the grid's active voxels match the array's foreground elements. - self.assertEqual(grid.activeVoxelCount(), len(coords)) - for c in coords: - self.assertEqual(acc.getValue(c), gridFG) - for value in grid.iterOnValues(): - self.assert_(value.min in coords) - - - def testCopyToArray(self): - import random - import time - - # Skip this test if NumPy is not available. - try: - import numpy as np - except ImportError: - return - - # Skip this test if the OpenVDB module was built without NumPy support. - arr = np.ndarray((1, 2, 1)) - grid = openvdb.FloatGrid() - try: - grid.copyFromArray(arr) - except NotImplementedError: - return - - # Verify that a grid can't be copied into a non-three-dimensional array. - grid = openvdb.FloatGrid() - self.assertRaises(TypeError, lambda: grid.copyToArray('abc')) - arr = np.ndarray((1, 2)) - self.assertRaises(ValueError, lambda: grid.copyToArray(arr)) - - # Verify that complex-valued arrays are not supported. - arr = np.ndarray((1, 2, 1), dtype = complex) - grid = openvdb.FloatGrid() - self.assertRaises(TypeError, lambda: grid.copyToArray(arr)) - - ARRAY_DIM = 201 - BG, FG = 0, 1 - - # Generate some random voxel coordinates. - random.seed(0) - def randCoord(): - return tuple(random.randint(0, ARRAY_DIM-1) for i in range(3)) - coords = set(randCoord() for i in range(200)) - - def createArrays(): - # Test both scalar- and vec3-valued (i.e., four-dimensional) arrays. - for shape in ( - (ARRAY_DIM, ARRAY_DIM, ARRAY_DIM), # scalar array - (ARRAY_DIM, ARRAY_DIM, ARRAY_DIM, 3) # vec3 array - ): - for dtype in (np.float32, np.int32, np.float64, np.int64, np.uint32, np.bool): - # Return a new NumPy array. - arr = np.ndarray(shape, dtype) - arr.fill(-100) - yield arr - - # Test copying from arrays of various types to grids of various types. - for cls in openvdb.GridTypes: - for arr in createArrays(): - isScalarArray = (len(arr.shape) == 3) - isScalarGrid = False - try: - len(cls.zeroValue) # values of vector grids are sequences, which have a length - except TypeError: - isScalarGrid = True # values of scalar grids have no length - - gridBG = valueFactory(cls.zeroValue, BG) - gridFG = valueFactory(cls.zeroValue, FG) - - # Create an empty grid, fill it with the background value, - # then set some elements to the foreground value. - grid = cls(gridBG) - acc = grid.getAccessor() - for c in coords: - acc.setValueOn(c, gridFG) - - # Verify that scalar grids can't be copied into vector arrays - # and vector grids can't be copied into scalar arrays. - if isScalarGrid != isScalarArray: - self.assertRaises(ValueError, lambda: grid.copyToArray(arr)) - continue - - # Copy values from the grid to the NumPy array. - now = time.clock() - grid.copyToArray(arr) - elapsed = time.clock() - now - #print 'copied %d voxels from %s to %s array in %f sec' % ( - # arr.shape[0] * arr.shape[1] * arr.shape[2], grid.__class__.__name__, - # str(arr.dtype) + ('' if isScalarArray else '[]'), elapsed) - - # Verify that the grid's active voxels match the array's foreground elements. - for c in coords: - self.assertEqual(arr[c] if isScalarArray else tuple(arr[c]), gridFG) - arr[c] = gridBG - self.assertEqual(np.amin(arr), BG) - self.assertEqual(np.amax(arr), BG) - - - def testMeshConversion(self): - import time - - # Skip this test if NumPy is not available. - try: - import numpy as np - except ImportError: - return - - # Test mesh to volume conversion. - - # Generate the vertices of a cube. - cubeVertices = [(x, y, z) for x in (0, 100) for y in (0, 100) for z in (0, 100)] - cubePoints = np.array(cubeVertices, float) - - # Generate the faces of a cube. - cubeQuads = np.array([ - (0, 1, 3, 2), # left - (0, 2, 6, 4), # front - (4, 6, 7, 5), # right - (5, 7, 3, 1), # back - (2, 3, 7, 6), # top - (0, 4, 5, 1), # bottom - ], float) - - voxelSize = 2.0 - halfWidth = 3.0 - xform = openvdb.createLinearTransform(voxelSize) - - # Only scalar, floating-point grids support createLevelSetFromPolygons() - # (and the OpenVDB module might have been compiled without DoubleGrid support). - grids = [] - for gridType in [n for n in openvdb.GridTypes - if n.__name__ in ('FloatGrid', 'DoubleGrid')]: - - # Skip this test if the OpenVDB module was built without NumPy support. - try: - grid = gridType.createLevelSetFromPolygons( - cubePoints, quads=cubeQuads, transform=xform, halfWidth=halfWidth) - except NotImplementedError: - return - - #openvdb.write('/tmp/testMeshConversion.vdb', grid) - - self.assertEqual(grid.transform, xform) - self.assertEqual(grid.background, halfWidth * voxelSize) - - dim = grid.evalActiveVoxelDim() - self.assert_(50 < dim[0] < 58) - self.assert_(50 < dim[1] < 58) - self.assert_(50 < dim[2] < 58) - - grids.append(grid) - - # Boolean-valued grids can't be used to store level sets. - self.assertRaises(TypeError, lambda: openvdb.BoolGrid.createLevelSetFromPolygons( - cubePoints, quads=cubeQuads, transform=xform, halfWidth=halfWidth)) - # Vector-valued grids can't be used to store level sets. - self.assertRaises(TypeError, lambda: openvdb.Vec3SGrid.createLevelSetFromPolygons( - cubePoints, quads=cubeQuads, transform=xform, halfWidth=halfWidth)) - # The "points" argument to createLevelSetFromPolygons() must be a NumPy array. - self.assertRaises(TypeError, lambda: openvdb.FloatGrid.createLevelSetFromPolygons( - cubeVertices, quads=cubeQuads, transform=xform, halfWidth=halfWidth)) - # The "points" argument to createLevelSetFromPolygons() must be a NumPy float or int array. - self.assertRaises(TypeError, lambda: openvdb.FloatGrid.createLevelSetFromPolygons( - np.array(cubeVertices, bool), quads=cubeQuads, transform=xform, halfWidth=halfWidth)) - # The "triangles" argument to createLevelSetFromPolygons() must be an N x 3 NumPy array. - self.assertRaises(TypeError, lambda: openvdb.FloatGrid.createLevelSetFromPolygons( - cubePoints, triangles=cubeQuads, transform=xform, halfWidth=halfWidth)) - - # Test volume to mesh conversion. - - # Vector-valued grids can't be meshed. - self.assertRaises(TypeError, lambda: openvdb.Vec3SGrid().convertToQuads()) - - for grid in grids: - points, quads = grid.convertToQuads() - - # These checks are intended mainly to test the Python/C++ bindings, - # not the OpenVDB volume to mesh converter. - self.assert_(len(points) > 8) - self.assert_(len(quads) > 6) - pmin, pmax = points.min(0), points.max(0) - self.assert_(-2 < pmin[0] < 2) - self.assert_(-2 < pmin[1] < 2) - self.assert_(-2 < pmin[2] < 2) - self.assert_(98 < pmax[0] < 102) - self.assert_(98 < pmax[1] < 102) - self.assert_(98 < pmax[2] < 102) - - points, triangles, quads = grid.convertToPolygons(adaptivity=1) - - self.assert_(len(points) > 8) - pmin, pmax = points.min(0), points.max(0) - self.assert_(-2 < pmin[0] < 2) - self.assert_(-2 < pmin[1] < 2) - self.assert_(-2 < pmin[2] < 2) - self.assert_(98 < pmax[0] < 102) - self.assert_(98 < pmax[1] < 102) - self.assert_(98 < pmax[2] < 102) - - -if __name__ == '__main__': - print 'Testing', os.path.dirname(openvdb.__file__) - sys.stdout.flush() - - try: - logging.configure(sys.argv) - args = Ani(sys.argv).userArgs() # strip out ANI-related arguments - except NameError: - args = sys.argv - - # Unlike CppUnit, PyUnit doesn't use the "-t" flag to identify - # test names, so for consistency, strip out any "-t" arguments, - # so that, e.g., "TestOpenVDB.py -t TestOpenVDB.testTransform" - # is equivalent to "TestOpenVDB.py TestOpenVDB.testTransform". - args = [a for a in args if a != '-t'] - - unittest.main(argv=args) - - -# Copyright (c) 2012-2014 DreamWorks Animation LLC -# All rights reserved. This software is distributed under the -# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/ChangeBackground.h b/openvdb_3_0_0_library/tools/ChangeBackground.h deleted file mode 100755 index 23d9939..0000000 --- a/openvdb_3_0_0_library/tools/ChangeBackground.h +++ /dev/null @@ -1,278 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file ChangeBackground.h -/// -/// @brief Efficient multi-threaded replacement of the background -/// values in tree. -/// -/// @author Ken Museth - -#ifndef OPENVDB_TOOLS_ChangeBACKGROUND_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_ChangeBACKGROUND_HAS_BEEN_INCLUDED - -#include // for isNegative and negative -#include // for Index typedef -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Replace the background value in all the nodes of a tree. -/// @details The sign of the background value is perserved, and only -/// inactive values equal to the old background value are replaced. -/// -/// @note If a LeafManager is used the cached leaf nodes are reused, -/// resulting in slightly better overall performance. -/// -/// @param tree Tree (or LeafManager) that will have its background value changed -/// @param background the new background value -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 32) -template -inline void -changeBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& background, - bool threaded = true, - size_t grainSize = 32); - - -/// @brief Replace the background value in all the nodes of a floating-point tree -/// containing a symmetric narrow-band level set. -/// @details All inactive values will be set to +| @a halfWidth | if outside -/// and -| @a halfWidth | if inside, where @a halfWidth is half the width -/// of the symmetric narrow band. -/// -/// @note This method is faster than changeBackground since it does not -/// perform tests to see if inactive values are equal to the old background value. -/// @note If a LeafManager is used the cached leaf nodes are reused, -/// resulting in slightly better overall performance. -/// -/// @param tree Tree (or LeafManager) that will have its background value changed -/// @param halfWidth half of the width of the symmetric narrow band -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 32) -/// -/// @throw ValueError if @a halfWidth is negative (as defined by math::isNegative) -template -inline void -changeLevelSetBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& halfWidth, - bool threaded = true, - size_t grainSize = 32); - - -/// @brief Replace the background values in all the nodes of a floating-point tree -/// containing a possibly asymmetric narrow-band level set. -/// @details All inactive values will be set to +| @a outsideWidth | if outside -/// and -| @a insideWidth | if inside, where @a outsideWidth is the outside -/// width of the narrow band and @a insideWidth is its inside width. -/// -/// @note This method is faster than changeBackground since it does not -/// perform tests to see if inactive values are equal to the old background value. -/// @note If a LeafManager is used the cached leaf nodes are reused, -/// resulting in slightly better overall performance. -/// -/// @param tree Tree (or LeafManager) that will have its background value changed -/// @param outsideWidth The width of the outside of the narrow band -/// @param insideWidth The width of the inside of the narrow band -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 32) -/// -/// @throw ValueError if @a outsideWidth is negative or @a insideWidth is -/// not negative (as defined by math::isNegative) -template -inline void -changeAsymmetricLevelSetBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& outsideWidth, - const typename TreeOrLeafManagerT::ValueType& insideWidth, - bool threaded = true, - size_t grainSize = 32); - - -////////////////////////////////////////////////////// - - -// Replaces the background value in a Tree of any type. -template -class ChangeBackgroundOp -{ -public: - typedef typename TreeOrLeafManagerT::ValueType ValueT; - typedef typename TreeOrLeafManagerT::RootNodeType RootT; - typedef typename TreeOrLeafManagerT::LeafNodeType LeafT; - - - ChangeBackgroundOp(const TreeOrLeafManagerT& tree, const ValueT& newValue) - : mOldValue(tree.root().background()) - , mNewValue(newValue) - { - } - void operator()(RootT& root) const - { - for (typename RootT::ValueOffIter it = root.beginValueOff(); it; ++it) this->set(it); - root.setBackground(mNewValue, false); - } - void operator()(LeafT& node) const - { - for (typename LeafT::ValueOffIter it = node.beginValueOff(); it; ++it) this->set(it); - } - template - void operator()(NodeT& node) const - { - typename NodeT::NodeMaskType mask = node.getValueOffMask(); - for (typename NodeT::ValueOnIter it(mask.beginOn(), &node); it; ++it) this->set(it); - } -private: - - template - inline void set(IterT& iter) const - { - if (math::isApproxEqual(*iter, mOldValue)) { - iter.setValue(mNewValue); - } else if (math::isApproxEqual(*iter, math::negative(mOldValue))) { - iter.setValue(math::negative(mNewValue)); - } - } - const ValueT mOldValue, mNewValue; -};// ChangeBackgroundOp - - -// Replaces the background value in a Tree assumed to represent a -// level set. It is generally faster then ChangeBackgroundOp. -// Note that is follows the sign-convension that outside is positive -// and inside is negative! -template -class ChangeLevelSetBackgroundOp -{ -public: - typedef typename TreeOrLeafManagerT::ValueType ValueT; - typedef typename TreeOrLeafManagerT::RootNodeType RootT; - typedef typename TreeOrLeafManagerT::LeafNodeType LeafT; - - /// @brief Constructor for asymetric narrow-bands - ChangeLevelSetBackgroundOp(const ValueT& outside, const ValueT& inside) - : mOutside(outside) - , mInside(inside) - { - if (math::isNegative(mOutside)) { - OPENVDB_THROW(ValueError, - "ChangeLevelSetBackgroundOp: the outside value cannot be negative!"); - } - if (!math::isNegative(mInside)) { - OPENVDB_THROW(ValueError, - "ChangeLevelSetBackgroundOp: the inside value must be negative!"); - } - } - void operator()(RootT& root) const - { - for (typename RootT::ValueOffIter it = root.beginValueOff(); it; ++it) this->set(it); - root.setBackground(mOutside, false); - } - void operator()(LeafT& node) const - { - for(typename LeafT::ValueOffIter it = node.beginValueOff(); it; ++it) this->set(it); - } - template - void operator()(NodeT& node) const - { - typedef typename NodeT::ValueOffIter IterT; - for (IterT it(node.getChildMask().beginOff(), &node); it; ++it) this->set(it); - } -private: - - template - inline void set(IterT& iter) const - { - //this is safe since we know ValueType is_floating_point - ValueT& v = const_cast(*iter); - v = v < 0 ? mInside : mOutside; - } - const ValueT mOutside, mInside; -};// ChangeLevelSetBackgroundOp - - -template -inline void -changeBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& background, - bool threaded, - size_t grainSize) -{ - tree::NodeManager linearTree(tree); - ChangeBackgroundOp op(tree, background); - linearTree.processTopDown(op, threaded, grainSize); -} - - -template -inline void -changeAsymmetricLevelSetBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& outsideValue, - const typename TreeOrLeafManagerT::ValueType& insideValue, - bool threaded, - size_t grainSize) -{ - tree::NodeManager linearTree(tree); - ChangeLevelSetBackgroundOp op(outsideValue, insideValue); - linearTree.processTopDown(op, threaded, grainSize); -} - - -// If the narrow-band is symmetric only one background value is required -template -inline void -changeLevelSetBackground( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& background, - bool threaded, - size_t grainSize) -{ - changeAsymmetricLevelSetBackground( - tree, background, math::negative(background), threaded, grainSize); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_CHANGEBACKGROUND_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Clip.h b/openvdb_3_0_0_library/tools/Clip.h deleted file mode 100755 index 87bdc9f..0000000 --- a/openvdb_3_0_0_library/tools/Clip.h +++ /dev/null @@ -1,421 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Clip.h -/// -/// @brief Functions to clip a grid against a bounding box or against -/// another grid's active voxel topology - -#ifndef OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED - -#include -#include -#include "GridTransformer.h" // for resampleToMatch() -#include -#include -#include -#include -#include -#include "Prune.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Clip the given grid against a world-space bounding box -/// and return a new grid containing the result. -/// @warning Clipping a level set will likely produce a grid that is -/// no longer a valid level set. -template OPENVDB_STATIC_SPECIALIZATION -inline typename GridType::Ptr clip(const GridType& grid, const BBoxd&); - -/// @brief Clip a grid against the active voxels of another grid -/// and return a new grid containing the result. -/// @param grid the grid to be clipped -/// @param mask a grid whose active voxels form a boolean clipping mask -/// @details The mask grid need not have the same transform as the source grid. -/// Also, if the mask grid is a level set, consider using tools::sdfInteriorMask -/// to construct a new mask comprising the interior (rather than the narrow band) -/// of the level set. -/// @warning Clipping a level set will likely produce a grid that is -/// no longer a valid level set. -template OPENVDB_STATIC_SPECIALIZATION -inline typename GridType::Ptr clip(const GridType& grid, const Grid& mask); - - -//////////////////////////////////////// - - -namespace clip_internal { - -// If T is a signed type, return bool(T < 0). -template -inline typename boost::enable_if, bool>::type -lessThanZero(const T& v) { return v < zeroVal(); } - -// If T is an unsigned type, no value of type T is less than zero. -template -inline typename boost::disable_if, bool>::type -lessThanZero(const T&) { return false; } - - -//////////////////////////////////////// - - -template -class MaskInteriorVoxels -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType LeafNodeT; - - MaskInteriorVoxels(const TreeT& tree): mAcc(tree) {} - - template - void operator()(LeafNodeType &leaf, size_t /*leafIndex*/) const - { - const LeafNodeT *refLeaf = mAcc.probeConstLeaf(leaf.origin()); - if (refLeaf) { - typename LeafNodeType::ValueOffIter iter = leaf.beginValueOff(); - for ( ; iter; ++iter) { - const Index pos = iter.pos(); - leaf.setActiveState(pos, lessThanZero(refLeaf->getValue(pos))); - } - } - } - -private: - tree::ValueAccessor mAcc; -}; - - -//////////////////////////////////////// - - -template -class CopyLeafNodes -{ -public: - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - typedef tree::LeafManager BoolLeafManagerT; - - CopyLeafNodes(const TreeT& tree, const BoolLeafManagerT& leafNodes); - - void run(bool threaded = true); - - typename TreeT::Ptr tree() const { return mNewTree; } - - CopyLeafNodes(CopyLeafNodes&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(const CopyLeafNodes& rhs) { mNewTree->merge(*rhs.mNewTree); } - -private: - const BoolTreeT* mClipMask; - const TreeT* mTree; - const BoolLeafManagerT* mLeafNodes; - typename TreeT::Ptr mNewTree; -}; - - -template -CopyLeafNodes::CopyLeafNodes(const TreeT& tree, const BoolLeafManagerT& leafNodes) - : mTree(&tree) - , mLeafNodes(&leafNodes) - , mNewTree(new TreeT(mTree->background())) -{ -} - - -template -CopyLeafNodes::CopyLeafNodes(CopyLeafNodes& rhs, tbb::split) - : mTree(rhs.mTree) - , mLeafNodes(rhs.mLeafNodes) - , mNewTree(new TreeT(mTree->background())) -{ -} - - -template -void -CopyLeafNodes::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mLeafNodes->getRange(), *this); - else (*this)(mLeafNodes->getRange()); -} - - -template -void -CopyLeafNodes::operator()(const tbb::blocked_range& range) -{ - typedef typename TreeT::LeafNodeType LeafT; - typedef typename BoolTree::LeafNodeType BoolLeafT; - typename BoolLeafT::ValueOnCIter it; - - tree::ValueAccessor acc(*mNewTree); - tree::ValueAccessor refAcc(*mTree); - - for (size_t n = range.begin(); n != range.end(); ++n) { - const BoolLeafT& maskLeaf = mLeafNodes->leaf(n); - const Coord& ijk = maskLeaf.origin(); - const LeafT* refLeaf = refAcc.probeConstLeaf(ijk); - - LeafT* newLeaf = acc.touchLeaf(ijk); - - if (refLeaf) { - for (it = maskLeaf.cbeginValueOn(); it; ++it) { - const Index pos = it.pos(); - newLeaf->setValueOnly(pos, refLeaf->getValue(pos)); - newLeaf->setActiveState(pos, refLeaf->isValueOn(pos)); - } - } else { - typename TreeT::ValueType value; - bool isActive = refAcc.probeValue(ijk, value); - - for (it = maskLeaf.cbeginValueOn(); it; ++it) { - const Index pos = it.pos(); - newLeaf->setValueOnly(pos, value); - newLeaf->setActiveState(pos, isActive); - } - } - } -} - - -//////////////////////////////////////// - - -struct BoolSampler -{ - static const char* name() { return "bin"; } - static int radius() { return 2; } - static bool mipmap() { return false; } - static bool consistent() { return true; } - - template - static bool sample(const TreeT& inTree, - const Vec3R& inCoord, typename TreeT::ValueType& result) - { - Coord ijk; - ijk[0] = int(std::floor(inCoord[0])); - ijk[1] = int(std::floor(inCoord[1])); - ijk[2] = int(std::floor(inCoord[2])); - return inTree.probeValue(ijk, result); - } -}; - - -//////////////////////////////////////// - - -// Convert a grid of one type to a grid of another type -template -struct ConvertGrid -{ - typedef typename FromGridT::Ptr FromGridPtrT; - typedef typename ToGridT::Ptr ToGridPtrT; - ToGridPtrT operator()(const FromGridPtrT& grid) { return ToGridPtrT(new ToGridT(*grid)); } -}; - -// Partial specialization that avoids copying when -// the input and output grid types are the same -template -struct ConvertGrid -{ - typedef typename GridT::Ptr GridPtrT; - GridPtrT operator()(const GridPtrT& grid) { return grid; } -}; - - -//////////////////////////////////////// - - -// Convert a grid of arbitrary type to a boolean mask grid and return a pointer to the new grid. -template -inline typename boost::disable_if, - typename GridT::template ValueConverter::Type::Ptr>::type -convertToBoolMaskGrid(const GridT& grid) -{ - typedef typename GridT::template ValueConverter::Type BoolGridT; - typedef typename BoolGridT::Ptr BoolGridPtrT; - - // Convert the input grid to a boolean mask grid (with the same tree configuration). - BoolGridPtrT mask = BoolGridT::create(/*background=*/false); - mask->topologyUnion(grid); - mask->setTransform(grid.constTransform().copy()); - return mask; -} - -// Overload that avoids any processing if the input grid is already a boolean grid -template -inline typename boost::enable_if, - typename GridT::Ptr>::type -convertToBoolMaskGrid(const GridT& grid) -{ - return grid.copy(); // shallow copy -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -doClip(const GridType& grid, const typename GridType::template ValueConverter::Type& aMask) -{ - typedef typename GridType::TreeType TreeT; - typedef typename GridType::TreeType::template ValueConverter::Type BoolTreeT; - - const GridClass gridClass = grid.getGridClass(); - const TreeT& tree = grid.tree(); - - BoolTreeT mask(false); - mask.topologyUnion(tree); - - if (gridClass == GRID_LEVEL_SET) { - tree::LeafManager leafNodes(mask); - leafNodes.foreach(MaskInteriorVoxels(tree)); - - tree::ValueAccessor acc(tree); - - typename BoolTreeT::ValueAllIter iter(mask); - iter.setMaxDepth(BoolTreeT::ValueAllIter::LEAF_DEPTH - 1); - - for ( ; iter; ++iter) { - iter.setActiveState(lessThanZero(acc.getValue(iter.getCoord()))); - } - } - - mask.topologyIntersection(aMask.constTree()); - - typename GridType::Ptr outGrid; - { - // Copy voxel values and states. - tree::LeafManager leafNodes(mask); - CopyLeafNodes maskOp(tree, leafNodes); - maskOp.run(); - outGrid = GridType::create(maskOp.tree()); - } - { - // Copy tile values and states. - tree::ValueAccessor refAcc(tree); - tree::ValueAccessor maskAcc(mask); - - typename TreeT::ValueAllIter it(outGrid->tree()); - it.setMaxDepth(TreeT::ValueAllIter::LEAF_DEPTH - 1); - for ( ; it; ++it) { - Coord ijk = it.getCoord(); - - if (maskAcc.isValueOn(ijk)) { - typename TreeT::ValueType value; - bool isActive = refAcc.probeValue(ijk, value); - - it.setValue(value); - if (!isActive) it.setValueOff(); - } - } - } - - outGrid->setTransform(grid.transform().copy()); - if (gridClass != GRID_LEVEL_SET) outGrid->setGridClass(gridClass); - - return outGrid; -} - -} // namespace clip_internal - - -//////////////////////////////////////// - - -template -OPENVDB_STATIC_SPECIALIZATION -inline typename GridType::Ptr -clip(const GridType& grid, const BBoxd& bbox) -{ - typedef typename GridType::template ValueConverter::Type BoolGridT; - - // Transform the world-space bounding box into the source grid's index space. - Vec3d idxMin, idxMax; - math::calculateBounds(grid.constTransform(), bbox.min(), bbox.max(), idxMin, idxMax); - CoordBBox region(Coord::floor(idxMin), Coord::floor(idxMax)); - // Construct a boolean mask grid that is true inside the index-space bounding box - // and false everywhere else. - BoolGridT clipMask(/*background=*/false); - clipMask.fill(region, /*value=*/true, /*active=*/true); - - return clip_internal::doClip(grid, clipMask); -} - - -template -OPENVDB_STATIC_SPECIALIZATION -inline typename GridType::Ptr -clip(const GridType& grid, const Grid& maskGrid) -{ - typedef typename GridType::template ValueConverter::Type BoolGridT; - typedef typename BoolGridT::Ptr BoolGridPtrT; - - typedef Grid MaskGridType; - typedef typename MaskGridType::template ValueConverter::Type BoolMaskGridT; - typedef typename BoolMaskGridT::Ptr BoolMaskGridPtrT; - - // Convert the mask grid to a boolean grid with the same tree configuration. - BoolMaskGridPtrT boolMaskGrid = clip_internal::convertToBoolMaskGrid(maskGrid); - - // Resample the boolean mask grid into the source grid's index space. - if (grid.constTransform() != boolMaskGrid->constTransform()) { - BoolMaskGridPtrT resampledMask = BoolMaskGridT::create(/*background=*/false); - resampledMask->setTransform(grid.constTransform().copy()); - tools::resampleToMatch(*boolMaskGrid, *resampledMask); - tools::prune(resampledMask->tree()); - boolMaskGrid = resampledMask; - } - - // Convert the bool mask grid to a bool grid of the same configuration as the source grid. - BoolGridPtrT clipMask = - clip_internal::ConvertGrid()(boolMaskGrid); - - // Clip the source grid against the boolean mask grid. - return clip_internal::doClip(grid, *clipMask); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_CLIP_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Composite.h b/openvdb_3_0_0_library/tools/Composite.h deleted file mode 100755 index 63e5353..0000000 --- a/openvdb_3_0_0_library/tools/Composite.h +++ /dev/null @@ -1,592 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Composite.h -/// -/// @brief Functions to efficiently perform various compositing operations on grids -/// -/// @author Peter Cucka - -#ifndef OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include // for isExactlyEqual() -#include "ValueTransformer.h" // for transformValues() -#include "Prune.h"// for prune -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Given two level set grids, replace the A grid with the union of A and B. -/// @throw ValueError if the background value of either grid is not greater than zero. -/// @note This operation always leaves the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); -/// @brief Given two level set grids, replace the A grid with the intersection of A and B. -/// @throw ValueError if the background value of either grid is not greater than zero. -/// @note This operation always leaves the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); -/// @brief Given two level set grids, replace the A grid with the difference A / B. -/// @throw ValueError if the background value of either grid is not greater than zero. -/// @note This operation always leaves the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune = true); - -/// @brief Given grids A and B, compute max(a, b) per voxel (using sparse traversal). -/// Store the result in the A grid and leave the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void compMax(GridOrTreeT& a, GridOrTreeT& b); -/// @brief Given grids A and B, compute min(a, b) per voxel (using sparse traversal). -/// Store the result in the A grid and leave the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void compMin(GridOrTreeT& a, GridOrTreeT& b); -/// @brief Given grids A and B, compute a + b per voxel (using sparse traversal). -/// Store the result in the A grid and leave the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void compSum(GridOrTreeT& a, GridOrTreeT& b); -/// @brief Given grids A and B, compute a * b per voxel (using sparse traversal). -/// Store the result in the A grid and leave the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void compMul(GridOrTreeT& a, GridOrTreeT& b); -/// @brief Given grids A and B, compute a / b per voxel (using sparse traversal). -/// Store the result in the A grid and leave the B grid empty. -template OPENVDB_STATIC_SPECIALIZATION -inline void compDiv(GridOrTreeT& a, GridOrTreeT& b); - -/// Copy the active voxels of B into A. -template OPENVDB_STATIC_SPECIALIZATION -inline void compReplace(GridOrTreeT& a, const GridOrTreeT& b); - - -//////////////////////////////////////// - - -namespace composite { - -// composite::min() and composite::max() for non-vector types compare with operator<(). -template inline -const typename boost::disable_if_c::IsVec, T>::type& // = T if T is not a vector type -min(const T& a, const T& b) { return std::min(a, b); } - -template inline -const typename boost::disable_if_c::IsVec, T>::type& -max(const T& a, const T& b) { return std::max(a, b); } - - -// composite::min() and composite::max() for OpenVDB vector types compare by magnitude. -template inline -const typename boost::enable_if_c::IsVec, T>::type& // = T if T is a vector type -min(const T& a, const T& b) -{ - const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr(); - return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b))); -} - -template inline -const typename boost::enable_if_c::IsVec, T>::type& -max(const T& a, const T& b) -{ - const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr(); - return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b))); -} - - -template inline -typename boost::disable_if, T>::type // = T if T is not an integer type -divide(const T& a, const T& b) { return a / b; } - -template inline -typename boost::enable_if, T>::type // = T if T is an integer type -divide(const T& a, const T& b) -{ - const T zero(0); - if (b != zero) return a / b; - if (a == zero) return 0; - return (a > 0 ? std::numeric_limits::max() : -std::numeric_limits::max()); -} - -// If b is true, return a / 1 = a. -// If b is false and a is true, return 1 / 0 = inf = MAX_BOOL = 1 = a. -// If b is false and a is false, return 0 / 0 = NaN = 0 = a. -inline bool divide(bool a, bool /*b*/) { return a; } - -} // namespace composite - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compMax(GridOrTreeT& aTree, GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - struct Local { - static inline void op(CombineArgs& args) { - args.setResult(composite::max(args.a(), args.b())); - } - }; - Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); -} - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compMin(GridOrTreeT& aTree, GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - struct Local { - static inline void op(CombineArgs& args) { - args.setResult(composite::min(args.a(), args.b())); - } - }; - Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); -} - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compSum(GridOrTreeT& aTree, GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - struct Local { - static inline void op(CombineArgs& args) { - args.setResult(args.a() + args.b()); - } - }; - Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); -} - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compMul(GridOrTreeT& aTree, GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - struct Local { - static inline void op(CombineArgs& args) { - args.setResult(args.a() * args.b()); - } - }; - Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); -} - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compDiv(GridOrTreeT& aTree, GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - struct Local { - static inline void op(CombineArgs& args) { - args.setResult(composite::divide(args.a(), args.b())); - } - }; - Adapter::tree(aTree).combineExtended(Adapter::tree(bTree), Local::op, /*prune=*/false); -} - - -//////////////////////////////////////// - - -template -struct CompReplaceOp -{ - TreeT* const aTree; - - CompReplaceOp(TreeT& _aTree): aTree(&_aTree) {} - - void operator()(const typename TreeT::ValueOnCIter& iter) const - { - CoordBBox bbox; - iter.getBoundingBox(bbox); - aTree->fill(bbox, *iter); - } - - void operator()(const typename TreeT::LeafCIter& leafIter) const - { - tree::ValueAccessor acc(*aTree); - for (typename TreeT::LeafCIter::LeafNodeT::ValueOnCIter iter = - leafIter->cbeginValueOn(); iter; ++iter) - { - acc.setValue(iter.getCoord(), *iter); - } - } -}; - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -compReplace(GridOrTreeT& aTree, const GridOrTreeT& bTree) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - typedef typename TreeT::ValueOnCIter ValueOnCIterT; - - // Copy active states (but not values) from B to A. - Adapter::tree(aTree).topologyUnion(Adapter::tree(bTree)); - - CompReplaceOp op(Adapter::tree(aTree)); - - // Copy all active tile values from B to A. - ValueOnCIterT iter = bTree.cbeginValueOn(); - iter.setMaxDepth(iter.getLeafDepth() - 1); // don't descend into leaf nodes - foreach(iter, op); - - // Copy all active voxel values from B to A. - foreach(Adapter::tree(bTree).cbeginLeaf(), op); -} - - -//////////////////////////////////////// - - -/// Base visitor class for CSG operations -/// (not intended to be used polymorphically, so no virtual functions) -template -class CsgVisitorBase -{ -public: - typedef TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT; - - enum { STOP = 3 }; - - CsgVisitorBase(const TreeT& aTree, const TreeT& bTree): - mAOutside(aTree.background()), - mAInside(math::negative(mAOutside)), - mBOutside(bTree.background()), - mBInside(math::negative(mBOutside)) - { - const ValueT zero = zeroVal(); - if (!(mAOutside > zero)) { - OPENVDB_THROW(ValueError, - "expected grid A outside value > 0, got " << mAOutside); - } - if (!(mAInside < zero)) { - OPENVDB_THROW(ValueError, - "expected grid A inside value < 0, got " << mAInside); - } - if (!(mBOutside > zero)) { - OPENVDB_THROW(ValueError, - "expected grid B outside value > 0, got " << mBOutside); - } - if (!(mBInside < zero)) { - OPENVDB_THROW(ValueError, - "expected grid B outside value < 0, got " << mBOutside); - } - } - -protected: - ValueT mAOutside, mAInside, mBOutside, mBInside; -}; - - -//////////////////////////////////////// - - -template -struct CsgUnionVisitor: public CsgVisitorBase -{ - typedef TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT; - - enum { STOP = CsgVisitorBase::STOP }; - - CsgUnionVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase(a, b) {} - - /// Don't process nodes that are at different tree levels. - template - inline int operator()(AIterT&, BIterT&) { return 0; } - - /// Process root and internal nodes. - template - inline int operator()(IterT& aIter, IterT& bIter) - { - ValueT aValue = zeroVal(); - typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue); - if (!aChild && aValue < zeroVal()) { - // A is an inside tile. Leave it alone and stop traversing this branch. - return STOP; - } - - ValueT bValue = zeroVal(); - typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue); - if (!bChild && bValue < zeroVal()) { - // B is an inside tile. Make A an inside tile and stop traversing this branch. - aIter.setValue(this->mAInside); - aIter.setValueOn(bIter.isValueOn()); - delete aChild; - return STOP; - } - - if (!aChild && aValue > zeroVal()) { - // A is an outside tile. If B has a child, transfer it to A, - // otherwise leave A alone. - if (bChild) { - bIter.setValue(this->mBOutside); - bIter.setValueOff(); - bChild->resetBackground(this->mBOutside, this->mAOutside); - aIter.setChild(bChild); // transfer child - delete aChild; - } - return STOP; - } - - // If A has a child and B is an outside tile, stop traversing this branch. - // Continue traversal only if A and B both have children. - return (aChild && bChild) ? 0 : STOP; - } - - /// Process leaf node values. - inline int operator()(ChildIterT& aIter, ChildIterT& bIter) - { - ValueT aValue, bValue; - aIter.probeValue(aValue); - bIter.probeValue(bValue); - if (aValue > bValue) { // a = min(a, b) - aIter.setValue(bValue); - aIter.setValueOn(bIter.isValueOn()); - } - return 0; - } -}; - - - -//////////////////////////////////////// - - -template -struct CsgIntersectVisitor: public CsgVisitorBase -{ - typedef TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT; - - enum { STOP = CsgVisitorBase::STOP }; - - CsgIntersectVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase(a, b) {} - - /// Don't process nodes that are at different tree levels. - template - inline int operator()(AIterT&, BIterT&) { return 0; } - - /// Process root and internal nodes. - template - inline int operator()(IterT& aIter, IterT& bIter) - { - ValueT aValue = zeroVal(); - typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue); - if (!aChild && !(aValue < zeroVal())) { - // A is an outside tile. Leave it alone and stop traversing this branch. - return STOP; - } - - ValueT bValue = zeroVal(); - typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue); - if (!bChild && !(bValue < zeroVal())) { - // B is an outside tile. Make A an outside tile and stop traversing this branch. - aIter.setValue(this->mAOutside); - aIter.setValueOn(bIter.isValueOn()); - delete aChild; - return STOP; - } - - if (!aChild && aValue < zeroVal()) { - // A is an inside tile. If B has a child, transfer it to A, - // otherwise leave A alone. - if (bChild) { - bIter.setValue(this->mBOutside); - bIter.setValueOff(); - bChild->resetBackground(this->mBOutside, this->mAOutside); - aIter.setChild(bChild); // transfer child - delete aChild; - } - return STOP; - } - - // If A has a child and B is an outside tile, stop traversing this branch. - // Continue traversal only if A and B both have children. - return (aChild && bChild) ? 0 : STOP; - } - - /// Process leaf node values. - inline int operator()(ChildIterT& aIter, ChildIterT& bIter) - { - ValueT aValue, bValue; - aIter.probeValue(aValue); - bIter.probeValue(bValue); - if (aValue < bValue) { // a = max(a, b) - aIter.setValue(bValue); - aIter.setValueOn(bIter.isValueOn()); - } - return 0; - } -}; - - -//////////////////////////////////////// - - -template -struct CsgDiffVisitor: public CsgVisitorBase -{ - typedef TreeType TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType::ChildAllIter ChildIterT; - - enum { STOP = CsgVisitorBase::STOP }; - - CsgDiffVisitor(const TreeT& a, const TreeT& b): CsgVisitorBase(a, b) {} - - /// Don't process nodes that are at different tree levels. - template - inline int operator()(AIterT&, BIterT&) { return 0; } - - /// Process root and internal nodes. - template - inline int operator()(IterT& aIter, IterT& bIter) - { - ValueT aValue = zeroVal(); - typename IterT::ChildNodeType* aChild = aIter.probeChild(aValue); - if (!aChild && !(aValue < zeroVal())) { - // A is an outside tile. Leave it alone and stop traversing this branch. - return STOP; - } - - ValueT bValue = zeroVal(); - typename IterT::ChildNodeType* bChild = bIter.probeChild(bValue); - if (!bChild && bValue < zeroVal()) { - // B is an inside tile. Make A an inside tile and stop traversing this branch. - aIter.setValue(this->mAOutside); - aIter.setValueOn(bIter.isValueOn()); - delete aChild; - return STOP; - } - - if (!aChild && aValue < zeroVal()) { - // A is an inside tile. If B has a child, transfer it to A, - // otherwise leave A alone. - if (bChild) { - bIter.setValue(this->mBOutside); - bIter.setValueOff(); - bChild->resetBackground(this->mBOutside, this->mAOutside); - aIter.setChild(bChild); // transfer child - bChild->negate(); - delete aChild; - } - return STOP; - } - - // If A has a child and B is an outside tile, stop traversing this branch. - // Continue traversal only if A and B both have children. - return (aChild && bChild) ? 0 : STOP; - } - - /// Process leaf node values. - inline int operator()(ChildIterT& aIter, ChildIterT& bIter) - { - ValueT aValue, bValue; - aIter.probeValue(aValue); - bIter.probeValue(bValue); - bValue = math::negative(bValue); - if (aValue < bValue) { // a = max(a, -b) - aIter.setValue(bValue); - aIter.setValueOn(bIter.isValueOn()); - } - return 0; - } -}; - - -//////////////////////////////////////// - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -csgUnion(GridOrTreeT& a, GridOrTreeT& b, bool prune) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); - CsgUnionVisitor visitor(aTree, bTree); - aTree.visit2(bTree, visitor); - if (prune) tools::pruneLevelSet(aTree); -} - -template -OPENVDB_STATIC_SPECIALIZATION inline void -csgIntersection(GridOrTreeT& a, GridOrTreeT& b, bool prune) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); - CsgIntersectVisitor visitor(aTree, bTree); - aTree.visit2(bTree, visitor); - if (prune) tools::pruneLevelSet(aTree); -} - -template -OPENVDB_STATIC_SPECIALIZATION inline void -csgDifference(GridOrTreeT& a, GridOrTreeT& b, bool prune) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - TreeT &aTree = Adapter::tree(a), &bTree = Adapter::tree(b); - CsgDiffVisitor visitor(aTree, bTree); - aTree.visit2(bTree, visitor); - if (prune) tools::pruneLevelSet(aTree); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_COMPOSITE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Dense.h b/openvdb_3_0_0_library/tools/Dense.h deleted file mode 100755 index 425dafc..0000000 --- a/openvdb_3_0_0_library/tools/Dense.h +++ /dev/null @@ -1,535 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Dense.h -/// -/// @brief This file defines a simple dense grid and efficient -/// converters to and from VDB grids. - -#ifndef OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include "Prune.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Populate a dense grid with the values of voxels from a sparse grid, -/// where the sparse grid intersects the dense grid. -/// @param sparse an OpenVDB grid or tree from which to copy values -/// @param dense the dense grid into which to copy values -/// @param serial if false, process voxels in parallel -template -void -copyToDense( - const GridOrTreeT& sparse, - DenseT& dense, - bool serial = false); - - -/// @brief Populate a sparse grid with the values of all of the voxels of a dense grid. -/// @param dense the dense grid from which to copy values -/// @param sparse an OpenVDB grid or tree into which to copy values -/// @param tolerance values in the dense grid that are within this tolerance of the sparse -/// grid's background value become inactive background voxels or tiles in the sparse grid -/// @param serial if false, process voxels in parallel -template -void -copyFromDense( - const DenseT& dense, - GridOrTreeT& sparse, - const typename GridOrTreeT::ValueType& tolerance, - bool serial = false); - - -//////////////////////////////////////// - -/// We currently support the following two 3D memory layouts for dense -/// volumes: XYZ, i.e. x is the fastest moving index, and ZYX, i.e. z -/// is the fastest moving index. The ZYX memory layout leads to nested -/// for-loops of the order x, y, z, which we find to be the most -/// intuitive. Hence, ZYX is the layout used throughout VDB. However, -/// other data structures, e.g. Houdini and Maya, employ the XYZ -/// layout. Clearly a dense volume with the ZYX layout converts more -/// efficiently to a VDB, but we support both for convenience. -enum MemoryLayout { LayoutXYZ, LayoutZYX }; - -/// @brief Base class for Dense which is defined below. -/// @note The constructor of this class is protected to prevent direct -/// instantiation. -template class DenseBase; - -/// @brief Partial template specialization of DenseBase. -/// @note ZYX is the memory-layout in VDB. It leads to nested -/// for-loops of the order x, y, z which we find to be the most intuitive. -template -class DenseBase -{ -public: - /// @brief Return the linear offset into this grid's value array given by - /// unsigned coordinates (i, j, k), i.e., coordinates relative to - /// the origin of this grid's bounding box. - inline size_t coordToOffset(size_t i, size_t j, size_t k) const { return i*mX + j*mY + k; } - - /// @brief Return the stride of the array in the x direction ( = dimY*dimZ). - /// @note This method is required by both CopyToDense and CopyFromDense. - inline size_t xStride() const { return mX; } - - /// @brief Return the stride of the array in the y direction ( = dimZ). - /// @note This method is required by both CopyToDense and CopyFromDense. - inline size_t yStride() const { return mY; } - - /// @brief Return the stride of the array in the z direction ( = 1). - /// @note This method is required by both CopyToDense and CopyFromDense. - static size_t zStride() { return 1; } - -protected: - /// Protected constructor so as to prevent direct instantiation - DenseBase(const CoordBBox& bbox) : mBBox(bbox), mY(bbox.dim()[2]), mX(mY*bbox.dim()[1]) {} - - const CoordBBox mBBox;//signed coordinates of the domain represented by the grid - const size_t mY, mX;//strides in the y and x direction -};// end of DenseBase - -/// @brief Partial template specialization of DenseBase. -/// @note This is the memory-layout emplayed in Houdini and Maya. It leads -/// to nested for-loops of the order z, y, x. -template -class DenseBase -{ -public: - /// @brief Return the linear offset into this grid's value array given by - /// unsigned coordinates (i, j, k), i.e., coordinates relative to - /// the origin of this grid's bounding box. - inline size_t coordToOffset(size_t i, size_t j, size_t k) const { return i + j*mY + k*mZ; } - - /// @brief Return the stride of the array in the x direction ( = 1). - /// @note This method is required by both CopyToDense and CopyFromDense. - static size_t xStride() { return 1; } - - /// @brief Return the stride of the array in the y direction ( = dimX). - /// @note This method is required by both CopyToDense and CopyFromDense. - inline size_t yStride() const { return mY; } - - /// @brief Return the stride of the array in the y direction ( = dimX*dimY). - /// @note This method is required by both CopyToDense and CopyFromDense. - inline size_t zStride() const { return mZ; } - -protected: - /// Protected constructor so as to prevent direct instantiation - DenseBase(const CoordBBox& bbox) : mBBox(bbox), mY(bbox.dim()[0]), mZ(mY*bbox.dim()[1]) {} - - const CoordBBox mBBox;//signed coordinates of the domain represented by the grid - const size_t mY, mZ;//strides in the y and z direction -};// end of DenseBase - -/// @brief Dense is a simple dense grid API used by the CopyToDense and -/// CopyFromDense classes defined below. -/// @details Use the Dense class to efficiently produce a dense in-memory -/// representation of an OpenVDB grid. However, be aware that a dense grid -/// could have a memory footprint that is orders of magnitude larger than -/// the sparse grid from which it originates. -/// -/// @note This class can be used as a simple wrapper for existing dense grid -/// classes if they provide access to the raw data array. -/// @note This implementation allows for the 3D memory layout to be -/// defined by the MemoryLayout template parameter (see above for definition). -/// The default memory layout is ZYX since that's the layout used by OpenVDB grids. -template -class Dense : public DenseBase -{ -public: - typedef ValueT ValueType; - typedef DenseBase BaseT; - - /// @brief Construct a dense grid with a given range of coordinates. - /// - /// @param bbox the bounding box of the (signed) coordinate range of this grid - /// @throw ValueError if the bounding box is empty. - /// @note The min and max coordinates of the bounding box are inclusive. - Dense(const CoordBBox& bbox) : BaseT(bbox) { this->init(); } - - /// @brief Construct a dense grid with a given range of coordinates and initial value - /// - /// @param bbox the bounding box of the (signed) coordinate range of this grid - /// @param value the initial value of the grid. - /// @throw ValueError if the bounding box is empty. - /// @note The min and max coordinates of the bounding box are inclusive. - Dense(const CoordBBox& bbox, const ValueT& value) : BaseT(bbox) - { - this->init(); - this->fill(value); - } - - /// @brief Construct a dense grid that wraps an external array. - /// - /// @param bbox the bounding box of the (signed) coordinate range of this grid - /// @param data a raw C-style array whose size is commensurate with - /// the coordinate domain of @a bbox - /// - /// @note The data array is assumed to have a stride of one in the @e z direction. - /// @throw ValueError if the bounding box is empty. - /// @note The min and max coordinates of the bounding box are inclusive. - Dense(const CoordBBox& bbox, ValueT* data) : BaseT(bbox), mData(data) - { - if (BaseT::mBBox.empty()) { - OPENVDB_THROW(ValueError, "can't construct a dense grid with an empty bounding box"); - } - } - - /// @brief Construct a dense grid with a given origin and dimensions. - /// - /// @param dim the desired dimensions of the grid - /// @param min the signed coordinates of the first voxel in the dense grid - /// @throw ValueError if any of the dimensions are zero. - /// @note The @a min coordinate is inclusive, and the max coordinate will be - /// @a min + @a dim - 1. - Dense(const Coord& dim, const Coord& min = Coord(0)) - : BaseT(CoordBBox(min, min+dim.offsetBy(-1))) - { - this->init(); - } - - /// @brief Return the memory layout for this grid (see above for definitions). - static MemoryLayout memoryLayout() { return Layout; } - - /// @brief Return a raw pointer to this grid's value array. - /// @note This method is required by CopyToDense. - inline ValueT* data() { return mData; } - - /// @brief Return a raw pointer to this grid's value array. - /// @note This method is required by CopyFromDense. - inline const ValueT* data() const { return mData; } - - /// @brief Return the bounding box of the signed index domain of this grid. - /// @note This method is required by both CopyToDense and CopyFromDense. - inline const CoordBBox& bbox() const { return BaseT::mBBox; } - - /// @brief Return the number of voxels contained in this grid. - inline Index64 valueCount() const { return BaseT::mBBox.volume(); } - - /// @brief Set the value of the voxel at the given array offset. - inline void setValue(size_t offset, const ValueT& value) { mData[offset] = value; } - - /// @brief Return the value of the voxel at the given array offset. - const ValueT& getValue(size_t offset) const { return mData[offset]; } - - /// @brief Set the value of the voxel at unsigned index coordinates (i, j, k). - /// @note This is somewhat slower than using an array offset. - inline void setValue(size_t i, size_t j, size_t k, const ValueT& value) - { - mData[BaseT::coordToOffset(i,j,k)] = value; - } - - /// @brief Return the value of the voxel at unsigned index coordinates (i, j, k). - /// @note This is somewhat slower than using an array offset. - inline const ValueT& getValue(size_t i, size_t j, size_t k) const - { - return mData[BaseT::coordToOffset(i,j,k)]; - } - - /// @brief Set the value of the voxel at the given signed coordinates. - /// @note This is slower than using either an array offset or unsigned index coordinates. - inline void setValue(const Coord& xyz, const ValueT& value) - { - mData[this->coordToOffset(xyz)] = value; - } - - /// @brief Return the value of the voxel at the given signed coordinates. - /// @note This is slower than using either an array offset or unsigned index coordinates. - inline const ValueT& getValue(const Coord& xyz) const - { - return mData[this->coordToOffset(xyz)]; - } - - /// @brief Fill this grid with a constant value. - inline void fill(const ValueT& value) - { - size_t size = this->valueCount(); - ValueT* a = mData; - while(size--) *a++ = value; - } - - /// @brief Return the linear offset into this grid's value array given by - /// the specified signed coordinates, i.e., coordinates in the space of - /// this grid's bounding box. - /// - /// @note This method reflects the fact that we assume the same - /// layout of values as an OpenVDB grid, i.e., the fastest coordinate is @e z. - inline size_t coordToOffset(Coord xyz) const - { - assert(BaseT::mBBox.isInside(xyz)); - return BaseT::coordToOffset(size_t(xyz[0]-BaseT::mBBox.min()[0]), - size_t(xyz[1]-BaseT::mBBox.min()[1]), - size_t(xyz[2]-BaseT::mBBox.min()[2])); - } - - /// @brief Return the memory footprint of this Dense grid in bytes. - inline Index64 memUsage() const - { - return sizeof(*this) + BaseT::mBBox.volume() * sizeof(ValueType); - } - -private: - - /// @brief Private method to initialize the dense value array. - void init() - { - if (BaseT::mBBox.empty()) { - OPENVDB_THROW(ValueError, "can't construct a dense grid with an empty bounding box"); - } - mArray.reset(new ValueT[BaseT::mBBox.volume()]); - mData = mArray.get(); - } - - boost::scoped_array mArray; - ValueT* mData;//raw c-style pointer to values -};// end of Dense - -//////////////////////////////////////// - - -/// @brief Copy an OpenVDB tree into an existing dense grid. -/// -/// @note Only voxels that intersect the dense grid's bounding box are copied -/// from the OpenVDB tree. But both active and inactive voxels are copied, -/// so all existing values in the dense grid are overwritten, regardless of -/// the OpenVDB tree's tolopogy. -template > -class CopyToDense -{ -public: - typedef _DenseT DenseT; - typedef _TreeT TreeT; - typedef typename TreeT::ValueType ValueT; - - CopyToDense(const TreeT& tree, DenseT& dense) - : mRoot(&(tree.root())), mDense(&dense) {} - - void copy(bool serial = false) const - { - if (serial) { - mRoot->copyToDense(mDense->bbox(), *mDense); - } else { - tbb::parallel_for(mDense->bbox(), *this); - } - } - - /// @brief Public method called by tbb::parallel_for - void operator()(const CoordBBox& bbox) const - { - mRoot->copyToDense(bbox, *mDense); - } - -private: - const typename TreeT::RootNodeType* mRoot; - DenseT* mDense; -};// CopyToDense - - -// Convenient wrapper function for the CopyToDense class -template -void -copyToDense(const GridOrTreeT& sparse, DenseT& dense, bool serial) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - - CopyToDense op(Adapter::constTree(sparse), dense); - op.copy(serial); -} - - -//////////////////////////////////////// - - -/// @brief Copy the values from a dense grid into an OpenVDB tree. -/// -/// @details Values in the dense grid that are within a tolerance of -/// the background value are truncated to inactive background voxels or tiles. -/// This allows the tree to form a sparse representation of the dense grid. -/// -/// @note Since this class allocates leaf nodes concurrently it is recommended -/// to use a scalable implementation of @c new like the one provided by TBB, -/// rather than the mutex-protected standard library @c new. -template > -class CopyFromDense -{ -public: - typedef _DenseT DenseT; - typedef _TreeT TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType LeafT; - typedef tree::ValueAccessor AccessorT; - - CopyFromDense(const DenseT& dense, TreeT& tree, const ValueT& tolerance) - : mDense(&dense), - mTree(&tree), - mBlocks(NULL), - mTolerance(tolerance), - mAccessor(tree.empty() ? NULL : new AccessorT(tree)) - { - } - CopyFromDense(const CopyFromDense& other) - : mDense(other.mDense), - mTree(other.mTree), - mBlocks(other.mBlocks), - mTolerance(other.mTolerance), - mAccessor(other.mAccessor.get() == NULL ? NULL : new AccessorT(*mTree)) - { - } - - /// @brief Copy values from the dense grid to the sparse tree. - void copy(bool serial = false) - { - mBlocks = new std::vector(); - const CoordBBox& bbox = mDense->bbox(); - // Pre-process: Construct a list of blocks alligned with (potential) leaf nodes - for (CoordBBox sub=bbox; sub.min()[0] <= bbox.max()[0]; sub.min()[0] = sub.max()[0] + 1) { - for (sub.min()[1] = bbox.min()[1]; sub.min()[1] <= bbox.max()[1]; - sub.min()[1] = sub.max()[1] + 1) - { - for (sub.min()[2] = bbox.min()[2]; sub.min()[2] <= bbox.max()[2]; - sub.min()[2] = sub.max()[2] + 1) - { - sub.max() = Coord::minComponent(bbox.max(), - (sub.min()&(~(LeafT::DIM-1u))).offsetBy(LeafT::DIM-1u)); - mBlocks->push_back(Block(sub)); - } - } - } - - // Multi-threaded process: Convert dense grid into leaf nodes and tiles - if (serial) { - (*this)(tbb::blocked_range(0, mBlocks->size())); - } else { - tbb::parallel_for(tbb::blocked_range(0, mBlocks->size()), *this); - } - - // Post-process: Insert leaf nodes and tiles into the tree, and prune the tiles only! - tree::ValueAccessor acc(*mTree); - for (size_t m=0, size = mBlocks->size(); mroot().pruneTiles(mTolerance); - } - - /// @brief Public method called by tbb::parallel_for - /// @warning Never call this method directly! - void operator()(const tbb::blocked_range &r) const - { - assert(mBlocks); - LeafT* leaf = new LeafT(); - - for (size_t m=r.begin(), n=0, end = r.end(); m != end; ++m, ++n) { - - Block& block = (*mBlocks)[m]; - const CoordBBox &bbox = block.bbox; - - if (mAccessor.get() == NULL) {//i.e. empty target tree - leaf->fill(mTree->background(), false); - } else {//account for existing leaf nodes in the target tree - if (const LeafT* target = mAccessor->probeConstLeaf(bbox.min())) { - (*leaf) = (*target); - } else { - ValueT value = zeroVal(); - bool state = mAccessor->probeValue(bbox.min(), value); - leaf->fill(value, state); - } - } - - leaf->copyFromDense(bbox, *mDense, mTree->background(), mTolerance); - - if (!leaf->isConstant(block.tile.first, block.tile.second, mTolerance)) { - leaf->setOrigin(bbox.min() & (~(LeafT::DIM - 1))); - block.leaf = leaf; - leaf = new LeafT(); - } - }// loop over blocks - - delete leaf; - } - -private: - struct Block { - CoordBBox bbox; - LeafT* leaf; - std::pair tile; - Block(const CoordBBox& b) : bbox(b), leaf(NULL) {} - }; - - const DenseT* mDense; - TreeT* mTree; - std::vector* mBlocks; - ValueT mTolerance; - boost::scoped_ptr mAccessor; -};// CopyFromDense - - -// Convenient wrapper function for the CopyFromDense class -template -void -copyFromDense(const DenseT& dense, GridOrTreeT& sparse, - const typename GridOrTreeT::ValueType& tolerance, bool serial) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeT; - - CopyFromDense op(dense, Adapter::tree(sparse), tolerance); - op.copy(serial); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_DENSE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/DenseSparseTools.h b/openvdb_3_0_0_library/tools/DenseSparseTools.h deleted file mode 100755 index bebe653..0000000 --- a/openvdb_3_0_0_library/tools/DenseSparseTools.h +++ /dev/null @@ -1,1259 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "Dense.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Selectively extract and transform data from a dense grid, producing a -/// sparse tree with leaf nodes only (e.g. create a tree from the square -/// of values greater than a cutoff.) -/// @param dense A dense grid that acts as a data source -/// @param functor A functor that selects and transforms data for output -/// @param background The background value of the resulting sparse grid -/// @param threaded Option to use threaded or serial code path -/// @return @c Ptr to tree with the valuetype and configuration defined -/// by typedefs in the @c functor. -/// @note To achieve optimal sparsity consider calling the prune() -/// method on the result. -/// @note To simply copy the all the data from a Dense grid to a -/// OpenVDB Grid, use tools::copyFromDense() for better performance. -/// -/// The type of the sparse tree is determined by the specified OtpType -/// functor by means of the typedef OptType::ResultTreeType -/// -/// The OptType function is responsible for the the transformation of -/// dense grid data to sparse grid data on a per-voxel basis. -/// -/// Only leaf nodes with active values will be added to the sparse grid. -/// -/// The OpType must struct that defines a the minimal form -/// @code -/// struct ExampleOp -/// { -/// typedef DesiredTreeType ResultTreeType; -/// -/// template -/// void OpType::operator() (const DenseValueType a, const IndexOrCoord& ijk, -/// ResultTreeType::LeafNodeType* leaf); -/// }; -/// @endcode -/// -/// For example, to generate a tree with valuesOn -/// at locations greater than a given maskvalue -/// @code -/// template -/// class Rule -/// { -/// public: -/// // Standard tree type (e.g. BoolTree or FloatTree in openvdb.h) -/// typedef typename openvdb::tree::Tree4::Type ResultTreeType; -/// -/// typedef typename ResultTreeType::LeafNodeType ResultLeafNodeType; -/// typedef typename ResultTreeType::ValueType ResultValueType; -/// -/// typedef float DenseValueType; -/// -/// typedef vdbmath::Coord::ValueType Index; -/// -/// Rule(const DenseValueType& value): mMaskValue(value){}; -/// -/// template -/// void operator()(const DenseValueType& a, const IndexOrCoord& offset, -/// ResultLeafNodeType* leaf) const -/// { -/// if (a > mMaskValue) { -/// leaf->setValueOn(offset, a); -/// } -/// } -/// -/// private: -/// const DenseValueType mMaskValue; -/// }; -/// @endcode -template -typename OpType::ResultTreeType::Ptr -extractSparseTree(const DenseType& dense, const OpType& functor, - const typename OpType::ResultValueType& background, - bool threaded = true); - -/// This struct that aids template resoluion of a new tree type -/// has the same configuration at TreeType, but the ValueType from -/// DenseType. -template struct DSConverter { - typedef typename DenseType::ValueType ValueType; - - typedef typename TreeType::template ValueConverter::Type Type; -}; - - -/// @brief Copy data from the intersection of a sparse tree and a dense input grid. -/// The resulting tree has the same configuration as the sparse tree, but holds -/// the data type specified by the dense input. -/// @param dense A dense grid that acts as a data source -/// @param mask The active voxels and tiles intersected with dense define iteration mask -/// @param background The background value of the resulting sparse grid -/// @param threaded Option to use threaded or serial code path -/// @return @c Ptr to tree with the same configuration as @c mask but of value type -/// defined by @c dense. -template -typename DSConverter::Type::Ptr -extractSparseTreeWithMask(const DenseType& dense, - const MaskTreeType& mask, - const typename DenseType::ValueType& background, - bool threaded = true); - - -/// Apply a point-wise functor to the intersection of a dense grid and a given bounding box -/// @param dense A dense grid to be transformed -/// @param bbox Index space bounding box, define region where the transformation is applied -/// @param op A functor that acts on the dense grid value type -/// @param parallel Used to select multithreaded or single threaded -/// Minimally, the @c op class has to support a @c operator() method, -/// @code -/// // Square values in a grid -/// struct Op -/// { -/// ValueT operator()(const ValueT& in) const -/// { -/// // do work -/// ValueT result = in * in; -/// -/// return result; -/// } -/// }; -/// @endcode -/// NB: only Dense grids with memory layout zxy are supported -template -void transformDense(Dense& dense, - const openvdb::CoordBBox& bbox, const OpType& op, bool parallel=true); - -/// We currrently support the following operations when compositing sparse -/// data into a dense grid. -enum DSCompositeOp { - DS_OVER, DS_ADD, DS_SUB, DS_MIN, DS_MAX, DS_MULT, DS_SET -}; - -/// @brief Composite data from a sparse tree into a dense array of the same value type. -/// @param dense Dense grid to be altered by the operation -/// @param source Sparse data to composite into @c dense -/// @param alpha Sparse Alpha mask used in compositing operations. -/// @param beta Constant multiplier on src -/// @param strength Constant multiplier on alpha -/// @param threaded Enable threading for this operation. -template -void compositeToDense(Dense& dense, - const TreeT& source, - const TreeT& alpha, - const typename TreeT::ValueType beta, - const typename TreeT::ValueType strength, - bool threaded = true); - - -/// @brief Functor-based class used to extract data that satisfies some -/// criteria defined by the embedded @c OpType functor. The @c extractSparseTree -/// function wraps this class. -template -class SparseExtractor -{ - -public: - - typedef openvdb::math::Coord::ValueType Index; - - typedef typename DenseType::ValueType DenseValueType; - typedef typename OpType::ResultTreeType ResultTreeType; - typedef typename ResultTreeType::ValueType ResultValueType; - typedef typename ResultTreeType::LeafNodeType ResultLeafNodeType; - typedef typename ResultTreeType::template ValueConverter::Type BoolTree; - - typedef tbb::blocked_range3d Range3d; - - -private: - - const DenseType& mDense; - const OpType& mFunctor; - const ResultValueType mBackground; - const openvdb::math::CoordBBox mBBox; - const Index mWidth; - typename ResultTreeType::Ptr mMask; - openvdb::math::Coord mMin; - - -public: - - SparseExtractor(const DenseType& dense, const OpType& functor, - const ResultValueType background) : - mDense(dense), mFunctor(functor), - mBackground(background), - mBBox(dense.bbox()), - mWidth(ResultLeafNodeType::DIM), - mMask( new ResultTreeType(mBackground)) - {} - - - SparseExtractor(const DenseType& dense, - const openvdb::math::CoordBBox& bbox, - const OpType& functor, - const ResultValueType background) : - mDense(dense), mFunctor(functor), - mBackground(background), - mBBox(bbox), - mWidth(ResultLeafNodeType::DIM), - mMask( new ResultTreeType(mBackground)) - { - // mBBox must be inside the coordinate rage of the dense grid - if (!dense.bbox().isInside(mBBox)) { - OPENVDB_THROW(ValueError, "Data extraction window out of bound"); - } - } - - - SparseExtractor(SparseExtractor& other, tbb::split): - mDense(other.mDense), mFunctor(other.mFunctor), - mBackground(other.mBackground), mBBox(other.mBBox), - mWidth(other.mWidth), - mMask(new ResultTreeType(mBackground)), - mMin(other.mMin) - {} - - typename ResultTreeType::Ptr extract(bool threaded = true) { - - - // Construct 3D range of leaf nodes that - // intersect mBBox. - - // Snap the bbox to nearest leaf nodes min and max - - openvdb::math::Coord padded_min = mBBox.min(); - openvdb::math::Coord padded_max = mBBox.max(); - - - padded_min &= ~(mWidth - 1); - padded_max &= ~(mWidth - 1); - - padded_max[0] += mWidth - 1; - padded_max[1] += mWidth - 1; - padded_max[2] += mWidth - 1; - - - // number of leaf nodes in each direction - // division by leaf width, e.g. 8 in most cases - - const Index xleafCount = ( padded_max.x() - padded_min.x() + 1 ) / mWidth; - const Index yleafCount = ( padded_max.y() - padded_min.y() + 1 ) / mWidth; - const Index zleafCount = ( padded_max.z() - padded_min.z() + 1 ) / mWidth; - - mMin = padded_min; - - - Range3d leafRange(0, xleafCount, 1, - 0, yleafCount, 1, - 0, zleafCount, 1); - - - // Iterate over the leafnodes applying *this as a functor. - if (threaded) { - tbb::parallel_reduce(leafRange, *this); - } else { - (*this)(leafRange); - } - - return mMask; - } - - - void operator()(const Range3d& range) { - - ResultLeafNodeType* leaf = NULL; - - // Unpack the range3d item. - const Index imin = range.pages().begin(); - const Index imax = range.pages().end(); - - const Index jmin = range.rows().begin(); - const Index jmax = range.rows().end(); - - const Index kmin = range.cols().begin(); - const Index kmax = range.cols().end(); - - - // loop over all the canidate leafs. Adding only those with 'true' values - // to the tree - - for (Index i = imin; i < imax; ++i) { - for (Index j = jmin; j < jmax; ++j) { - for (Index k = kmin; k < kmax; ++k) { - - // Calculate the origin of canidate leaf - const openvdb::math::Coord origin = - mMin + openvdb::math::Coord(mWidth * i, - mWidth * j, - mWidth * k ); - - if (leaf == NULL) { - leaf = new ResultLeafNodeType(origin, mBackground); - } else { - leaf->setOrigin(origin); - leaf->fill(mBackground); - leaf->setValuesOff(); - } - - // The bouding box for this leaf - - openvdb::math::CoordBBox localBBox = leaf->getNodeBoundingBox(); - - // Shrink to the intersection with mBBox (i.e. the dense - // volume) - - localBBox.intersect(mBBox); - - // Early out for non-intersecting leafs - - if (localBBox.empty()) continue; - - - const openvdb::math::Coord start = localBBox.getStart(); - const openvdb::math::Coord end = localBBox.getEnd(); - - // Order the looping to respect the memory layout in - // the Dense source - - if (mDense.memoryLayout() == openvdb::tools::LayoutZYX) { - - openvdb::math::Coord ijk; - Index offset; - const DenseValueType* dp; - for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) { - for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) { - for (ijk[2] = start.z(), - offset = ResultLeafNodeType::coordToOffset(ijk), - dp = &mDense.getValue(ijk); - ijk[2] < end.z(); ++ijk[2], ++offset, ++dp) { - - mFunctor(*dp, offset, leaf); - } - } - } - - } else { - - openvdb::math::Coord ijk; - const DenseValueType* dp; - for (ijk[2] = start.z(); ijk[2] < end.z(); ++ijk[2]) { - for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1]) { - for (ijk[0] = start.x(), - dp = &mDense.getValue(ijk); - ijk[0] < end.x(); ++ijk[0], ++dp) { - - mFunctor(*dp, ijk, leaf); - - } - } - } - } - - // Only add non-empty leafs (empty is defined as all inactive) - - if (!leaf->isEmpty()) { - mMask->addLeaf(*leaf); - leaf = NULL; - } - - } - } - } - - // Clean up an unused leaf. - - if (leaf != NULL) delete leaf; - }; - - void join(SparseExtractor& rhs) { - mMask->merge(*rhs.mMask); - } -}; // class SparseExtractor - - -template -typename OpType::ResultTreeType::Ptr -extractSparseTree(const DenseType& dense, const OpType& functor, - const typename OpType::ResultValueType& background, - bool threaded) -{ - - // Construct the mask using a parallel reduce patern. - // Each thread computes disjoint mask-trees. The join merges - // into a single tree. - - SparseExtractor extractor(dense, functor, background); - - return extractor.extract(threaded); -} - - -/// @brief Functor-based class used to extract data from a dense grid, at -/// the index-space intersection with a suppiled maks in the form of a sparse tree. -/// The @c extractSparseTreeWithMask function wraps this class. -template -class SparseMaskedExtractor -{ -public: - - typedef typename DSConverter::Type _ResultTreeType; - typedef _ResultTreeType ResultTreeType; - typedef typename ResultTreeType::LeafNodeType ResultLeafNodeType; - typedef typename ResultTreeType::ValueType ResultValueType; - typedef ResultValueType DenseValueType; - - typedef typename ResultTreeType::template ValueConverter::Type BoolTree; - typedef typename BoolTree::LeafCIter BoolLeafCIter; - typedef std::vector BoolLeafVec; - - - SparseMaskedExtractor(const DenseType& dense, - const ResultValueType& background, - const BoolLeafVec& leafVec - ): - mDense(dense), mBackground(background), mBBox(dense.bbox()), - mLeafVec(leafVec), - mResult(new ResultTreeType(mBackground)) - {} - - - - SparseMaskedExtractor(const SparseMaskedExtractor& other, tbb::split): - mDense(other.mDense), mBackground(other.mBackground), mBBox(other.mBBox), - mLeafVec(other.mLeafVec), mResult( new ResultTreeType(mBackground)) - {} - - typename ResultTreeType::Ptr extract(bool threaded = true) { - - tbb::blocked_range range(0, mLeafVec.size()); - - if (threaded) { - tbb::parallel_reduce(range, *this); - } else { - (*this)(range); - } - - return mResult; - } - - - // Used in looping over leaf nodes in the masked grid - // and using the active mask to select data to - void operator()(const tbb::blocked_range& range) { - - ResultLeafNodeType* leaf = NULL; - - - // loop over all the canidate leafs. Adding only those with 'true' values - // to the tree - - for (size_t idx = range.begin(); idx < range.end(); ++ idx) { - - const typename BoolTree::LeafNodeType* boolLeaf = mLeafVec[idx]; - - // The bouding box for this leaf - - openvdb::math::CoordBBox localBBox = boolLeaf->getNodeBoundingBox(); - - // Shrink to the intersection with the dense volume - - localBBox.intersect(mBBox); - - // Early out if there was no intersection - - if (localBBox.empty()) continue; - - // Reset or allocate the target leaf - - if (leaf == NULL) { - leaf = new ResultLeafNodeType(boolLeaf->origin(), mBackground); - } else { - leaf->setOrigin(boolLeaf->origin()); - leaf->fill(mBackground); - leaf->setValuesOff(); - } - - - // Iterate over the intersecting bounding box - // copying active values to the result tree - - const openvdb::math::Coord start = localBBox.getStart(); - const openvdb::math::Coord end = localBBox.getEnd(); - - - openvdb::math::Coord ijk; - - if (mDense.memoryLayout() == openvdb::tools::LayoutZYX - && boolLeaf->isDense()) { - - Index offset; - const DenseValueType* src; - for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) { - for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) { - for (ijk[2] = start.z(), - offset = ResultLeafNodeType::coordToOffset(ijk), - src = &mDense.getValue(ijk); - ijk[2] < end.z(); ++ijk[2], ++offset, ++src) { - - // copy into leaf - leaf->setValueOn(offset, *src); - } - - } - } - - } else { - - Index offset; - for (ijk[0] = start.x(); ijk[0] < end.x(); ++ijk[0] ) { - for (ijk[1] = start.y(); ijk[1] < end.y(); ++ijk[1] ) { - for (ijk[2] = start.z(), - offset = ResultLeafNodeType::coordToOffset(ijk); - ijk[2] < end.z(); ++ijk[2], ++offset) { - - if (boolLeaf->isValueOn(offset)) { - const ResultValueType denseValue = mDense.getValue(ijk); - leaf->setValueOn(offset, denseValue); - } - } - } - } - } - // Only add non-empty leafs (empty is defined as all inactive) - - if (!leaf->isEmpty()) { - mResult->addLeaf(*leaf); - leaf = NULL; - } - } - - // Clean up an unused leaf. - - if (leaf != NULL) delete leaf; - }; - - void join(SparseMaskedExtractor& rhs) { - mResult->merge(*rhs.mResult); - } - - -private: - const DenseType& mDense; - const ResultValueType mBackground; - const openvdb::math::CoordBBox& mBBox; - const BoolLeafVec& mLeafVec; - - typename ResultTreeType::Ptr mResult; - -}; // class SparseMaskedExtractor - - -/// @brief a simple utility class used by @c extractSparseTreeWithMask -template -struct ExtractAll -{ - typedef _ResultTreeType ResultTreeType; - typedef typename ResultTreeType::LeafNodeType ResultLeafNodeType; - - template inline void - operator()(const DenseValueType& a, const CoordOrIndex& offset, ResultLeafNodeType* leaf) const - { - leaf->setValueOn(offset, a); - } -}; - - -template -typename DSConverter::Type::Ptr -extractSparseTreeWithMask(const DenseType& dense, - const MaskTreeType& mask, - const typename DenseType::ValueType& background, - bool threaded) -{ - typedef SparseMaskedExtractor LeafExtractor; - typedef typename LeafExtractor::DenseValueType DenseValueType; - typedef typename LeafExtractor::ResultTreeType ResultTreeType; - typedef typename LeafExtractor::BoolLeafVec BoolLeafVec; - typedef typename LeafExtractor::BoolTree BoolTree; - typedef typename LeafExtractor::BoolLeafCIter BoolLeafCIter; - typedef ExtractAll ExtractionRule; - - // Use Bool tree to hold the topology - - BoolTree boolTree(mask, false, TopologyCopy()); - - // Construct an array of pointers to the mask leafs. - - const size_t leafCount = boolTree.leafCount(); - BoolLeafVec leafarray(leafCount); - BoolLeafCIter leafiter = boolTree.cbeginLeaf(); - for (size_t n = 0; n != leafCount; ++n, ++leafiter) { - leafarray[n] = leafiter.getLeaf(); - } - - - // Extract the data that is masked leaf nodes in the mask. - - LeafExtractor leafextractor(dense, background, leafarray); - typename ResultTreeType::Ptr resultTree = leafextractor.extract(threaded); - - - // Extract data that is masked by tiles in the mask. - - - // Loop over the mask tiles, extracting the data into new trees. - // These trees will be leaf-orthogonal to the leafTree (i.e. no leaf - // nodes will overlap). Merge these trees into the result. - - typename MaskTreeType::ValueOnCIter tileIter(mask); - tileIter.setMaxDepth(MaskTreeType::ValueOnCIter::LEAF_DEPTH - 1); - - // Return the leaf tree if the mask had no tiles - - if (!tileIter) return resultTree; - - ExtractionRule allrule; - - // Loop over the tiles in series, but the actual data extraction - // is in parallel. - - CoordBBox bbox; - for ( ; tileIter; ++tileIter) { - - // Find the intersection of the tile with the dense grid. - - tileIter.getBoundingBox(bbox); - bbox.intersect(dense.bbox()); - - if (bbox.empty()) continue; - - SparseExtractor copyData(dense, bbox, allrule, background); - typename ResultTreeType::Ptr fromTileTree = copyData.extract(threaded); - resultTree->merge(*fromTileTree); - } - - return resultTree; -} - - -/// @brief Class that applies a functor to the index space intersection -/// of a prescribed bounding box and the dense grid. -/// NB: This class only supports DenseGrids with ZYX memory layout. -template -class DenseTransformer -{ -public: - - typedef _ValueT ValueT; - typedef Dense DenseT; - typedef openvdb::math::Coord::ValueType IntType; - typedef tbb::blocked_range2d RangeType; - - -private: - - DenseT& mDense; - const OpType& mOp; - openvdb::math::CoordBBox mBBox; - -public: - DenseTransformer(DenseT& dense, - const openvdb::math::CoordBBox& bbox, - const OpType& functor): - mDense(dense), mOp(functor), mBBox(dense.bbox()) - { - // The interation space is the intersection of the - // input bbox and the index-space covered by the dense grid - mBBox.intersect(bbox); - } - - DenseTransformer(const DenseTransformer& other) : - mDense(other.mDense), mOp(other.mOp), mBBox(other.mBBox) {} - - void apply(bool threaded = true) { - - // Early out if the interation space is empty - - if (mBBox.empty()) return; - - - const openvdb::math::Coord start = mBBox.getStart(); - const openvdb::math::Coord end = mBBox.getEnd(); - - // The interation range only the slower two directions. - const RangeType range(start.x(), end.x(), 1, - start.y(), end.y(), 1); - - if (threaded) { - tbb::parallel_for(range, *this); - } else { - (*this)(range); - } - } - - void operator()(const RangeType& range) const { - - // The stride in the z-direction. - // Note: the bbox is [inclusive, inclusive] - - const size_t zlength = size_t(mBBox.max().z() - mBBox.min().z() + 1); - - const IntType imin = range.rows().begin(); - const IntType imax = range.rows().end(); - const IntType jmin = range.cols().begin(); - const IntType jmax = range.cols().end(); - - - openvdb::math::Coord xyz(imin, jmin, mBBox.min().z()); - for (xyz[0] = imin; xyz[0] != imax; ++xyz[0]) { - for (xyz[1] = jmin; xyz[1] != jmax; ++xyz[1]) { - - mOp.transform(mDense, xyz, zlength); - } - } - } -}; // class DenseTransformer - - -/// @brief a wrapper struct used to avoid unnecessary computation of -/// memory access from @c Coord when all offsets are guaranteed to be -/// within the dense grid. -template -struct ContiguousOp -{ - ContiguousOp(const PointWiseOp& op) : mOp(op){}; - - typedef Dense DenseT; - inline void transform(DenseT& dense, openvdb::math::Coord& ijk, size_t size) const - { - ValueT* dp = const_cast(&dense.getValue(ijk)); - - for (size_t offset = 0; offset < size; ++offset) { - dp[offset] = mOp(dp[offset]); - } - } - - const PointWiseOp mOp; -}; - - -/// Apply a point-wise functor to the intersection of a dense grid and a given bounding box -template -void -transformDense(Dense& dense, - const openvdb::CoordBBox& bbox, - const PointwiseOpT& functor, bool parallel) -{ - typedef ContiguousOp OpT; - - // Convert the Op so it operates on an contiguous line in memory - - OpT op(functor); - - // Apply to the index space intersection in the dense grid - DenseTransformer transformer(dense, bbox, op); - transformer.apply(parallel); -} - - -template -class SparseToDenseCompositor -{ - -public: - typedef _TreeT TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::LeafNodeType LeafT; - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef Dense DenseT; - typedef openvdb::math::Coord::ValueType Index; - typedef tbb::blocked_range3d Range3d; - - SparseToDenseCompositor(DenseT& dense, const TreeT& source, const TreeT& alpha, - const ValueT beta, const ValueT strength) : - mDense(dense), mSource(source), mAlpha(alpha), mBeta(beta), mStrength(strength) - {} - - SparseToDenseCompositor(const SparseToDenseCompositor& other): - mDense(other.mDense), mSource(other.mSource), mAlpha(other.mAlpha), - mBeta(other.mBeta), mStrength(other.mStrength) {}; - - - - void sparseComposite(bool threaded) { - - const ValueT beta = mBeta; - const ValueT strenght = mStrength; - - // construct a tree that defines the iteration space - - BoolTreeT boolTree(mSource, false /*background*/, openvdb::TopologyCopy()); - boolTree.topologyUnion(mAlpha); - - // Coposite regions that are represented by leafnodes in either mAlpha or mSource - // Parallelize over bool-leafs - - openvdb::tree::LeafManager boolLeafs(boolTree); - boolLeafs.foreach(*this, threaded); - - // Composite tregions that are represnted by tiles - // Parallelize within each tile. - - typename BoolTreeT::ValueOnCIter citer = boolTree.cbeginValueOn(); - citer.setMaxDepth(BoolTree::ValueOnCIter::LEAF_DEPTH - 1); - - if (!citer) return; - - typename tree::ValueAccessor alphaAccessor(mAlpha); - typename tree::ValueAccessor sourceAccessor(mSource); - - for (; citer; ++citer) { - - const openvdb::math::Coord org = citer.getCoord(); - - // Early out if both alpha and source are zero in this tile. - - const ValueT alphaValue = alphaAccessor.getValue(org); - const ValueT sourceValue = sourceAccessor.getValue(org); - - if (openvdb::math::isZero(alphaValue) && - openvdb::math::isZero(sourceValue) ) continue; - - // Compute overlap of tile with the dense grid - - openvdb::math::CoordBBox localBBox = citer.getBoundingBox(); - localBBox.intersect(mDense.bbox()); - - // Early out if there is no intersection - - if (localBBox.empty()) continue; - - // Composite the tile-uniform values into the dense grid. - compositeFromTile(mDense, localBBox, sourceValue, - alphaValue, beta, strenght, threaded); - } - } - - // Composites leaf values where the alpha values are active. - // Used in sparseComposite - void inline operator()(const BoolLeafT& boolLeaf, size_t /*i*/) const - { - - typedef UniformLeaf ULeaf; - openvdb::math::CoordBBox localBBox = boolLeaf.getNodeBoundingBox(); - localBBox.intersect(mDense.bbox()); - - // Early out for non-overlapping leafs - - if (localBBox.empty()) return; - - const openvdb::math::Coord org = boolLeaf.origin(); - const LeafT* alphaLeaf = mAlpha.probeLeaf(org); - const LeafT* sourceLeaf = mSource.probeLeaf(org); - - if (!sourceLeaf) { - - // Create a source leaf proxy with the correct value - ULeaf uniformSource(mSource.getValue(org)); - - if (!alphaLeaf) { - - // Create an alpha leaf proxy with the correct value - ULeaf uniformAlpha(mAlpha.getValue(org)); - - compositeFromLeaf(mDense, localBBox, uniformSource, uniformAlpha, - mBeta, mStrength); - } else { - - compositeFromLeaf(mDense, localBBox, uniformSource, *alphaLeaf, - mBeta, mStrength); - } - } else { - if (!alphaLeaf) { - - // Create an alpha leaf proxy with the correct value - ULeaf uniformAlpha(mAlpha.getValue(org)); - - compositeFromLeaf(mDense, localBBox, *sourceLeaf, uniformAlpha, - mBeta, mStrength); - } else { - - compositeFromLeaf(mDense, localBBox, *sourceLeaf, *alphaLeaf, - mBeta, mStrength); - } - } - } - // i.e. it assumes that all valueOff Alpha voxels have value 0. - - template - inline static void compositeFromLeaf(DenseT& dense, const openvdb::math::CoordBBox& bbox, - const LeafT1& source, const LeafT2& alpha, - const ValueT beta, const ValueT strength) - { - typedef openvdb::math::Coord::ValueType IntType; - - const ValueT sbeta = strength * beta; - openvdb::math::Coord ijk = bbox.min(); - - - if (alpha.isDense() /*all active values*/) { - - // Optial path for dense alphaLeaf - const IntType size = bbox.max().z() + 1 - bbox.min().z(); - - for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) { - for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) { - - ValueT* d = const_cast(&dense.getValue(ijk)); - const ValueT* a = &alpha.getValue(ijk); - const ValueT* s = &source.getValue(ijk); - - for (IntType idx = 0; idx < size; ++idx) { - d[idx] = CompositeMethod::apply(d[idx], a[idx], s[idx], - strength, beta, sbeta); - } - } - } - } else { - - // AlphaLeaf has non-active cells. - - for (ijk[0] = bbox.min().x(); ijk[0] < bbox.max().x() + 1; ++ijk[0]) { - for (ijk[1] = bbox.min().y(); ijk[1] < bbox.max().y() + 1; ++ijk[1]) { - for (ijk[2] = bbox.min().z(); ijk[2] < bbox.max().z() + 1; ++ijk[2]) { - - if (alpha.isValueOn(ijk)) { - - dense.setValue(ijk, - CompositeMethod::apply(dense.getValue(ijk), - alpha.getValue(ijk), source.getValue(ijk), - strength, beta, sbeta) - ); - } - } - } - } - } - } - - inline static void compositeFromTile(DenseT& dense, openvdb::math::CoordBBox& bbox, - const ValueT& sourceValue, const ValueT& alphaValue, - const ValueT& beta, const ValueT& strength, - bool threaded) - { - - typedef UniformTransformer TileTransformer; - TileTransformer functor(sourceValue, alphaValue, beta, strength); - - // Transform the data inside the bbox according to the TileTranformer. - - transformDense(dense, bbox, functor, threaded); - - } - - - void denseComposite(bool threaded) - { - /// Construct a range that corresponds to the - /// bounding box of the dense volume - const openvdb::math::CoordBBox& bbox = mDense.bbox(); - - Range3d range(bbox.min().x(), bbox.max().x(), LeafT::DIM, - bbox.min().y(), bbox.max().y(), LeafT::DIM, - bbox.min().z(), bbox.max().z(), LeafT::DIM); - - // Interate over the range, compositing into - // the dense grid using value accessors for - // sparse the grids. - if (threaded) { - tbb::parallel_for(range, *this); - } else { - (*this)(range); - } - - } - - // Composites a dense region using value accessors - // into a dense grid - void inline operator()(const Range3d& range) const - { - // Use value accessors to alpha and source - - typename tree::ValueAccessor alphaAccessor(mAlpha); - typename tree::ValueAccessor sourceAccessor(mSource); - - const ValueT strength = mStrength; - const ValueT beta = mBeta; - const ValueT sbeta = strength * beta; - - // Unpack the range3d item. - const Index imin = range.pages().begin(); - const Index imax = range.pages().end(); - - const Index jmin = range.rows().begin(); - const Index jmax = range.rows().end(); - - const Index kmin = range.cols().begin(); - const Index kmax = range.cols().end(); - - openvdb::Coord ijk; - for (ijk[0] = imin; ijk[0] < imax; ++ijk[0]) { - for (ijk[1] = jmin; ijk[1] < jmax; ++ijk[1]) { - for (ijk[2] = kmin; ijk[2] < kmax; ++ijk[2]) { - const ValueT d_old = mDense.getValue(ijk); - const ValueT& alpha = alphaAccessor.getValue(ijk); - const ValueT& src = sourceAccessor.getValue(ijk); - - mDense.setValue(ijk, CompositeMethod::apply(d_old, alpha, src, - strength, beta, sbeta)); - } - } - } - - } - - -private: - - // Internal class that wraps the templated composite method - // for use when both alpha and source are uniform over - // a prescribed bbox (e.g. a tile). - class UniformTransformer - { - public: - UniformTransformer(const ValueT& source, const ValueT& alpha, const ValueT& _beta, - const ValueT& _strength) : - mSource(source), mAlpha(alpha), mBeta(_beta), - mStrength(_strength), mSBeta(_strength * _beta) - {} - - ValueT operator()(const ValueT& input) const - { - return CompositeMethod::apply(input, mAlpha, mSource, - mStrength, mBeta, mSBeta); - } - - private: - const ValueT mSource; const ValueT mAlpha; const ValueT mBeta; - const ValueT mStrength; const ValueT mSBeta; - }; - - - // Simple Class structure that mimics a leaf - // with uniform values. Holds LeafT::DIM copies - // of a value in an array. - struct Line { ValueT mValues[LeafT::DIM]; }; - class UniformLeaf : private Line - { - public: - typedef typename LeafT::ValueType ValueT; - - typedef Line BaseT; - UniformLeaf(const ValueT& value) : BaseT(init(value)){}; - - static const BaseT init(const ValueT& value) { - BaseT tmp; - for (openvdb::Index i = 0; i < LeafT::DIM; ++i) { - tmp.mValues[i] = value; - } - return tmp; - } - - bool isDense() const { return true; } - bool isValueOn(openvdb::math::Coord&) const { return true; } - - inline const ValueT& getValue(const openvdb::math::Coord& ) const - {return BaseT::mValues[0];} - }; - -private: - DenseT& mDense; - const TreeT& mSource; - const TreeT& mAlpha; - ValueT mBeta; - ValueT mStrength; -}; // class SparseToDenseCompositor - - -namespace ds -{ - //@{ - /// @brief Point wise methods used to apply various compositing operations. - template - struct OpOver - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT strength, - const ValueT beta, - const ValueT /*sbeta*/) - { return (u + strength * alpha * (beta * v - u)); } - }; - - - template - struct OpAdd - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT /*strength*/, - const ValueT /*beta*/, - const ValueT sbeta) - { return (u + sbeta * alpha * v); } - }; - - template - struct OpSub - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT /*strength*/, - const ValueT /*beta*/, - const ValueT sbeta) - { return (u - sbeta * alpha * v); } - }; - - template - struct OpMin - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT s /*trength*/, - const ValueT beta, - const ValueT /*sbeta*/) - { return ( ( 1 - s * alpha) * u + s * alpha * std::min(u, beta * v) ); } - }; - - - template - struct OpMax - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT s/*trength*/, - const ValueT beta, - const ValueT /*sbeta*/) - { return ( ( 1 - s * alpha ) * u + s * alpha * std::min(u, beta * v) ); } - }; - - template - struct OpMult - { - static inline ValueT apply(const ValueT u, const ValueT alpha, - const ValueT v, - const ValueT s/*trength*/, - const ValueT /*beta*/, - const ValueT sbeta) - { return ( ( 1 + alpha * (sbeta * v - s)) * u ); } - }; - //@} - - //@{ - /// Translator that converts an enum to compositing functor types - template - struct CompositeFunctorTranslator{}; - - template - struct CompositeFunctorTranslator{ typedef OpOver OpT; }; - - template - struct CompositeFunctorTranslator{ typedef OpAdd OpT; }; - - template - struct CompositeFunctorTranslator{ typedef OpSub OpT; }; - - template - struct CompositeFunctorTranslator{ typedef OpMin OpT; }; - - template - struct CompositeFunctorTranslator{ typedef OpMax OpT; }; - - template - struct CompositeFunctorTranslator{ typedef OpMult OpT; }; - //@} - -} // namespace ds - - -template -void compositeToDense( - Dense& dense, - const TreeT& source, const TreeT& alpha, - const typename TreeT::ValueType beta, - const typename TreeT::ValueType strength, - bool threaded) -{ - typedef typename TreeT::ValueType ValueT; - typedef ds::CompositeFunctorTranslator Translator; - typedef typename Translator::OpT Method; - - if (openvdb::math::isZero(strength)) return; - - SparseToDenseCompositor tool(dense, source, alpha, beta, strength); - - if (openvdb::math::isZero(alpha.background()) && - openvdb::math::isZero(source.background())) - { - // Use the sparsity of (alpha U source) as the iteration space. - tool.sparseComposite(threaded); - } else { - // Use the bounding box of dense as the iteration space. - tool.denseComposite(threaded); - } -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif //OPENVDB_TOOLS_DENSESPARSETOOLS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Diagnostics.h b/openvdb_3_0_0_library/tools/Diagnostics.h deleted file mode 100755 index 3547c5f..0000000 --- a/openvdb_3_0_0_library/tools/Diagnostics.h +++ /dev/null @@ -1,900 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* TODO: Ken Museth - -checkLevelSet -1) has level set class type -2) value type is floating point -3) has uniform scale -4) background value is positive and n*dx -5) active values in range between +-background -6) no active tiles -8) abs of inactive values = background -9) norm grad is close to one - -checkDensity volume -1) has fog class tag -2) value type is a floating point -3) background = 0 -4) all inactive values are zero -5) all active values are 0-1 - -*/ - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -//////////////////////////////////////// - - -/// @brief Threaded method to find unique inactive values. -/// -/// @param grid A VDB volume. -/// @param values List of unique inactive values, returned by this method. -/// @param numValues Number of values to look for. -/// @return @c false if the @a grid has more than @a numValues inactive values. -template -bool -uniqueInactiveValues(const GridType& grid, - std::vector& values, size_t numValues); - - -//////////////////////////////////////////////////////////////////////////////// - -/// @brief Checks nan values -template -struct CheckNan -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - /// @brief Default constructor - CheckNan() {} - - /// Return true if the scalar value is nan - inline bool operator()(const ElementType& v) const { return boost::math::isnan(v); } - - /// @brief This allow for vector values to be checked componentwise - template - inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const - { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true;//should unroll - return false; - } - - /// @brief Return true if the tile at the iterator location is nan - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the voxel at the iterator location is nan - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const { return "nan"; } - -};// CheckNan - -/// @brief Checks for infinite values, e.g. 1/0 or -1/0 -template -struct CheckInf -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - /// @brief Default constructor - CheckInf() {} - - /// Return true if the value is infinite - inline bool operator()(const ElementType& v) const { return boost::math::isinf(v); } - - /// Return true if any of the vector components are infinite. - template inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const - { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the tile at the iterator location is infinite - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the tile at the iterator location is infinite - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const { return "infinite"; } -};// CheckInf - -/// @brief Checks for both NaN and inf values, i.e. any value that is not finite. -template -struct CheckFinite -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - /// @brief Default constructor - CheckFinite() {} - - /// Return true if the value is NOT finite, i.e. it's Nan or infinite - inline bool operator()(const ElementType& v) const { return !boost::math::isfinite(v); } - - /// Return true if any of the vector components are Nan or infinite. - template - inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the tile at the iterator location is Nan or infinite. - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the tile at the iterator location is Nan or infinite. - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const { return "not finite"; } -};// CheckFinite - -/// @brief Check that the magnitude of a value, a, is close to a fixed -/// magnitude, b, given a fixed tolerance c. That is | |a| - |b| | <= c -template -struct CheckMagnitude -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - /// @brief Default constructor - CheckMagnitude(const ElementType& a, - const ElementType& t = math::Tolerance::value()) - : absVal(math::Abs(a)), tolVal(math::Abs(t)) - { - } - - /// Return true if the magnitude of the value is not approximatly - /// equal to totVal. - inline bool operator()(const ElementType& v) const - { - return math::Abs(math::Abs(v) - absVal) > tolVal; - } - - /// Return true if any of the vector components are infinite. - template inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const - { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the tile at the iterator location is infinite - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the tile at the iterator location is infinite - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "not equal to +/-"< -struct CheckRange -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - // @brief Constructor taking a range to be tested against. - CheckRange(const ElementType& _min, const ElementType& _max) : minVal(_min), maxVal(_max) - { - } - - /// Return true if the value is smaller then min or larger then max. - inline bool operator()(const ElementType& v) const - { - return (MinInclusive ? vmaxVal : v>=maxVal); - } - - /// Return true if any of the vector components are out of range. - template - inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the voxel at the iterator location is out of range. - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the tile at the iterator location is out of range. - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "outside the range " << (MinInclusive ? "[" : "]") - << minVal << "," << maxVal << (MaxInclusive ? "]" : "["); - return ss.str(); - } - - const ElementType minVal, maxVal; -};// CheckRange - -/// @brief Checks a value against a minimum -template -struct CheckMin -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - // @brief Constructor taking a minimum to be tested against. - CheckMin(const ElementType& _min) : minVal(_min) {} - - /// Return true if the value is smaller then min. - inline bool operator()(const ElementType& v) const { return v - inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the voxel at the iterator location is smaller then min. - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the tile at the iterator location is smaller then min. - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "smaller then "< -struct CheckMax -{ - typedef typename VecTraits::ElementType ElementType; - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - - /// @brief Constructor taking a maximum to be tested against. - CheckMax(const ElementType& _max) : maxVal(_max) {} - - /// Return true if the value is larger then max. - inline bool operator()(const ElementType& v) const { return v>maxVal; } - - /// Return true if any of the vector components are larger then max. - template - inline typename boost::enable_if_c::IsVec, bool>::type - operator()(const T& v) const { - for (int i=0; i::Size; ++i) if ((*this)(v[i])) return true; - return false; - } - - /// @brief Return true if the tile at the iterator location is larger then max. - bool operator()(const TreeIterT &iter) const { return (*this)(*iter); } - - /// @brief Return true if the voxel at the iterator location is larger then max. - bool operator()(const VoxelIterT &iter) const { return (*this)(*iter); } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "larger then "<//math::WENO5_BIAS> -struct CheckNormGrad -{ - typedef typename GridT::ValueType ValueType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - typedef typename GridT::ConstAccessor AccT; - - /// @brief Constructor taking a grid and a range to be tested against. - CheckNormGrad(const GridT& grid, const ValueType& _min, const ValueType& _max) - : acc(grid.getConstAccessor()) - , invdx2(ValueType(1.0/math::Pow2(grid.voxelSize()[0]))) - , minVal(_min) - , maxVal(_max) - { - if ( !grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "The transform must have uniform scale for CheckNormGrad to function"); - } - } - - CheckNormGrad(const CheckNormGrad& other) - : acc(other.acc.tree()) - , invdx2(other.invdx2) - , minVal(other.minVal) - , maxVal(other.maxVal) - { - } - - CheckNormGrad& operator=(const CheckNormGrad& other) - { - if (&other != this) { - acc = AccT(other.acc.tree()); - invdx2 = other.invdx2; - minVal = other.minVal; - maxVal = other.maxVal; - } - return *this; - } - - /// Return true if the value is smaller then min or larger then max. - inline bool operator()(const ValueType& v) const { return vmaxVal; } - - /// @brief Return true if zero is outside the range. - /// @note We assume that the norm of the gradient of a tile is always zero. - inline bool operator()(const TreeIterT&) const { return (*this)(ValueType(0)); } - - /// @brief Return true if the norm of the gradient at a voxel - /// location of the iterator is out of range. - inline bool operator()(const VoxelIterT &iter) const - { - const Coord ijk = iter.getCoord(); - return (*this)(invdx2 * math::ISGradientNormSqrd::result(acc, ijk)); - } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "outside the range ["< -struct CheckDivergence -{ - typedef typename GridT::ValueType ValueType; - typedef typename VecTraits::ElementType ElementType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - typedef TreeIterT TileIterT; - typedef typename tree::IterTraits - ::template NodeConverter::Type VoxelIterT; - typedef typename GridT::ConstAccessor AccT; - - /// @brief Constructor taking a grid and a range to be tested against. - CheckDivergence(const GridT& grid, - const ValueType& _min, - const ValueType& _max) - : acc(grid.getConstAccessor()) - , invdx(ValueType(1.0/grid.voxelSize()[0])) - , minVal(_min) - , maxVal(_max) - { - if ( !grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "The transform must have uniform scale for CheckDivergence to function"); - } - } - /// Return true if the value is smaller then min or larger then max. - inline bool operator()(const ElementType& v) const { return vmaxVal; } - - /// @brief Return true if zero is outside the range. - /// @note We assume that the divergence of a tile is always zero. - inline bool operator()(const TreeIterT&) const { return (*this)(ElementType(0)); } - - /// @brief Return true if the divergence at a voxel location of - /// the iterator is out of range. - inline bool operator()(const VoxelIterT &iter) const - { - const Coord ijk = iter.getCoord(); - return (*this)(invdx * math::ISDivergence::result(acc, ijk)); - } - - /// @brief Return a string describing a failed check. - std::string str() const - { - std::ostringstream ss; - ss << "outside the range ["< -class Diagnose -{ - public: - typedef typename GridT::template ValueConverter::Type MaskType; - - Diagnose(const GridT& grid) : mGrid(&grid), mMask(new MaskType()), mCount(0) - { - mMask->setTransform(grid.transformPtr()->copy()); - } - - template - std::string check(const CheckT& check, - bool updateMask = false, - bool checkVoxels = true, - bool checkTiles = true, - bool checkBackground = true) - { - typename MaskType::TreeType* mask = updateMask ? &(mMask->tree()) : NULL; - CheckValues cc(mask, mGrid, check); - std::ostringstream ss; - if (checkBackground) ss << cc.checkBackground(); - if (checkTiles) ss << cc.checkTiles(); - if (checkVoxels) ss << cc.checkVoxels(); - mCount += cc.mCount; - return ss.str(); - } - - /// @brief Return a boolean mask of all the values - /// (i.e. tiles and/or voxels) that have failed one or - /// more checks. - typename MaskType::ConstPtr mask() const { return mMask; } - - /// @brief Return the number of values (i.e. background, tiles or - /// voxels) that have failed one or more checks. - Index64 valueCount() const { return mMask->activeVoxelCount(); } - - /// @brief Return total number of failed checks - /// @note If only one check was performed and the mask was updated - /// failureCount equals valueCount. - Index64 failureCount() const { return mCount; } - -private: - const GridT* mGrid; - typename MaskType::Ptr mMask; - Index64 mCount; - - /// @brief Private class that performs the multithreaded checks - template - struct CheckValues - { - typedef typename MaskType::TreeType MaskT; - typedef typename GridT::TreeType::LeafNodeType LeafT; - typedef typename tree::LeafManager LeafManagerT; - const bool mOwnsMask; - MaskT* mMask; - const GridT* mGrid; - const CheckT mCheck; - Index64 mCount; - - CheckValues(MaskT* mask, const GridT* grid, const CheckT& check) - : mOwnsMask(false) - , mMask(mask) - , mGrid(grid) - , mCheck(check) - , mCount(0) - { - } - CheckValues(CheckValues& other, tbb::split) - : mOwnsMask(true) - , mMask(other.mMask ? new MaskT() : NULL) - , mGrid(other.mGrid) - , mCheck(other.mCheck) - , mCount(0) - { - } - ~CheckValues() { if (mOwnsMask) delete mMask; } - - std::string checkBackground() - { - std::ostringstream ss; - if (mCheck(mGrid->background())) { - ++mCount; - ss << "Background is " + mCheck.str() << std::endl; - } - return ss.str(); - } - - std::string checkTiles() - { - std::ostringstream ss; - const Index64 n = mCount; - typename CheckT::TileIterT i(mGrid->tree()); - for (i.setMaxDepth(GridT::TreeType::RootNodeType::LEVEL - 1); i; ++i) { - if (mCheck(i)) { - ++mCount; - if (mMask) mMask->fill(i.getBoundingBox(), true, true); - } - } - if (const Index64 m = mCount - n) { - ss << m << (m==1?" tile is ":" tiles are ") + mCheck.str() << std::endl; - } - return ss.str(); - } - - std::string checkVoxels() - { - std::ostringstream ss; - LeafManagerT leafs(mGrid->tree()); - const Index64 n = mCount; - tbb::parallel_reduce(leafs.leafRange(), *this); - if (const Index64 m = mCount - n) { - ss << m << (m==1?" voxel is ":" voxels are ") + mCheck.str() << std::endl; - } - return ss.str(); - } - - void operator()(const typename LeafManagerT::LeafRange& r) - { - typedef typename CheckT::VoxelIterT VoxelIterT; - if (mMask) { - for (typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) { - typename MaskT::LeafNodeType* maskLeaf = NULL; - for (VoxelIterT j = tree::IterTraits::begin(*i); j; ++j) { - if (mCheck(j)) { - ++mCount; - if (maskLeaf == NULL) maskLeaf = mMask->touchLeaf(j.getCoord()); - maskLeaf->setValueOn(j.pos(), true); - } - } - } - } else { - for (typename LeafManagerT::LeafRange::Iterator i=r.begin(); i; ++i) { - for (VoxelIterT j = tree::IterTraits::begin(*i); j; ++j) { - if (mCheck(j)) ++mCount; - } - } - } - } - void join(const CheckValues& other) - { - if (mMask) mMask->merge(*(other.mMask), openvdb::MERGE_ACTIVE_STATES_AND_NODES); - mCount += other.mCount; - } - };//End of private class CheckValues - -};// End of public class Diagnose - - -//////////////////////////////////////////////////////////////////////////////// - -// Internal utility objects and implementation details - - -namespace diagnostics_internal { - - -template -class InactiveVoxelValues -{ -public: - typedef tree::LeafManager LeafArray; - typedef typename TreeType::ValueType ValueType; - typedef std::set SetType; - - InactiveVoxelValues(LeafArray&, size_t numValues); - - void runParallel(); - void runSerial(); - - void getInactiveValues(SetType&) const; - - inline InactiveVoxelValues(const InactiveVoxelValues&, tbb::split); - inline void operator()(const tbb::blocked_range&); - inline void join(const InactiveVoxelValues&); - -private: - LeafArray& mLeafArray; - SetType mInactiveValues; - size_t mNumValues; -}; - -template -InactiveVoxelValues::InactiveVoxelValues(LeafArray& leafs, size_t numValues) - : mLeafArray(leafs) - , mInactiveValues() - , mNumValues(numValues) -{ -} - -template -inline -InactiveVoxelValues::InactiveVoxelValues( - const InactiveVoxelValues& rhs, tbb::split) - : mLeafArray(rhs.mLeafArray) - , mInactiveValues() - , mNumValues(rhs.mNumValues) -{ -} - -template -void -InactiveVoxelValues::runParallel() -{ - tbb::parallel_reduce(mLeafArray.getRange(), *this); -} - - -template -void -InactiveVoxelValues::runSerial() -{ - (*this)(mLeafArray.getRange()); -} - - -template -inline void -InactiveVoxelValues::operator()(const tbb::blocked_range& range) -{ - typename TreeType::LeafNodeType::ValueOffCIter iter; - - for (size_t n = range.begin(); n < range.end() && !tbb::task::self().is_cancelled(); ++n) { - for (iter = mLeafArray.leaf(n).cbeginValueOff(); iter; ++iter) { - mInactiveValues.insert(iter.getValue()); - } - - if (mInactiveValues.size() > mNumValues) { - tbb::task::self().cancel_group_execution(); - } - } -} - -template -inline void -InactiveVoxelValues::join(const InactiveVoxelValues& rhs) -{ - mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end()); -} - -template -inline void -InactiveVoxelValues::getInactiveValues(SetType& values) const -{ - values.insert(mInactiveValues.begin(), mInactiveValues.end()); -} - - -//////////////////////////////////////// - - -template -class InactiveTileValues -{ -public: - typedef tree::IteratorRange IterRange; - typedef typename TreeType::ValueType ValueType; - typedef std::set SetType; - - InactiveTileValues(size_t numValues); - - void runParallel(IterRange&); - void runSerial(IterRange&); - - void getInactiveValues(SetType&) const; - - inline InactiveTileValues(const InactiveTileValues&, tbb::split); - inline void operator()(IterRange&); - inline void join(const InactiveTileValues&); - -private: - SetType mInactiveValues; - size_t mNumValues; -}; - - -template -InactiveTileValues::InactiveTileValues(size_t numValues) - : mInactiveValues() - , mNumValues(numValues) -{ -} - -template -inline -InactiveTileValues::InactiveTileValues( - const InactiveTileValues& rhs, tbb::split) - : mInactiveValues() - , mNumValues(rhs.mNumValues) -{ -} - -template -void -InactiveTileValues::runParallel(IterRange& range) -{ - tbb::parallel_reduce(range, *this); -} - - -template -void -InactiveTileValues::runSerial(IterRange& range) -{ - (*this)(range); -} - - -template -inline void -InactiveTileValues::operator()(IterRange& range) -{ - for (; range && !tbb::task::self().is_cancelled(); ++range) { - typename TreeType::ValueOffCIter iter = range.iterator(); - for (; iter; ++iter) { - mInactiveValues.insert(iter.getValue()); - } - - if (mInactiveValues.size() > mNumValues) { - tbb::task::self().cancel_group_execution(); - } - } -} - -template -inline void -InactiveTileValues::join(const InactiveTileValues& rhs) -{ - mInactiveValues.insert(rhs.mInactiveValues.begin(), rhs.mInactiveValues.end()); -} - -template -inline void -InactiveTileValues::getInactiveValues(SetType& values) const -{ - values.insert(mInactiveValues.begin(), mInactiveValues.end()); -} - -} // namespace diagnostics_internal - - -//////////////////////////////////////// - - -template -bool -uniqueInactiveValues(const GridType& grid, - std::vector& values, size_t numValues) -{ - - typedef typename GridType::TreeType TreeType; - typedef typename GridType::ValueType ValueType; - typedef std::set SetType; - - SetType uniqueValues; - - { // Check inactive voxels - TreeType& tree = const_cast(grid.tree()); - tree::LeafManager leafs(tree); - diagnostics_internal::InactiveVoxelValues voxelOp(leafs, numValues); - voxelOp.runParallel(); - voxelOp.getInactiveValues(uniqueValues); - } - - // Check inactive tiles - if (uniqueValues.size() <= numValues) { - typename TreeType::ValueOffCIter iter(grid.tree()); - iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1); - diagnostics_internal::InactiveTileValues tileOp(numValues); - - tree::IteratorRange range(iter); - tileOp.runParallel(range); - - tileOp.getInactiveValues(uniqueValues); - } - - values.clear(); - values.reserve(uniqueValues.size()); - - typename SetType::iterator it = uniqueValues.begin(); - for ( ; it != uniqueValues.end(); ++it) { - values.push_back(*it); - } - - return values.size() <= numValues; -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_DIAGNOSTICS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Filter.h b/openvdb_3_0_0_library/tools/Filter.h deleted file mode 100755 index 1ff86a8..0000000 --- a/openvdb_3_0_0_library/tools/Filter.h +++ /dev/null @@ -1,460 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file Filter.h -/// -/// @brief Filtering of VDB volumes. Note that only the values in the -/// grid are changed, not its topology! All operations can optionally -/// be masked with another grid that acts as an alpha-mask. - -#ifndef OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Interpolation.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Volume filtering (e.g., diffusion) with optional alpha masking -/// -/// @note Only the values in the grid are changed, not its topology! -template::Type, - typename InterruptT = util::NullInterrupter> -class Filter -{ -public: - typedef GridT GridType; - typedef MaskT MaskType; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::LeafNodeType LeafType; - typedef typename GridType::ValueType ValueType; - typedef typename MaskType::ValueType AlphaType; - typedef typename tree::LeafManager LeafManagerType; - typedef typename LeafManagerType::LeafRange RangeType; - typedef typename LeafManagerType::BufferType BufferType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// Constructor - /// @param grid Grid to be filtered. - /// @param interrupt Optional interrupter. - Filter(GridT& grid, InterruptT* interrupt = NULL) - : mGrid(&grid) - , mTask(0) - , mInterrupter(interrupt) - , mMask(NULL) - , mGrainSize(1) - , mMinMask(0) - , mMaxMask(1) - , mInvertMask(false) - { - } - - /// @brief Shallow copy constructor called by tbb::parallel_for() - /// threads during filtering. - /// @param other The other Filter from which to copy. - Filter(const Filter& other) - : mGrid(other.mGrid) - , mTask(other.mTask) - , mInterrupter(other.mInterrupter) - , mMask(other.mMask) - , mGrainSize(other.mGrainSize) - , mMinMask(other.mMinMask) - , mMaxMask(other.mMaxMask) - , mInvertMask(other.mInvertMask) - { - } - - /// @return the grain-size used for multi-threading - int getGrainSize() const { return mGrainSize; } - /// @brief Set the grain-size used for multi-threading. - /// @note A grainsize of 0 or less disables multi-threading! - void setGrainSize(int grainsize) { mGrainSize = grainsize; } - - /// @brief Return the minimum value of the mask to be used for the - /// derivation of a smooth alpha value. - AlphaType minMask() const { return mMinMask; } - /// @brief Return the maximum value of the mask to be used for the - /// derivation of a smooth alpha value. - AlphaType maxMask() const { return mMaxMask; } - /// @brief Define the range for the (optional) scalar mask. - /// @param min Minimum value of the range. - /// @param max Maximum value of the range. - /// @details Mask values outside the range are clamped to zero or one, and - /// values inside the range map smoothly to 0->1 (unless the mask is inverted). - /// @throw ValueError if @a min is not smaller then @a max. - void setMaskRange(AlphaType min, AlphaType max) - { - if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)"); - mMinMask = min; - mMaxMask = max; - } - - /// @brief Return true if the mask is inverted, i.e. min->max in the - /// original mask maps to 1->0 in the inverted alpha mask. - bool isMaskInverted() const { return mInvertMask; } - /// @brief Invert the optional mask, i.e. min->max in the original - /// mask maps to 1->0 in the inverted alpha mask. - void invertMask(bool invert=true) { mInvertMask = invert; } - - /// @brief One iteration of a fast separable mean-value (i.e. box) filter. - /// @param width The width of the mean-value filter is 2*width+1 voxels. - /// @param iterations Number of times the mean-value filter is applied. - /// @param mask Optional alpha mask. - void mean(int width = 1, int iterations = 1, const MaskType* mask = NULL); - - /// @brief One iteration of a fast separable gaussian filter. - /// - /// @note This is approximated as 4 iterations of a separable mean filter - /// which typically leads an approximation that's better than 95%! - /// @param width The width of the mean-value filter is 2*width+1 voxels. - /// @param iterations Numer of times the mean-value filter is applied. - /// @param mask Optional alpha mask. - void gaussian(int width = 1, int iterations = 1, const MaskType* mask = NULL); - - /// @brief One iteration of a median-value filter - /// - /// @note This filter is not separable and is hence relatively slow! - /// @param width The width of the mean-value filter is 2*width+1 voxels. - /// @param iterations Numer of times the mean-value filter is applied. - /// @param mask Optional alpha mask. - void median(int width = 1, int iterations = 1, const MaskType* mask = NULL); - - /// Offsets (i.e. adds) a constant value to all active voxels. - /// @param offset Offset in the same units as the grid. - /// @param mask Optional alpha mask. - void offset(ValueType offset, const MaskType* mask = NULL); - - /// @brief Used internally by tbb::parallel_for() - /// @param range Range of LeafNodes over which to multi-thread. - /// - /// @warning Never call this method directly! - void operator()(const RangeType& range) const - { - if (mTask) mTask(const_cast(this), range); - else OPENVDB_THROW(ValueError, "task is undefined - call median(), mean(), etc."); - } - -private: - typedef typename TreeType::LeafNodeType LeafT; - typedef typename LeafT::ValueOnIter VoxelIterT; - typedef typename LeafT::ValueOnCIter VoxelCIterT; - typedef typename tree::LeafManager::BufferType BufferT; - typedef typename RangeType::Iterator LeafIterT; - typedef tools::AlphaMask AlphaMaskT; - - void cook(LeafManagerType& leafs); - - template - struct Avg { - Avg(const GridT* grid, Int32 w): acc(grid->tree()), width(w), frac(1.f/float(2*w+1)) {} - inline ValueType operator()(Coord xyz); - typename GridT::ConstAccessor acc; - const Int32 width; - const float frac; - }; - - // Private filter methods called by tbb::parallel_for threads - template - void doBox( const RangeType& r, Int32 w); - void doBoxX(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doBoxZ(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doBoxY(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doMedian(const RangeType&, int); - void doOffset(const RangeType&, ValueType); - /// @return true if the process was interrupted - bool wasInterrupted(); - - GridType* mGrid; - typename boost::function mTask; - InterruptT* mInterrupter; - const MaskType* mMask; - int mGrainSize; - AlphaType mMinMask, mMaxMask; - bool mInvertMask; -}; // end of Filter class - - -//////////////////////////////////////// - - -namespace filter_internal { -// Helper function for Filter::Avg::operator() -template static inline void accum(T& sum, T addend) { sum += addend; } -// Overload for bool ValueType -inline void accum(bool& sum, bool addend) { sum = sum || addend; } -} - - -template -template -inline typename GridT::ValueType -Filter::Avg::operator()(Coord xyz) -{ - ValueType sum = zeroVal(); - Int32 &i = xyz[Axis], j = i + width; - for (i -= width; i <= j; ++i) filter_internal::accum(sum, acc.getValue(xyz)); - return static_cast(sum * frac); -} - - -//////////////////////////////////////// - - -template -inline void -Filter::mean(int width, int iterations, const MaskType* mask) -{ - mMask = mask; - - if (mInterrupter) mInterrupter->start("Applying mean filter"); - - const int w = std::max(1, width); - - LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0); - - for (int i=0; iwasInterrupted(); ++i) { - mTask = boost::bind(&Filter::doBoxX, _1, _2, w); - this->cook(leafs); - - mTask = boost::bind(&Filter::doBoxY, _1, _2, w); - this->cook(leafs); - - mTask = boost::bind(&Filter::doBoxZ, _1, _2, w); - this->cook(leafs); - } - - if (mInterrupter) mInterrupter->end(); -} - - -template -inline void -Filter::gaussian(int width, int iterations, const MaskType* mask) -{ - mMask = mask; - - if (mInterrupter) mInterrupter->start("Applying gaussian filter"); - - const int w = std::max(1, width); - - LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0); - - for (int i=0; iwasInterrupted(); ++n) { - mTask = boost::bind(&Filter::doBoxX, _1, _2, w); - this->cook(leafs); - - mTask = boost::bind(&Filter::doBoxY, _1, _2, w); - this->cook(leafs); - - mTask = boost::bind(&Filter::doBoxZ, _1, _2, w); - this->cook(leafs); - } - } - - if (mInterrupter) mInterrupter->end(); -} - - -template -inline void -Filter::median(int width, int iterations, const MaskType* mask) -{ - mMask = mask; - - if (mInterrupter) mInterrupter->start("Applying median filter"); - - LeafManagerType leafs(mGrid->tree(), 1, mGrainSize==0); - - mTask = boost::bind(&Filter::doMedian, _1, _2, std::max(1, width)); - for (int i=0; iwasInterrupted(); ++i) this->cook(leafs); - - if (mInterrupter) mInterrupter->end(); -} - - -template -inline void -Filter::offset(ValueType value, const MaskType* mask) -{ - mMask = mask; - - if (mInterrupter) mInterrupter->start("Applying offset"); - - LeafManagerType leafs(mGrid->tree(), 0, mGrainSize==0); - - mTask = boost::bind(&Filter::doOffset, _1, _2, value); - this->cook(leafs); - - if (mInterrupter) mInterrupter->end(); -} - - -//////////////////////////////////////// - - -/// Private method to perform the task (serial or threaded) and -/// subsequently swap the leaf buffers. -template -inline void -Filter::cook(LeafManagerType& leafs) -{ - if (mGrainSize>0) { - tbb::parallel_for(leafs.leafRange(mGrainSize), *this); - } else { - (*this)(leafs.leafRange()); - } - leafs.swapLeafBuffer(1, mGrainSize==0); -} - - -/// One dimensional convolution of a separable box filter -template -template -inline void -Filter::doBox(const RangeType& range, Int32 w) -{ - this->wasInterrupted(); - AvgT avg(mGrid, w); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - const Coord xyz = iter.getCoord(); - if (alpha(xyz, a, b)) { - buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*avg(xyz))); - } - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - buffer.setValue(iter.pos(), avg(iter.getCoord())); - } - } - } -} - - -/// Performs simple but slow median-value diffusion -template -inline void -Filter::doMedian(const RangeType& range, int width) -{ - this->wasInterrupted(); - typename math::DenseStencil stencil(*mGrid, width);//creates local cache! - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), ValueType(b*(*iter) + a*stencil.median())); - } - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), stencil.median()); - } - } - } -} - - -/// Offsets the values by a constant -template -inline void -Filter::doOffset(const RangeType& range, ValueType offset) -{ - this->wasInterrupted(); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(*mGrid, *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) iter.setValue(ValueType(*iter + a*offset)); - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) { - iter.setValue(*iter + offset); - } - } - } -} - - -template -inline bool -Filter::wasInterrupted() -{ - if (util::wasInterrupted(mInterrupter)) { - tbb::task::self().cancel_group_execution(); - return true; - } - return false; -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_FILTER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/GridOperators.h b/openvdb_3_0_0_library/tools/GridOperators.h deleted file mode 100755 index 8cd2de0..0000000 --- a/openvdb_3_0_0_library/tools/GridOperators.h +++ /dev/null @@ -1,1090 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file GridOperators.h -/// -/// @brief Applies an operator on an input grid to produce an output -/// grid with the same topology but potentially different value type. - -#ifndef OPENVDB_TOOLS_GRID_OPERATORS_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_GRID_OPERATORS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief VectorToScalarConverter::Type is the type of a grid -/// having the same tree configuration as VectorGridType but a scalar value type, T, -/// where T is the type of the original vector components. -/// @details For example, VectorToScalarConverter::Type is equivalent to DoubleGrid. -template struct VectorToScalarConverter { - typedef typename VectorGridType::ValueType::value_type VecComponentValueT; - typedef typename VectorGridType::template ValueConverter::Type Type; -}; - -/// @brief ScalarToVectorConverter::Type is the type of a grid -/// having the same tree configuration as ScalarGridType but value type Vec3 -/// where T is ScalarGridType::ValueType. -/// @details For example, ScalarToVectorConverter::Type is equivalent to Vec3DGrid. -template struct ScalarToVectorConverter { - typedef math::Vec3 VectorValueT; - typedef typename ScalarGridType::template ValueConverter::Type Type; -}; - - -/// @brief Compute the Closest-Point Transform (CPT) from a distance field. -/// @return a new vector-valued grid with the same numerical precision as the input grid -/// (for example, if the input grid is a DoubleGrid, the output grid will be a Vec3DGrid) -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -/// @note The current implementation assumes all the input distance values -/// are represented by leaf voxels and not tiles. This is true for all -/// narrow-band level sets, which this class was originally developed for. -/// In the future we will expand this class to also handle tile values. -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, bool threaded = true) -{ - return cpt(grid, threaded, NULL); -} - -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return cpt(grid, mask, threaded, NULL); -} - - -/// @brief Compute the curl of the given vector-valued grid. -/// @return a new vector-valued grid -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename GridType::Ptr -curl(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -curl(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -curl(const GridType& grid, bool threaded = true) -{ - return curl(grid, threaded, NULL); -} - -template inline -typename GridType::Ptr -curl(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return curl(grid, mask, threaded, NULL); -} - - -/// @brief Compute the divergence of the given vector-valued grid. -/// @return a new scalar-valued grid with the same numerical precision as the input grid -/// (for example, if the input grid is a Vec3DGrid, the output grid will be a DoubleGrid) -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, bool threaded = true) -{ - return divergence(grid, threaded, NULL); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return divergence(grid, mask, threaded, NULL); -} - - -/// @brief Compute the gradient of the given scalar grid. -/// @return a new vector-valued grid with the same numerical precision as the input grid -/// (for example, if the input grid is a DoubleGrid, the output grid will be a Vec3DGrid) -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, bool threaded = true) -{ - return gradient(grid, threaded, NULL); -} - -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return gradient(grid, mask, threaded, NULL); -} - - -/// @brief Compute the Laplacian of the given scalar grid. -/// @return a new scalar grid -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename GridType::Ptr -laplacian(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -laplacian(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -laplacian(const GridType& grid, bool threaded = true) -{ - return laplacian(grid, threaded, NULL); -} - -template inline -typename GridType::Ptr -laplacian(const GridType& grid, const MaskT mask, bool threaded = true) -{ - return laplacian(grid, mask, threaded, NULL); -} - - -/// @brief Compute the mean curvature of the given grid. -/// @return a new grid -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, bool threaded = true) -{ - return meanCurvature(grid, threaded, NULL); -} - -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return meanCurvature(grid, mask, threaded, NULL); -} - - -/// @brief Compute the magnitudes of the vectors of the given vector-valued grid. -/// @return a new scalar-valued grid with the same numerical precision as the input grid -/// (for example, if the input grid is a Vec3DGrid, the output grid will be a DoubleGrid) -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, bool threaded = true) -{ - return magnitude(grid, threaded, NULL); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return magnitude(grid, mask, threaded, NULL); -} - - -/// @brief Normalize the vectors of the given vector-valued grid. -/// @return a new vector-valued grid -/// @details When a mask grid is specified, the solution is calculated only in -/// the intersection of the mask active topology and the input active topology -/// independent of the transforms associated with either grid. -template inline -typename GridType::Ptr -normalize(const GridType& grid, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -normalize(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt); - -template inline -typename GridType::Ptr -normalize(const GridType& grid, bool threaded = true) -{ - return normalize(grid, threaded, NULL); -} - -template inline -typename GridType::Ptr -normalize(const GridType& grid, const MaskT& mask, bool threaded = true) -{ - return normalize(grid, mask, threaded, NULL); -} - - -//////////////////////////////////////// - - -namespace gridop { - -/// @brief ToBoolGrid::Type is the type of a grid having the same -/// tree hierarchy as grid type T but a value type of bool. -/// @details For example, ToBoolGrid::Type is equivalent to BoolGrid. -template -struct ToBoolGrid { - typedef Grid::Type> Type; -}; - - -/// @brief Apply an operator on an input grid to produce an output grid -/// with the same topology but a possibly different value type. -/// @details To facilitate inlining, this class is also templated on a Map type. -/// -/// @note This is a helper class and should never be used directly. -/// -/// @note The current implementation assumes all the input -/// values are represented by leaf voxels and not tiles. In the -/// future we will expand this class to also handle tile values. -template< - typename InGridT, - typename MaskGridType, - typename OutGridT, - typename MapT, - typename OperatorT, - typename InterruptT = util::NullInterrupter> -class GridOperator -{ -public: - typedef typename OutGridT::TreeType OutTreeT; - typedef typename OutTreeT::LeafNodeType OutLeafT; - typedef typename tree::LeafManager LeafManagerT; - - GridOperator(const InGridT& grid, const MaskGridType* mask, const MapT& map, - InterruptT* interrupt = NULL): - mAcc(grid.getConstAccessor()), mMap(map), mInterrupt(interrupt), mMask(mask) - { - } - - virtual ~GridOperator() {} - typename OutGridT::Ptr process(bool threaded = true) - { - if (mInterrupt) mInterrupt->start("Processing grid"); - - // Derive background value of the output grid - typename InGridT::TreeType tmp(mAcc.tree().background()); - typename OutGridT::ValueType backg = OperatorT::result(mMap, tmp, math::Coord(0)); - - // output tree = topology copy of input tree! - typename OutTreeT::Ptr tree(new OutTreeT(mAcc.tree(), backg, TopologyCopy())); - - - // create grid with output tree and unit transform - typename OutGridT::Ptr result(new OutGridT(tree)); - - // Modify the solution area if a mask was supplied. - if (mMask) { - result->topologyIntersection(*mMask); - } - - // transform of output grid = transform of input grid - result->setTransform(math::Transform::Ptr(new math::Transform( mMap.copy() ))); - - LeafManagerT leafManager(*tree); - - if (threaded) { - tbb::parallel_for(leafManager.leafRange(), *this); - } else { - (*this)(leafManager.leafRange()); - } - - if (mInterrupt) mInterrupt->end(); - return result; - } - - /// @brief Iterate sequentially over LeafNodes and voxels in the output - /// grid and compute the laplacian using a valueAccessor for the - /// input grid. - /// - /// @note Never call this public method directly - it is called by - /// TBB threads only! - void operator()(const typename LeafManagerT::LeafRange& range) const - { - if (util::wasInterrupted(mInterrupt)) tbb::task::self().cancel_group_execution(); - - for (typename LeafManagerT::LeafRange::Iterator leaf=range.begin(); leaf; ++leaf) { - for (typename OutLeafT::ValueOnIter value=leaf->beginValueOn(); value; ++value) { - value.setValue(OperatorT::result(mMap, mAcc, value.getCoord())); - } - } - } - -protected: - typedef typename InGridT::ConstAccessor AccessorT; - mutable AccessorT mAcc; - const MapT& mMap; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of GridOperator class - -} // namespace gridop - - -//////////////////////////////////////// - - -/// @brief Compute the closest-point transform of a scalar grid. -template< - typename InGridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Cpt -{ -public: - typedef InGridT InGridType; - typedef typename ScalarToVectorConverter::Type OutGridType; - - Cpt(const InGridType& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Cpt(const InGridType& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename OutGridType::Ptr process(bool threaded = true, bool useWorldTransform = true) - { - Functor functor(mInputGrid, mMask, threaded, useWorldTransform, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (functor.mOutputGrid) functor.mOutputGrid->setVectorType(VEC_CONTRAVARIANT_ABSOLUTE); - return functor.mOutputGrid; - } - -private: - struct IsOpT - { - template - static typename OutGridType::ValueType - result(const MapT& map, const AccT& acc, const Coord& xyz) - { - return math::CPT::result(map, acc, xyz); - } - }; - struct WsOpT - { - template - static typename OutGridType::ValueType - result(const MapT& map, const AccT& acc, const Coord& xyz) - { - return math::CPT_RANGE::result(map, acc, xyz); - } - }; - struct Functor - { - Functor(const InGridType& grid, const MaskGridType* mask, - bool threaded, bool worldspace, InterruptT* interrupt) - : mThreaded(threaded) - , mWorldSpace(worldspace) - , mInputGrid(grid) - , mInterrupt(interrupt) - , mMask(mask) - {} - - template - void operator()(const MapT& map) - { - if (mWorldSpace) { - gridop::GridOperator - op(mInputGrid, mMask, map, mInterrupt); - mOutputGrid = op.process(mThreaded); // cache the result - } else { - gridop::GridOperator - op(mInputGrid, mMask, map, mInterrupt); - mOutputGrid = op.process(mThreaded); // cache the result - } - } - const bool mThreaded; - const bool mWorldSpace; - const InGridType& mInputGrid; - typename OutGridType::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; - const InGridType& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Cpt class - - -//////////////////////////////////////// - - -/// @brief Compute the curl of a vector grid. -template< - typename GridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Curl -{ -public: - typedef GridT InGridType; - typedef GridT OutGridType; - - Curl(const GridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Curl(const GridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename GridT::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (functor.mOutputGrid) functor.mOutputGrid->setVectorType(VEC_COVARIANT); - return functor.mOutputGrid; - } - -private: - struct Functor - { - Functor(const GridT& grid, const MaskGridType* mask, - bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - typedef math::Curl OpT; - gridop::GridOperator - op(mInputGrid, mMask, map, mInterrupt); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const GridT& mInputGrid; - typename GridT::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const GridT& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Curl class - - -//////////////////////////////////////// - - -/// @brief Compute the divergence of a vector grid. -template< - typename InGridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Divergence -{ -public: - typedef InGridT InGridType; - typedef typename VectorToScalarConverter::Type OutGridType; - - Divergence(const InGridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Divergence(const InGridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename OutGridType::Ptr process(bool threaded = true) - { - if (mInputGrid.getGridClass() == GRID_STAGGERED) { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - return functor.mOutputGrid; - } else { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - return functor.mOutputGrid; - } - } - -protected: - template - struct Functor - { - Functor(const InGridT& grid, const MaskGridType* mask, - bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - typedef math::Divergence OpT; - gridop::GridOperator - op(mInputGrid, mMask, map, mInterrupt); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const InGridType& mInputGrid; - typename OutGridType::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const InGridType& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Divergence class - - -//////////////////////////////////////// - - -/// @brief Compute the gradient of a scalar grid. -template< - typename InGridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Gradient -{ -public: - typedef InGridT InGridType; - typedef typename ScalarToVectorConverter::Type OutGridType; - - Gradient(const InGridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Gradient(const InGridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename OutGridType::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (functor.mOutputGrid) functor.mOutputGrid->setVectorType(VEC_COVARIANT); - return functor.mOutputGrid; - } - -protected: - struct Functor - { - Functor(const InGridT& grid, const MaskGridType* mask, - bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - typedef math::Gradient OpT; - gridop::GridOperator - op(mInputGrid, mMask, map, mInterrupt); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const InGridT& mInputGrid; - typename OutGridType::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const InGridT& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Gradient class - - -//////////////////////////////////////// - - -template< - typename GridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Laplacian -{ -public: - typedef GridT InGridType; - typedef GridT OutGridType; - - Laplacian(const GridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Laplacian(const GridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename GridT::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (functor.mOutputGrid) functor.mOutputGrid->setVectorType(VEC_COVARIANT); - return functor.mOutputGrid; - } - -protected: - struct Functor - { - Functor(const GridT& grid, const MaskGridType* mask, bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - typedef math::Laplacian OpT; - gridop::GridOperator - op(mInputGrid, mMask, map); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const GridT& mInputGrid; - typename GridT::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const GridT& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Laplacian class - - -//////////////////////////////////////// - - -template< - typename GridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class MeanCurvature -{ -public: - typedef GridT InGridType; - typedef GridT OutGridType; - - MeanCurvature(const GridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - MeanCurvature(const GridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename GridT::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (functor.mOutputGrid) functor.mOutputGrid->setVectorType(VEC_COVARIANT); - return functor.mOutputGrid; - } - -protected: - struct Functor - { - Functor(const GridT& grid, const MaskGridType* mask, bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - typedef math::MeanCurvature OpT; - gridop::GridOperator - op(mInputGrid, mMask, map); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const GridT& mInputGrid; - typename GridT::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const GridT& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of MeanCurvature class - - -//////////////////////////////////////// - - -template< - typename InGridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Magnitude -{ -public: - typedef InGridT InGridType; - typedef typename VectorToScalarConverter::Type OutGridType; - - Magnitude(const InGridType& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Magnitude(const InGridType& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename OutGridType::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - return functor.mOutputGrid; - } - -protected: - struct OpT - { - template - static typename OutGridType::ValueType - result(const MapT&, const AccT& acc, const Coord& xyz) { return acc.getValue(xyz).length();} - }; - struct Functor - { - Functor(const InGridT& grid, const MaskGridType* mask, - bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - gridop::GridOperator - op(mInputGrid, mMask, map); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const InGridType& mInputGrid; - typename OutGridType::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const InGridType& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Magnitude class - - -//////////////////////////////////////// - - -template< - typename GridT, - typename MaskGridType = typename gridop::ToBoolGrid::Type, - typename InterruptT = util::NullInterrupter> -class Normalize -{ -public: - typedef GridT InGridType; - typedef GridT OutGridType; - - Normalize(const GridT& grid, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(NULL) - { - } - - Normalize(const GridT& grid, const MaskGridType& mask, InterruptT* interrupt = NULL): - mInputGrid(grid), mInterrupt(interrupt), mMask(&mask) - { - } - - typename GridT::Ptr process(bool threaded = true) - { - Functor functor(mInputGrid, mMask, threaded, mInterrupt); - processTypedMap(mInputGrid.transform(), functor); - if (typename GridT::Ptr outGrid = functor.mOutputGrid) { - const VecType vecType = mInputGrid.getVectorType(); - if (vecType == VEC_COVARIANT) { - outGrid->setVectorType(VEC_COVARIANT_NORMALIZE); - } else { - outGrid->setVectorType(vecType); - } - } - return functor.mOutputGrid; - } - -protected: - struct OpT - { - template - static typename OutGridType::ValueType - result(const MapT&, const AccT& acc, const Coord& xyz) - { - typename OutGridType::ValueType vec = acc.getValue(xyz); - if ( !vec.normalize() ) vec.setZero(); - return vec; - } - }; - struct Functor - { - Functor(const GridT& grid, const MaskGridType* mask, bool threaded, InterruptT* interrupt): - mThreaded(threaded), mInputGrid(grid), mInterrupt(interrupt), mMask(mask) {} - - template - void operator()(const MapT& map) - { - gridop::GridOperator - op(mInputGrid, mMask,map); - mOutputGrid = op.process(mThreaded); // cache the result - } - - const bool mThreaded; - const GridT& mInputGrid; - typename GridT::Ptr mOutputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; - }; // Private Functor - - const GridT& mInputGrid; - InterruptT* mInterrupt; - const MaskGridType* mMask; -}; // end of Normalize class - - -//////////////////////////////////////// - - -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Cpt::Type, InterruptT> op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename ScalarToVectorConverter::Type::Ptr -cpt(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Cpt op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -curl(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Curl::Type, InterruptT> op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -curl(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Curl op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Divergence::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -divergence(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Divergence op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Gradient::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename ScalarToVectorConverter::Type::Ptr -gradient(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Gradient op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -laplacian(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Laplacian::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -laplacian(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Laplacian op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - MeanCurvature::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -meanCurvature(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - MeanCurvature op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Magnitude::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename VectorToScalarConverter::Type::Ptr -magnitude(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Magnitude op(grid, mask, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -normalize(const GridType& grid, bool threaded, InterruptT* interrupt) -{ - Normalize::Type, InterruptT> - op(grid, interrupt); - return op.process(threaded); -} - -template inline -typename GridType::Ptr -normalize(const GridType& grid, const MaskT& mask, bool threaded, InterruptT* interrupt) -{ - Normalize op(grid, mask, interrupt); - return op.process(threaded); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_GRID_OPERATORS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/GridTransformer.h b/openvdb_3_0_0_library/tools/GridTransformer.h deleted file mode 100755 index fd0123e..0000000 --- a/openvdb_3_0_0_library/tools/GridTransformer.h +++ /dev/null @@ -1,991 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file GridTransformer.h -/// @author Peter Cucka - -#ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for isApproxEqual() -#include -#include "ChangeBackground.h" -#include "Interpolation.h" -#include "LevelSetRebuild.h" // for doLevelSetRebuild() -#include "SignedFloodFill.h" // for signedFloodFill -#include "Prune.h" // for pruneLevelSet - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Resample an input grid into an output grid of the same type such that, -/// after resampling, the input and output grids coincide (apart from sampling -/// artifacts), but the output grid's transform is unchanged. -/// @details Specifically, this function resamples the input grid into the output -/// grid's index space, using a sampling kernel like PointSampler, BoxSampler, -/// or QuadraticSampler. -/// @param inGrid the grid to be resampled -/// @param outGrid the grid into which to write the resampled voxel data -/// @param interrupter an object adhering to the util::NullInterrupter interface -/// @par Example: -/// @code -/// // Create an input grid with the default identity transform -/// // and populate it with a level-set sphere. -/// FloatGrid::ConstPtr src = tools::makeSphere(...); -/// // Create an output grid and give it a uniform-scale transform. -/// FloatGrid::Ptr dest = FloatGrid::create(); -/// const float voxelSize = 0.5; -/// dest->setTransform(math::Transform::createLinearTransform(voxelSize)); -/// // Resample the input grid into the output grid, reproducing -/// // the level-set sphere at a smaller voxel size. -/// MyInterrupter interrupter = ...; -/// tools::resampleToMatch(*src, *dest, interrupter); -/// @endcode -template -inline void -resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter); - -/// @brief Resample an input grid into an output grid of the same type such that, -/// after resampling, the input and output grids coincide (apart from sampling -/// artifacts), but the output grid's transform is unchanged. -/// @details Specifically, this function resamples the input grid into the output -/// grid's index space, using a sampling kernel like PointSampler, BoxSampler, -/// or QuadraticSampler. -/// @param inGrid the grid to be resampled -/// @param outGrid the grid into which to write the resampled voxel data -/// @par Example: -/// @code -/// // Create an input grid with the default identity transform -/// // and populate it with a level-set sphere. -/// FloatGrid::ConstPtr src = tools::makeSphere(...); -/// // Create an output grid and give it a uniform-scale transform. -/// FloatGrid::Ptr dest = FloatGrid::create(); -/// const float voxelSize = 0.5; -/// dest->setTransform(math::Transform::createLinearTransform(voxelSize)); -/// // Resample the input grid into the output grid, reproducing -/// // the level-set sphere at a smaller voxel size. -/// tools::resampleToMatch(*src, *dest); -/// @endcode -template -inline void -resampleToMatch(const GridType& inGrid, GridType& outGrid); - - -//////////////////////////////////////// - - -namespace internal { - -/// @brief A TileSampler wraps a grid sampler of another type (BoxSampler, -/// QuadraticSampler, etc.), and for samples that fall within a given tile -/// of the grid, it returns a cached tile value instead of accessing the grid. -template -class TileSampler: public Sampler -{ -public: - typedef typename TreeT::ValueType ValueT; - - /// @param b the index-space bounding box of a particular grid tile - /// @param tileVal the tile's value - /// @param on the tile's active state - TileSampler(const CoordBBox& b, const ValueT& tileVal, bool on): - mBBox(b.min().asVec3d(), b.max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false) - { - mBBox.expand(-this->radius()); // shrink the bounding box by the sample radius - mEmpty = mBBox.empty(); - } - - bool sample(const TreeT& inTree, const Vec3R& inCoord, ValueT& result) const - { - if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal; return mActive; } - return Sampler::sample(inTree, inCoord, result); - } - -protected: - BBoxd mBBox; - ValueT mVal; - bool mActive, mEmpty; -}; - - -/// @brief For point sampling, tree traversal is less expensive than testing -/// bounding box membership. -template -class TileSampler: public PointSampler { -public: - TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {} -}; - -/// @brief For point sampling, tree traversal is less expensive than testing -/// bounding box membership. -template -class TileSampler: public StaggeredPointSampler { -public: - TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {} -}; - -} // namespace internal - - -//////////////////////////////////////// - - -/// A GridResampler applies a geometric transformation to an -/// input grid using one of several sampling schemes, and stores -/// the result in an output grid. -/// -/// Usage: -/// @code -/// GridResampler resampler(); -/// resampler.transformGrid(xform, inGrid, outGrid); -/// @endcode -/// where @c xform is a functor that implements the following methods: -/// @code -/// bool isAffine() const -/// openvdb::Vec3d transform(const openvdb::Vec3d&) const -/// openvdb::Vec3d invTransform(const openvdb::Vec3d&) const -/// @endcode -/// @note When the transform is affine and can be expressed as a 4 x 4 matrix, -/// a GridTransformer is much more efficient than a GridResampler. -class GridResampler -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::function InterruptFunc; - - GridResampler(): mThreaded(true), mTransformTiles(true) {} - virtual ~GridResampler() {} - - /// Enable or disable threading. (Threading is enabled by default.) - void setThreaded(bool b) { mThreaded = b; } - /// Return @c true if threading is enabled. - bool threaded() const { return mThreaded; } - /// Enable or disable processing of tiles. (Enabled by default, except for level set grids.) - void setTransformTiles(bool b) { mTransformTiles = b; } - /// Return @c true if tile processing is enabled. - bool transformTiles() const { return mTransformTiles; } - - /// @brief Allow processing to be aborted by providing an interrupter object. - /// The interrupter will be queried periodically during processing. - /// @see util/NullInterrupter.h for interrupter interface requirements. - template void setInterrupter(InterrupterType&); - - template - void transformGrid(const Transformer&, - const GridT& inGrid, GridT& outGrid) const; - -protected: - template - void applyTransform(const Transformer&, const GridT& inGrid, GridT& outGrid) const; - - bool interrupt() const { return mInterrupt && mInterrupt(); } - -private: - template - static void transformBBox(const Transformer&, const CoordBBox& inBBox, - const InTreeT& inTree, OutTreeT& outTree, const InterruptFunc&, - const Sampler& = Sampler()); - - template - class RangeProcessor; - - bool mThreaded, mTransformTiles; - InterruptFunc mInterrupt; -}; - - -//////////////////////////////////////// - - -/// @brief A GridTransformer applies a geometric transformation to an -/// input grid using one of several sampling schemes, and stores -/// the result in an output grid. -/// -/// @note GridTransformer is optimized for affine transformations. -/// -/// Usage: -/// @code -/// Mat4R xform = ...; -/// GridTransformer transformer(xform); -/// transformer.transformGrid(inGrid, outGrid); -/// @endcode -/// or -/// @code -/// Vec3R pivot = ..., scale = ..., rotate = ..., translate = ...; -/// GridTransformer transformer(pivot, scale, rotate, translate); -/// transformer.transformGrid(inGrid, outGrid); -/// @endcode -class GridTransformer: public GridResampler -{ -public: - typedef boost::shared_ptr Ptr; - - GridTransformer(const Mat4R& xform); - GridTransformer( - const Vec3R& pivot, - const Vec3R& scale, - const Vec3R& rotate, - const Vec3R& translate, - const std::string& xformOrder = "tsr", - const std::string& rotationOrder = "zyx"); - virtual ~GridTransformer() {} - - const Mat4R& getTransform() const { return mTransform; } - - template - void transformGrid(const GridT& inGrid, GridT& outGrid) const; - -private: - struct MatrixTransform; - - inline void init(const Vec3R& pivot, const Vec3R& scale, - const Vec3R& rotate, const Vec3R& translate, - const std::string& xformOrder, const std::string& rotOrder); - - Vec3R mPivot; - Vec3i mMipLevels; - Mat4R mTransform, mPreScaleTransform, mPostScaleTransform; -}; - - -//////////////////////////////////////// - - -namespace local_util { - -/// @brief Decompose an affine transform into scale, rotation and translation components. -/// @return @c false if the given matrix is not affine or cannot otherwise be decomposed. -/// @todo This is not safe for matrices with shear. -template -inline bool -decompose(const math::Mat4& m, math::Vec3& scale, - math::Vec3& rotate, math::Vec3& translate) -{ - if (!math::isAffine(m)) return false; - - // this is the translation in world space - translate = m.getTranslation(); - // Extract translation. - math::Mat3 temp = m.getMat3(); - - scale.init( - (math::Vec3(1, 0, 0) * temp).length(), - (math::Vec3(0, 1, 0) * temp).length(), - (math::Vec3(0, 0, 1) * temp).length()); - // Extract scale. - temp *= math::scale >(scale).inverse(); - - rotate = math::eulerAngles(temp, math::XYZ_ROTATION); - - if (!rotate.eq(math::Vec3::zero()) && !scale.eq(math::Vec3(scale[0]))) { - // No unique decomposition if scale is nonuniform and rotation is nonzero. - return false; - } - return true; -} - -} // namespace local_util - - -//////////////////////////////////////// - - -/// This class implements the Transformer functor interface (specifically, -/// the isAffine(), transform() and invTransform() methods) for a transform -/// that is expressed as a 4 x 4 matrix. -struct GridTransformer::MatrixTransform -{ - MatrixTransform(): mat(Mat4R::identity()), invMat(Mat4R::identity()) {} - MatrixTransform(const Mat4R& xform): mat(xform), invMat(xform.inverse()) {} - - bool isAffine() const { return math::isAffine(mat); } - - Vec3R transform(const Vec3R& pos) const { return mat.transformH(pos); } - - Vec3R invTransform(const Vec3R& pos) const { return invMat.transformH(pos); } - - Mat4R mat, invMat; -}; - - -//////////////////////////////////////// - - -/// @brief This class implements the Transformer functor interface (specifically, -/// the isAffine(), transform() and invTransform() methods) for a transform -/// that maps an A grid into a B grid's index space such that, after resampling, -/// A's index space and transform match B's index space and transform. -class ABTransform -{ -public: - /// @param aXform the A grid's transform - /// @param bXform the B grid's transform - ABTransform(const math::Transform& aXform, const math::Transform& bXform): - mAXform(aXform), - mBXform(bXform), - mIsAffine(mAXform.isLinear() && mBXform.isLinear()), - mIsIdentity(mIsAffine && mAXform == mBXform) - {} - - bool isAffine() const { return mIsAffine; } - - bool isIdentity() const { return mIsIdentity; } - - openvdb::Vec3R transform(const openvdb::Vec3R& pos) const - { - return mBXform.worldToIndex(mAXform.indexToWorld(pos)); - } - - openvdb::Vec3R invTransform(const openvdb::Vec3R& pos) const - { - return mAXform.worldToIndex(mBXform.indexToWorld(pos)); - } - - const math::Transform& getA() const { return mAXform; } - const math::Transform& getB() const { return mBXform; } - -private: - const math::Transform &mAXform, &mBXform; - const bool mIsAffine; - const bool mIsIdentity; -}; - - -/// The normal entry points for resampling are the resampleToMatch() functions, -/// which correctly handle level set grids under scaling and shearing. -/// doResampleToMatch() is mainly for internal use but is typically faster -/// for level sets, and correct provided that no scaling or shearing is needed. -/// -/// @warning Do not use this function to scale or shear a level set grid. -template -inline void -doResampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter) -{ - ABTransform xform(inGrid.transform(), outGrid.transform()); - - if (Sampler::consistent() && xform.isIdentity()) { - // If the transforms of the input and output are identical, the - // output tree is simply a deep copy of the input tree. - outGrid.setTree(inGrid.tree().copy()); - } else if (xform.isAffine()) { - // If the input and output transforms are both affine, create an - // input to output transform (in:index-to-world * out:world-to-index) - // and use the fast GridTransformer API. - Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() * - ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() ); - - GridTransformer transformer(mat); - transformer.setInterrupter(interrupter); - - // Transform the input grid and store the result in the output grid. - transformer.transformGrid(inGrid, outGrid); - } else { - // If either the input or the output transform is non-affine, - // use the slower GridResampler API. - GridResampler resampler; - resampler.setInterrupter(interrupter); - - resampler.transformGrid(xform, inGrid, outGrid); - } -} - - -template -inline void -resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter) -{ - if (inGrid.getGridClass() == GRID_LEVEL_SET) { - // If the input grid is a level set, resample it using the level set rebuild tool. - - if (inGrid.constTransform() == outGrid.constTransform()) { - // If the transforms of the input and output grids are identical, - // the output tree is simply a deep copy of the input tree. - outGrid.setTree(inGrid.tree().copy()); - return; - } - - // If the output grid is a level set, resample the input grid to have the output grid's - // background value. Otherwise, preserve the input grid's background value. - typedef typename GridType::ValueType ValueT; - const ValueT halfWidth = ((outGrid.getGridClass() == openvdb::GRID_LEVEL_SET) - ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0])) - : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0]))); - - typename GridType::Ptr tempGrid; - try { - tempGrid = doLevelSetRebuild(inGrid, /*iso=*/zeroVal(), - /*exWidth=*/halfWidth, /*inWidth=*/halfWidth, - &outGrid.constTransform(), &interrupter); - } catch (TypeError&) { - // The input grid is classified as a level set, but it has a value type - // that is not supported by the level set rebuild tool. Fall back to - // using the generic resampler. - tempGrid.reset(); - } - if (tempGrid) { - outGrid.setTree(tempGrid->treePtr()); - return; - } - } - - // If the input grid is not a level set, use the generic resampler. - doResampleToMatch(inGrid, outGrid, interrupter); -} - - -template -inline void -resampleToMatch(const GridType& inGrid, GridType& outGrid) -{ - util::NullInterrupter interrupter; - resampleToMatch(inGrid, outGrid, interrupter); -} - - -//////////////////////////////////////// - - -inline -GridTransformer::GridTransformer(const Mat4R& xform): - mPivot(0, 0, 0), - mMipLevels(0, 0, 0), - mTransform(xform), - mPreScaleTransform(Mat4R::identity()), - mPostScaleTransform(Mat4R::identity()) -{ - Vec3R scale, rotate, translate; - if (local_util::decompose(mTransform, scale, rotate, translate)) { - // If the transform can be decomposed into affine components, - // use them to set up a mipmapping-like scheme for downsampling. - init(mPivot, scale, rotate, translate, "srt", "zyx"); - } -} - - -inline -GridTransformer::GridTransformer( - const Vec3R& pivot, const Vec3R& scale, - const Vec3R& rotate, const Vec3R& translate, - const std::string& xformOrder, const std::string& rotOrder): - mPivot(0, 0, 0), - mMipLevels(0, 0, 0), - mPreScaleTransform(Mat4R::identity()), - mPostScaleTransform(Mat4R::identity()) -{ - init(pivot, scale, rotate, translate, xformOrder, rotOrder); -} - - -//////////////////////////////////////// - - -inline void -GridTransformer::init( - const Vec3R& pivot, const Vec3R& scale, - const Vec3R& rotate, const Vec3R& translate, - const std::string& xformOrder, const std::string& rotOrder) -{ - if (xformOrder.size() != 3) { - OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")"); - } - if (rotOrder.size() != 3) { - OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")"); - } - - mPivot = pivot; - - // Scaling is handled via a mipmapping-like scheme of successive - // halvings of the tree resolution, until the remaining scale - // factor is greater than or equal to 1/2. - Vec3R scaleRemainder = scale; - for (int i = 0; i < 3; ++i) { - double s = std::fabs(scale(i)); - if (s < 0.5) { - mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0))); - scaleRemainder(i) = scale(i) * (1 << mMipLevels(i)); - } - } - - // Build pre-scale and post-scale transform matrices based on - // the user-specified order of operations. - // Note that we iterate over the transform order string in reverse order - // (e.g., "t", "r", "s", given "srt"). This is because math::Mat matrices - // postmultiply row vectors rather than premultiplying column vectors. - mTransform = mPreScaleTransform = mPostScaleTransform = Mat4R::identity(); - Mat4R* remainder = &mPostScaleTransform; - int rpos, spos, tpos; - rpos = spos = tpos = 3; - for (int ix = 2; ix >= 0; --ix) { // reverse iteration - switch (xformOrder[ix]) { - - case 'r': - rpos = ix; - mTransform.preTranslate(pivot); - remainder->preTranslate(pivot); - - int xpos, ypos, zpos; - xpos = ypos = zpos = 3; - for (int ir = 2; ir >= 0; --ir) { - switch (rotOrder[ir]) { - case 'x': - xpos = ir; - mTransform.preRotate(math::X_AXIS, rotate.x()); - remainder->preRotate(math::X_AXIS, rotate.x()); - break; - case 'y': - ypos = ir; - mTransform.preRotate(math::Y_AXIS, rotate.y()); - remainder->preRotate(math::Y_AXIS, rotate.y()); - break; - case 'z': - zpos = ir; - mTransform.preRotate(math::Z_AXIS, rotate.z()); - remainder->preRotate(math::Z_AXIS, rotate.z()); - break; - } - } - // Reject rotation order strings that don't contain exactly one - // instance of "x", "y" and "z". - if (xpos > 2 || ypos > 2 || zpos > 2) { - OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")"); - } - - mTransform.preTranslate(-pivot); - remainder->preTranslate(-pivot); - break; - - case 's': - spos = ix; - mTransform.preTranslate(pivot); - mTransform.preScale(scale); - mTransform.preTranslate(-pivot); - - remainder->preTranslate(pivot); - remainder->preScale(scaleRemainder); - remainder->preTranslate(-pivot); - remainder = &mPreScaleTransform; - break; - - case 't': - tpos = ix; - mTransform.preTranslate(translate); - remainder->preTranslate(translate); - break; - } - } - // Reject transform order strings that don't contain exactly one - // instance of "t", "r" and "s". - if (tpos > 2 || rpos > 2 || spos > 2) { - OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")"); - } -} - - -//////////////////////////////////////// - - -template -void -GridResampler::setInterrupter(InterrupterType& interrupter) -{ - mInterrupt = boost::bind(&InterrupterType::wasInterrupted, - /*this=*/&interrupter, /*percent=*/-1); -} - - -template -void -GridResampler::transformGrid(const Transformer& xform, - const GridT& inGrid, GridT& outGrid) const -{ - tools::changeBackground(outGrid.tree(), inGrid.background()); - applyTransform(xform, inGrid, outGrid); -} - - -template -void -GridTransformer::transformGrid(const GridT& inGrid, GridT& outGrid) const -{ - tools::changeBackground(outGrid.tree(), inGrid.background()); - - if (!Sampler::mipmap() || mMipLevels == Vec3i::zero()) { - // Skip the mipmapping step. - const MatrixTransform xform(mTransform); - applyTransform(xform, inGrid, outGrid); - - } else { - bool firstPass = true; - const typename GridT::ValueType background = inGrid.background(); - typename GridT::Ptr tempGrid = GridT::create(background); - - if (!mPreScaleTransform.eq(Mat4R::identity())) { - firstPass = false; - // Apply the pre-scale transform to the input grid - // and store the result in a temporary grid. - const MatrixTransform xform(mPreScaleTransform); - applyTransform(xform, inGrid, *tempGrid); - } - - // While the scale factor along one or more axes is less than 1/2, - // scale the grid by half along those axes. - Vec3i count = mMipLevels; // # of halvings remaining per axis - while (count != Vec3i::zero()) { - MatrixTransform xform; - xform.mat.setTranslation(mPivot); - xform.mat.preScale(Vec3R( - count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1)); - xform.mat.preTranslate(-mPivot); - xform.invMat = xform.mat.inverse(); - - if (firstPass) { - firstPass = false; - // Scale the input grid and store the result in a temporary grid. - applyTransform(xform, inGrid, *tempGrid); - } else { - // Scale the temporary grid and store the result in a transient grid, - // then swap the two and discard the transient grid. - typename GridT::Ptr destGrid = GridT::create(background); - applyTransform(xform, *tempGrid, *destGrid); - tempGrid.swap(destGrid); - } - // (3, 2, 1) -> (2, 1, 0) -> (1, 0, 0) -> (0, 0, 0), etc. - count = math::maxComponent(count - 1, Vec3i::zero()); - } - - // Apply the post-scale transform and store the result in the output grid. - if (!mPostScaleTransform.eq(Mat4R::identity())) { - const MatrixTransform xform(mPostScaleTransform); - applyTransform(xform, *tempGrid, outGrid); - } else { - outGrid.setTree(tempGrid->treePtr()); - } - } -} - - -//////////////////////////////////////// - - -template -class GridResampler::RangeProcessor -{ -public: - typedef typename TreeT::LeafCIter LeafIterT; - typedef typename TreeT::ValueAllCIter TileIterT; - typedef typename tree::IteratorRange LeafRange; - typedef typename tree::IteratorRange TileRange; - typedef typename tree::ValueAccessor InTreeAccessor; - typedef typename tree::ValueAccessor OutTreeAccessor; - - RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inT, TreeT& outT): - mIsRoot(true), mXform(xform), mBBox(b), - mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree) - {} - - RangeProcessor(const Transformer& xform, const CoordBBox& b, const TreeT& inTree): - mIsRoot(false), mXform(xform), mBBox(b), - mInTree(inTree), mOutTree(new TreeT(inTree.background())), - mInAcc(mInTree), mOutAcc(*mOutTree) - {} - - ~RangeProcessor() { if (!mIsRoot) delete mOutTree; } - - /// Splitting constructor: don't copy the original processor's output tree - RangeProcessor(RangeProcessor& other, tbb::split): - mIsRoot(false), - mXform(other.mXform), - mBBox(other.mBBox), - mInTree(other.mInTree), - mOutTree(new TreeT(mInTree.background())), - mInAcc(mInTree), - mOutAcc(*mOutTree), - mInterrupt(other.mInterrupt) - {} - - void setInterrupt(const InterruptFunc& f) { mInterrupt = f; } - - /// Transform each leaf node in the given range. - void operator()(LeafRange& r) - { - for ( ; r; ++r) { - if (interrupt()) break; - LeafIterT i = r.iterator(); - CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim())); - if (!mBBox.empty()) { - // Intersect the leaf node's bounding box with mBBox. - bbox = CoordBBox( - Coord::maxComponent(bbox.min(), mBBox.min()), - Coord::minComponent(bbox.max(), mBBox.max())); - } - if (!bbox.empty()) { - transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt); - } - } - } - - /// Transform each non-background tile in the given range. - void operator()(TileRange& r) - { - for ( ; r; ++r) { - if (interrupt()) break; - - TileIterT i = r.iterator(); - // Skip voxels and background tiles. - if (!i.isTileValue()) continue; - if (!i.isValueOn() && math::isApproxEqual(*i, mOutTree->background())) continue; - - CoordBBox bbox; - i.getBoundingBox(bbox); - if (!mBBox.empty()) { - // Intersect the tile's bounding box with mBBox. - bbox = CoordBBox( - Coord::maxComponent(bbox.min(), mBBox.min()), - Coord::minComponent(bbox.max(), mBBox.max())); - } - if (!bbox.empty()) { - /// @todo This samples the tile voxel-by-voxel, which is much too slow. - /// Instead, compute the largest axis-aligned bounding box that is - /// contained in the transformed tile (adjusted for the sampler radius) - /// and fill it with the tile value. Then transform the remaining voxels. - internal::TileSampler - sampler(bbox, i.getValue(), i.isValueOn()); - transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler); - } - } - } - - /// Merge another processor's output tree into this processor's tree. - void join(RangeProcessor& other) - { - if (!interrupt()) mOutTree->merge(*other.mOutTree); - } - -private: - bool interrupt() const { return mInterrupt && mInterrupt(); } - - const bool mIsRoot; // true if mOutTree is the top-level tree - Transformer mXform; - CoordBBox mBBox; - const TreeT& mInTree; - TreeT* mOutTree; - InTreeAccessor mInAcc; - OutTreeAccessor mOutAcc; - InterruptFunc mInterrupt; -}; - - -//////////////////////////////////////// - - -template -void -GridResampler::applyTransform(const Transformer& xform, - const GridT& inGrid, GridT& outGrid) const -{ - typedef typename GridT::TreeType TreeT; - const TreeT& inTree = inGrid.tree(); - TreeT& outTree = outGrid.tree(); - - typedef RangeProcessor RangeProc; - - const GridClass gridClass = inGrid.getGridClass(); - - if (gridClass != GRID_LEVEL_SET && mTransformTiles) { - // Independently transform the tiles of the input grid. - // Note: Tiles in level sets can only be background tiles, and they - // are handled more efficiently with a signed flood fill (see below). - - RangeProc proc(xform, CoordBBox(), inTree, outTree); - proc.setInterrupt(mInterrupt); - - typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll(); - tileIter.setMaxDepth(tileIter.getLeafDepth() - 1); // skip leaf nodes - typename RangeProc::TileRange tileRange(tileIter); - - if (mThreaded) { - tbb::parallel_reduce(tileRange, proc); - } else { - proc(tileRange); - } - } - - CoordBBox clipBBox; - if (gridClass == GRID_LEVEL_SET) { - // Inactive voxels in level sets can only be background voxels, and they - // are handled more efficiently with a signed flood fill (see below). - clipBBox = inGrid.evalActiveVoxelBoundingBox(); - } - - // Independently transform the leaf nodes of the input grid. - - RangeProc proc(xform, clipBBox, inTree, outTree); - proc.setInterrupt(mInterrupt); - - typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf()); - - if (mThreaded) { - tbb::parallel_reduce(leafRange, proc); - } else { - proc(leafRange); - } - - // If the grid is a level set, mark inactive voxels as inside or outside. - if (gridClass == GRID_LEVEL_SET) { - tools::pruneLevelSet(outTree); - tools::signedFloodFill(outTree); - } -} - - -//////////////////////////////////////// - - -//static -template -void -GridResampler::transformBBox( - const Transformer& xform, - const CoordBBox& bbox, - const InTreeT& inTree, - OutTreeT& outTree, - const InterruptFunc& interrupt, - const Sampler& sampler) -{ - typedef typename OutTreeT::ValueType ValueT; - - // Transform the corners of the input tree's bounding box - // and compute the enclosing bounding box in the output tree. - Vec3R - inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()), - inRMax(bbox.max().x(), bbox.max().y(), bbox.max().z()), - outRMin = math::minComponent(xform.transform(inRMin), xform.transform(inRMax)), - outRMax = math::maxComponent(xform.transform(inRMin), xform.transform(inRMax)); - for (int i = 0; i < 8; ++i) { - Vec3R corner( - i & 1 ? inRMax.x() : inRMin.x(), - i & 2 ? inRMax.y() : inRMin.y(), - i & 4 ? inRMax.z() : inRMin.z()); - outRMin = math::minComponent(outRMin, xform.transform(corner)); - outRMax = math::maxComponent(outRMax, xform.transform(corner)); - } - Vec3i - outMin = local_util::floorVec3(outRMin) - Sampler::radius(), - outMax = local_util::ceilVec3(outRMax) + Sampler::radius(); - - if (!xform.isAffine()) { - // If the transform is not affine, back-project each output voxel - // into the input tree. - Vec3R xyz, inXYZ; - Coord outXYZ; - int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z(); - for (x = outMin.x(); x <= outMax.x(); ++x) { - if (interrupt && interrupt()) break; - xyz.x() = x; - for (y = outMin.y(); y <= outMax.y(); ++y) { - if (interrupt && interrupt()) break; - xyz.y() = y; - for (z = outMin.z(); z <= outMax.z(); ++z) { - xyz.z() = z; - inXYZ = xform.invTransform(xyz); - ValueT result; - if (sampler.sample(inTree, inXYZ, result)) { - outTree.setValueOn(outXYZ, result); - } else { - // Note: Don't overwrite existing active values with inactive values. - if (!outTree.isValueOn(outXYZ)) { - outTree.setValueOff(outXYZ, result); - } - } - } - } - } - } else { // affine - // Compute step sizes in the input tree that correspond to - // unit steps in x, y and z in the output tree. - const Vec3R - translation = xform.invTransform(Vec3R(0, 0, 0)), - deltaX = xform.invTransform(Vec3R(1, 0, 0)) - translation, - deltaY = xform.invTransform(Vec3R(0, 1, 0)) - translation, - deltaZ = xform.invTransform(Vec3R(0, 0, 1)) - translation; - -#if defined(__ICC) - /// @todo The following line is a workaround for bad code generation - /// in opt-icc11.1_64 (but not debug or gcc) builds. It should be - /// removed once the problem has been addressed at its source. - const Vec3R dummy = deltaX; -#endif - - // Step by whole voxels through the output tree, sampling the - // corresponding fractional voxels of the input tree. - Vec3R inStartX = xform.invTransform(Vec3R(outMin)); - Coord outXYZ; - int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z(); - for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) { - if (interrupt && interrupt()) break; - Vec3R inStartY = inStartX; - for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) { - if (interrupt && interrupt()) break; - Vec3R inXYZ = inStartY; - for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) { - ValueT result; - if (sampler.sample(inTree, inXYZ, result)) { - outTree.setValueOn(outXYZ, result); - } else { - // Note: Don't overwrite existing active values with inactive values. - if (!outTree.isValueOn(outXYZ)) { - outTree.setValueOff(outXYZ, result); - } - } - } - } - } - } -} // GridResampler::transformBBox() - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Interpolation.h b/openvdb_3_0_0_library/tools/Interpolation.h deleted file mode 100755 index 543afb2..0000000 --- a/openvdb_3_0_0_library/tools/Interpolation.h +++ /dev/null @@ -1,811 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Interpolation.h -/// -/// Sampler classes such as PointSampler and BoxSampler that are intended for use -/// with tools::GridTransformer should operate in voxel space and must adhere to -/// the interface described in the example below: -/// @code -/// struct MySampler -/// { -/// // Return a short name that can be used to identify this sampler -/// // in error messages and elsewhere. -/// const char* name() { return "mysampler"; } -/// -/// // Return the radius of the sampling kernel in voxels, not including -/// // the center voxel. This is the number of voxels of padding that -/// // are added to all sides of a volume as a result of resampling. -/// int radius() { return 2; } -/// -/// // Return true if scaling by a factor smaller than 0.5 (along any axis) -/// // should be handled via a mipmapping-like scheme of successive halvings -/// // of a grid's resolution, until the remaining scale factor is -/// // greater than or equal to 1/2. Set this to false only when high-quality -/// // scaling is not required. -/// bool mipmap() { return true; } -/// -/// // Specify if sampling at a location that is collocated with a grid point -/// // is guaranteed to return the exact value at that grid point. -/// // For most sampling kernels, this should be false. -/// bool consistent() { return false; } -/// -/// // Sample the tree at the given coordinates and return the result in val. -/// // Return true if the sampled value is active. -/// template -/// bool sample(const TreeT& tree, const Vec3R& coord, typename TreeT::ValueType& val); -/// }; -/// @endcode - -#ifndef OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED - -#include -#include -#include // for OPENVDB_VERSION_NAME -#include // for round() -#include // for SmoothUnitStep -#include // for Transform -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -// The following samplers operate in voxel space. -// When the samplers are applied to grids holding vector or other non-scalar data, -// the data is assumed to be collocated. For example, using the BoxSampler on a grid -// with ValueType Vec3f assumes that all three elements in a vector can be assigned -// the same physical location. Consider using the GridSampler below instead. - -struct PointSampler -{ - static const char* name() { return "point"; } - static int radius() { return 0; } - static bool mipmap() { return false; } - static bool consistent() { return true; } - - /// @brief Sample @a inTree at the nearest neighbor to @a inCoord - /// and store the result in @a result. - /// @return @c true if the sampled value is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); -}; - - -struct BoxSampler -{ - static const char* name() { return "box"; } - static int radius() { return 1; } - static bool mipmap() { return true; } - static bool consistent() { return true; } - - /// @brief Trilinearly reconstruct @a inTree at @a inCoord - /// and store the result in @a result. - /// @return @c true if any one of the sampled values is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); - - /// @brief Trilinearly reconstruct @a inTree at @a inCoord. - /// @return the reconstructed value - template - static typename TreeT::ValueType sample(const TreeT& inTree, const Vec3R& inCoord); - -private: - template - static inline ValueT trilinearInterpolation(ValueT (& data)[N][N][N], const Vec3R& uvw); -}; - - -struct QuadraticSampler -{ - static const char* name() { return "quadratic"; } - static int radius() { return 1; } - static bool mipmap() { return true; } - static bool consistent() { return false; } - - /// @brief Triquadratically reconstruct @a inTree at @a inCoord - /// and store the result in @a result. - /// @return @c true if any one of the sampled values is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); -}; - - -//////////////////////////////////////// - - -// The following samplers operate in voxel space and are designed for Vec3 -// staggered grid data (e.g., fluid simulations using the Marker-and-Cell approach -// associate elements of the velocity vector with different physical locations: -// the faces of a cube). - -struct StaggeredPointSampler -{ - static const char* name() { return "point"; } - static int radius() { return 0; } - static bool mipmap() { return false; } - static bool consistent() { return false; } - - /// @brief Sample @a inTree at the nearest neighbor to @a inCoord - /// and store the result in @a result. - /// @return true if the sampled value is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); -}; - - -struct StaggeredBoxSampler -{ - static const char* name() { return "box"; } - static int radius() { return 1; } - static bool mipmap() { return true; } - static bool consistent() { return false; } - - /// @brief Trilinearly reconstruct @a inTree at @a inCoord - /// and store the result in @a result. - /// @return true if any one of the sampled value is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); -}; - - -struct StaggeredQuadraticSampler -{ - static const char* name() { return "quadratic"; } - static int radius() { return 1; } - static bool mipmap() { return true; } - static bool consistent() { return false; } - - /// @brief Triquadratically reconstruct @a inTree at @a inCoord - /// and store the result in @a result. - /// @return true if any one of the sampled values is active. - template - static bool sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result); -}; - - -//////////////////////////////////////// - - -/// @brief Class that provides the interface for continuous sampling -/// of values in a tree. -/// -/// @details Since trees support only discrete voxel sampling, TreeSampler -/// must be used to sample arbitrary continuous points in (world or -/// index) space. -/// -/// @warning This implementation of the GridSampler stores a pointer -/// to a Tree for value access. While this is thread-safe it is -/// uncached and hence slow compared to using a -/// ValueAccessor. Consequently it is normally advisable to use the -/// template specialization below that employs a -/// ValueAccessor. However, care must be taken when dealing with -/// multi-threading (see warning below). -template -class GridSampler -{ -public: - typedef boost::shared_ptr Ptr; - typedef typename GridOrTreeType::ValueType ValueType; - typedef typename TreeAdapter::GridType GridType; - typedef typename TreeAdapter::TreeType TreeType; - typedef typename TreeAdapter::AccessorType AccessorType; - - /// @param grid a grid to be sampled - explicit GridSampler(const GridType& grid) - : mTree(&(grid.tree())), mTransform(&(grid.transform())) {} - - /// @param tree a tree to be sampled, or a ValueAccessor for the tree - /// @param transform is used when sampling world space locations. - GridSampler(const TreeType& tree, const math::Transform& transform) - : mTree(&tree), mTransform(&transform) {} - - const math::Transform& transform() const { return *mTransform; } - - /// @brief Sample a point in index space in the grid. - /// @param x Fractional x-coordinate of point in index-coordinates of grid - /// @param y Fractional y-coordinate of point in index-coordinates of grid - /// @param z Fractional z-coordinate of point in index-coordinates of grid - template - ValueType sampleVoxel(const RealType& x, const RealType& y, const RealType& z) const - { - return this->isSample(Vec3d(x,y,z)); - } - - /// @brief Sample value in integer index space - /// @param i Integer x-coordinate in index space - /// @param j Integer y-coordinate in index space - /// @param k Integer x-coordinate in index space - ValueType sampleVoxel(typename Coord::ValueType i, - typename Coord::ValueType j, - typename Coord::ValueType k) const - { - return this->isSample(Coord(i,j,k)); - } - - /// @brief Sample value in integer index space - /// @param ijk the location in index space - ValueType isSample(const Coord& ijk) const { return mTree->getValue(ijk); } - - /// @brief Sample in fractional index space - /// @param ispoint the location in index space - ValueType isSample(const Vec3d& ispoint) const - { - ValueType result = zeroVal(); - SamplerType::sample(*mTree, ispoint, result); - return result; - } - - /// @brief Sample in world space - /// @param wspoint the location in world space - ValueType wsSample(const Vec3d& wspoint) const - { - ValueType result = zeroVal(); - SamplerType::sample(*mTree, mTransform->worldToIndex(wspoint), result); - return result; - } - -private: - const TreeType* mTree; - const math::Transform* mTransform; -}; // class GridSampler - - -/// @brief Specialization of GridSampler for construction from a ValueAccessor type -/// -/// @note This version should normally be favoured over the one above -/// that takes a Grid or Tree. The reason is this version uses a -/// ValueAccessor that performs fast (cached) access where the -/// tree-based flavour performs slower (uncached) access. -/// -/// @warning Since this version stores a pointer to an (externally -/// allocated) value accessor it is not threadsafe. Hence each thread -/// should have it own instance of a GridSampler constructed from a -/// local ValueAccessor. Alternatively the Grid/Tree-based GridSampler -/// is threadsafe, but also slower. -template -class GridSampler, SamplerType> -{ -public: - typedef boost::shared_ptr Ptr; - typedef typename TreeT::ValueType ValueType; - typedef TreeT TreeType; - typedef Grid GridType; - typedef typename tree::ValueAccessor AccessorType; - - /// @param acc a ValueAccessor to be sampled - /// @param transform is used when sampling world space locations. - GridSampler(const AccessorType& acc, - const math::Transform& transform) - : mAccessor(&acc), mTransform(&transform) {} - - const math::Transform& transform() const { return *mTransform; } - - /// @brief Sample a point in index space in the grid. - /// @param x Fractional x-coordinate of point in index-coordinates of grid - /// @param y Fractional y-coordinate of point in index-coordinates of grid - /// @param z Fractional z-coordinate of point in index-coordinates of grid - template - ValueType sampleVoxel(const RealType& x, const RealType& y, const RealType& z) const - { - return this->isSample(Vec3d(x,y,z)); - } - - /// @brief Sample value in integer index space - /// @param i Integer x-coordinate in index space - /// @param j Integer y-coordinate in index space - /// @param k Integer x-coordinate in index space - ValueType sampleVoxel(typename Coord::ValueType i, - typename Coord::ValueType j, - typename Coord::ValueType k) const - { - return this->isSample(Coord(i,j,k)); - } - - /// @brief Sample value in integer index space - /// @param ijk the location in index space - ValueType isSample(const Coord& ijk) const { return mAccessor->getValue(ijk); } - - /// @brief Sample in fractional index space - /// @param ispoint the location in index space - ValueType isSample(const Vec3d& ispoint) const - { - ValueType result = zeroVal(); - SamplerType::sample(*mAccessor, ispoint, result); - return result; - } - - /// @brief Sample in world space - /// @param wspoint the location in world space - ValueType wsSample(const Vec3d& wspoint) const - { - ValueType result = zeroVal(); - SamplerType::sample(*mAccessor, mTransform->worldToIndex(wspoint), result); - return result; - } - -private: - const AccessorType* mAccessor;//not thread-safe! - const math::Transform* mTransform; -};//Specialization of GridSampler - - -//////////////////////////////////////// - - -/// @brief This is a simple convenience class that allows for sampling -/// from a source grid into the index space of a target grid. At -/// construction the source and target grids are checked for alignment -/// which potentially renders interpolation unnecessary. Else -/// interpolation is performed according to the templated Sampler -/// type. -/// -/// @warning For performance reasons the check for alignment of the -/// two grids is only performed at construction time! -template -class DualGridSampler -{ -public: - typedef typename GridOrTreeT::ValueType ValueType; - typedef typename TreeAdapter::GridType GridType; - typedef typename TreeAdapter::TreeType TreeType; - typedef typename TreeAdapter::AccessorType AccessorType; - - /// @brief Grid and transform constructor. - /// @param sourceGrid Source grid. - /// @param targetXform Transform of the target grid. - DualGridSampler(const GridType& sourceGrid, - const math::Transform& targetXform) - : mSourceTree(&(sourceGrid.tree())) - , mSourceXform(&(sourceGrid.transform())) - , mTargetXform(&targetXform) - , mAligned(targetXform == *mSourceXform) - { - } - /// @brief Tree and transform constructor. - /// @param sourceTree Source tree. - /// @param sourceXform Transform of the source grid. - /// @param targetXform Transform of the target grid. - DualGridSampler(const TreeType& sourceTree, - const math::Transform& sourceXform, - const math::Transform& targetXform) - : mSourceTree(&sourceTree) - , mSourceXform(&sourceXform) - , mTargetXform(&targetXform) - , mAligned(targetXform == sourceXform) - { - } - /// @brief Return the value of the source grid at the index - /// coordinates, ijk, relative to the target grid (or its tranform). - inline ValueType operator()(const Coord& ijk) const - { - if (mAligned) return mSourceTree->getValue(ijk); - const Vec3R world = mTargetXform->indexToWorld(ijk); - return SamplerT::sample(*mSourceTree, mSourceXform->worldToIndex(world)); - } - /// @brief Return true if the two grids are aligned. - inline bool isAligned() const { return mAligned; } -private: - const TreeType* mSourceTree; - const math::Transform* mSourceXform; - const math::Transform* mTargetXform; - const bool mAligned; -};// DualGridSampler - -/// @brief Specialization of DualGridSampler for construction from a ValueAccessor type. -template -class DualGridSampler, SamplerT> -{ - public: - typedef typename TreeT::ValueType ValueType; - typedef TreeT TreeType; - typedef Grid GridType; - typedef typename tree::ValueAccessor AccessorType; - - /// @brief ValueAccessor and transform constructor. - /// @param sourceAccessor ValueAccessor into the source grid. - /// @param sourceXform Transform for the source grid. - /// @param targetXform Transform for the target grid. - DualGridSampler(const AccessorType& sourceAccessor, - const math::Transform& sourceXform, - const math::Transform& targetXform) - : mSourceAcc(&sourceAccessor) - , mSourceXform(&sourceXform) - , mTargetXform(&targetXform) - , mAligned(targetXform == sourceXform) - { - } - /// @brief Return the value of the source grid at the index - /// coordinates, ijk, relative to the target grid. - inline ValueType operator()(const Coord& ijk) const - { - if (mAligned) return mSourceAcc->getValue(ijk); - const Vec3R world = mTargetXform->indexToWorld(ijk); - return SamplerT::sample(*mSourceAcc, mSourceXform->worldToIndex(world)); - } - /// @brief Return true if the two grids are aligned. - inline bool isAligned() const { return mAligned; } -private: - const AccessorType* mSourceAcc; - const math::Transform* mSourceXform; - const math::Transform* mTargetXform; - const bool mAligned; -};//Specialization of DualGridSampler - -//////////////////////////////////////// - - -// Class to derive the normalized alpha mask -template -class AlphaMask -{ -public: - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - typedef GridT GridType; - typedef MaskT MaskType; - typedef SamplerT SamlerType; - typedef FloatT FloatType; - - AlphaMask(const GridT& grid, const MaskT& mask, FloatT min, FloatT max, bool invert) - : mAcc(mask.tree()) - , mSampler(mAcc, mask.transform() , grid.transform()) - , mMin(min) - , mInvNorm(1/(max-min)) - , mInvert(invert) - { - assert(min < max); - } - - inline bool operator()(const Coord& xyz, FloatT& a, FloatT& b) const - { - a = math::SmoothUnitStep( (mSampler(xyz) - mMin) * mInvNorm );//smooth mapping to 0->1 - b = 1 - a; - if (mInvert) std::swap(a,b); - return a>0; - } - -protected: - typedef typename MaskType::ConstAccessor AccT; - AccT mAcc; - tools::DualGridSampler mSampler; - const FloatT mMin, mInvNorm; - const bool mInvert; -};// AlphaMask - -//////////////////////////////////////// - -namespace local_util { - -inline Vec3i -floorVec3(const Vec3R& v) -{ - return Vec3i(int(std::floor(v(0))), int(std::floor(v(1))), int(std::floor(v(2)))); -} - - -inline Vec3i -ceilVec3(const Vec3R& v) -{ - return Vec3i(int(std::ceil(v(0))), int(std::ceil(v(1))), int(std::ceil(v(2)))); -} - - -inline Vec3i -roundVec3(const Vec3R& v) -{ - return Vec3i(int(::round(v(0))), int(::round(v(1))), int(::round(v(2)))); -} - -} // namespace local_util - - -//////////////////////////////////////// - - -template -inline bool -PointSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - Vec3i inIdx = local_util::roundVec3(inCoord); - return inTree.probeValue(Coord(inIdx), result); -} - - -//////////////////////////////////////// - - -template -inline ValueT -BoxSampler::trilinearInterpolation(ValueT (& data)[N][N][N], const Vec3R& uvw) -{ - // Trilinear interpolation: - // The eight surrounding latice values are used to construct the result. \n - // result(x,y,z) = - // v000 (1-x)(1-y)(1-z) + v001 (1-x)(1-y)z + v010 (1-x)y(1-z) + v011 (1-x)yz - // + v100 x(1-y)(1-z) + v101 x(1-y)z + v110 xy(1-z) + v111 xyz - - ValueT resultA, resultB; - - resultA = data[0][0][0] + ValueT((data[0][0][1] - data[0][0][0]) * uvw[2]); - resultB = data[0][1][0] + ValueT((data[0][1][1] - data[0][1][0]) * uvw[2]); - ValueT result1 = resultA + ValueT((resultB-resultA) * uvw[1]); - - resultA = data[1][0][0] + ValueT((data[1][0][1] - data[1][0][0]) * uvw[2]); - resultB = data[1][1][0] + ValueT((data[1][1][1] - data[1][1][0]) * uvw[2]); - ValueT result2 = resultA + ValueT((resultB - resultA) * uvw[1]); - - return result1 + ValueT(uvw[0] * (result2 - result1)); -} - - -template -inline bool -BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - typedef typename TreeT::ValueType ValueT; - - Vec3i inIdx = local_util::floorVec3(inCoord); - Vec3R uvw = inCoord - inIdx; - - // Retrieve the values of the eight voxels surrounding the - // fractional source coordinates. - ValueT data[2][2][2]; - - bool hasActiveValues = false; - Coord ijk(inIdx); - hasActiveValues |= inTree.probeValue(ijk, data[0][0][0]); // i, j, k - ijk[2] += 1; - hasActiveValues |= inTree.probeValue(ijk, data[0][0][1]); // i, j, k + 1 - ijk[1] += 1; - hasActiveValues |= inTree.probeValue(ijk, data[0][1][1]); // i, j+1, k + 1 - ijk[2] = inIdx[2]; - hasActiveValues |= inTree.probeValue(ijk, data[0][1][0]); // i, j+1, k - ijk[0] += 1; - ijk[1] = inIdx[1]; - hasActiveValues |= inTree.probeValue(ijk, data[1][0][0]); // i+1, j, k - ijk[2] += 1; - hasActiveValues |= inTree.probeValue(ijk, data[1][0][1]); // i+1, j, k + 1 - ijk[1] += 1; - hasActiveValues |= inTree.probeValue(ijk, data[1][1][1]); // i+1, j+1, k + 1 - ijk[2] = inIdx[2]; - hasActiveValues |= inTree.probeValue(ijk, data[1][1][0]); // i+1, j+1, k - - result = trilinearInterpolation(data, uvw); - return hasActiveValues; -} - - -template -inline typename TreeT::ValueType -BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord) -{ - typedef typename TreeT::ValueType ValueT; - - Vec3i inIdx = local_util::floorVec3(inCoord); - Vec3R uvw = inCoord - inIdx; - - // Retrieve the values of the eight voxels surrounding the - // fractional source coordinates. - ValueT data[2][2][2]; - - Coord ijk(inIdx); - data[0][0][0] = inTree.getValue(ijk); // i, j, k - ijk[2] += 1; - data[0][0][1] = inTree.getValue(ijk); // i, j, k + 1 - ijk[1] += 1; - data[0][1][1] = inTree.getValue(ijk); // i, j+1, k + 1 - ijk[2] = inIdx[2]; - data[0][1][0] = inTree.getValue(ijk); // i, j+1, k - ijk[0] += 1; - ijk[1] = inIdx[1]; - data[1][0][0] = inTree.getValue(ijk); // i+1, j, k - ijk[2] += 1; - data[1][0][1] = inTree.getValue(ijk); // i+1, j, k + 1 - ijk[1] += 1; - data[1][1][1] = inTree.getValue(ijk); // i+1, j+1, k + 1 - ijk[2] = inIdx[2]; - data[1][1][0] = inTree.getValue(ijk); // i+1, j+1, k - - return trilinearInterpolation(data, uvw); -} - - -//////////////////////////////////////// - - -template -inline bool -QuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - typedef typename TreeT::ValueType ValueT; - - Vec3i - inIdx = local_util::floorVec3(inCoord), - inLoIdx = inIdx - Vec3i(1, 1, 1); - Vec3R frac = inCoord - inIdx; - - // Retrieve the values of the 27 voxels surrounding the - // fractional source coordinates. - bool active = false; - ValueT v[3][3][3]; - for (int dx = 0, ix = inLoIdx.x(); dx < 3; ++dx, ++ix) { - for (int dy = 0, iy = inLoIdx.y(); dy < 3; ++dy, ++iy) { - for (int dz = 0, iz = inLoIdx.z(); dz < 3; ++dz, ++iz) { - if (inTree.probeValue(Coord(ix, iy, iz), v[dx][dy][dz])) { - active = true; - } - } - } - } - - /// @todo For vector types, interpolate over each component independently. - ValueT vx[3]; - for (int dx = 0; dx < 3; ++dx) { - ValueT vy[3]; - for (int dy = 0; dy < 3; ++dy) { - // Fit a parabola to three contiguous samples in z - // (at z=-1, z=0 and z=1), then evaluate the parabola at z', - // where z' is the fractional part of inCoord.z, i.e., - // inCoord.z - inIdx.z. The coefficients come from solving - // - // | (-1)^2 -1 1 || a | | v0 | - // | 0 0 1 || b | = | v1 | - // | 1^2 1 1 || c | | v2 | - // - // for a, b and c. - const ValueT* vz = &v[dx][dy][0]; - const ValueT - az = static_cast(0.5 * (vz[0] + vz[2]) - vz[1]), - bz = static_cast(0.5 * (vz[2] - vz[0])), - cz = static_cast(vz[1]); - vy[dy] = static_cast(frac.z() * (frac.z() * az + bz) + cz); - } - // Fit a parabola to three interpolated samples in y, then - // evaluate the parabola at y', where y' is the fractional - // part of inCoord.y. - const ValueT - ay = static_cast(0.5 * (vy[0] + vy[2]) - vy[1]), - by = static_cast(0.5 * (vy[2] - vy[0])), - cy = static_cast(vy[1]); - vx[dx] = static_cast(frac.y() * (frac.y() * ay + by) + cy); - } - // Fit a parabola to three interpolated samples in x, then - // evaluate the parabola at the fractional part of inCoord.x. - const ValueT - ax = static_cast(0.5 * (vx[0] + vx[2]) - vx[1]), - bx = static_cast(0.5 * (vx[2] - vx[0])), - cx = static_cast(vx[1]); - result = static_cast(frac.x() * (frac.x() * ax + bx) + cx); - - return active; -} - - -//////////////////////////////////////// - - -template -inline bool -StaggeredPointSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - typedef typename TreeT::ValueType ValueType; - - ValueType tempX, tempY, tempZ; - bool active = false; - - active = PointSampler::sample(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active; - active = PointSampler::sample(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active; - active = PointSampler::sample(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active; - - result.x() = tempX.x(); - result.y() = tempY.y(); - result.z() = tempZ.z(); - - return active; -} - - -//////////////////////////////////////// - - -template -inline bool -StaggeredBoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - typedef typename TreeT::ValueType ValueType; - - ValueType tempX, tempY, tempZ; - tempX = tempY = tempZ = zeroVal(); - bool active = false; - - active = BoxSampler::sample(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active; - active = BoxSampler::sample(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active; - active = BoxSampler::sample(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active; - - result.x() = tempX.x(); - result.y() = tempY.y(); - result.z() = tempZ.z(); - - return active; -} - - -//////////////////////////////////////// - - -template -inline bool -StaggeredQuadraticSampler::sample(const TreeT& inTree, const Vec3R& inCoord, - typename TreeT::ValueType& result) -{ - typedef typename TreeT::ValueType ValueType; - - ValueType tempX, tempY, tempZ; - bool active = false; - - active = QuadraticSampler::sample(inTree, inCoord + Vec3R(0.5, 0, 0), tempX) || active; - active = QuadraticSampler::sample(inTree, inCoord + Vec3R(0, 0.5, 0), tempY) || active; - active = QuadraticSampler::sample(inTree, inCoord + Vec3R(0, 0, 0.5), tempZ) || active; - - result.x() = tempX.x(); - result.y() = tempY.y(); - result.z() = tempZ.z(); - - return active; -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_INTERPOLATION_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetAdvect.h b/openvdb_3_0_0_library/tools/LevelSetAdvect.h deleted file mode 100755 index b30caf9..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetAdvect.h +++ /dev/null @@ -1,717 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file LevelSetAdvect.h -/// -/// @brief Hyperbolic advection of narrow-band level sets - -#ifndef OPENVDB_TOOLS_LEVEL_SET_ADVECT_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVEL_SET_ADVECT_HAS_BEEN_INCLUDED - -#include -#include "LevelSetTracker.h" -#include "Interpolation.h" // for BoxSampler, etc. -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// Below are two simple wrapper classes for advection velocity fields -/// DiscreteField wraps a velocity grid and EnrightField is mostly -/// intended for debugging (it's an analytical divergence free and -/// periodic field). They both share the same API required by the -/// LevelSetAdvection class defined below. Thus, any class with this -/// API should work with LevelSetAdvection. - -/// Note the Field wrapper classes below always assume the velocity -/// is represented in the world-frame of reference. For DiscreteField -/// this implies the input grid must contain velocities in world -/// coordinates. - -/// @brief Thin wrapper class for a velocity grid -/// @note Consider replacing BoxSampler with StaggeredBoxSampler -template -class DiscreteField -{ -public: - typedef typename VelGridT::ValueType VectorType; - typedef typename VectorType::ValueType ScalarType; - - DiscreteField(const VelGridT &vel): mAccessor(vel.tree()), mTransform(&vel.transform()) {} - - /// @return const reference to the transfrom between world and index space - /// @note Use this method to determine if a client grid is - /// aligned with the coordinate space of the velocity grid. - const math::Transform& transform() const { return *mTransform; } - - /// @return the interpolated velocity at the world space position xyz - inline VectorType operator() (const Vec3d& xyz, ScalarType) const - { - VectorType result = zeroVal(); - Interpolator::sample(mAccessor, mTransform->worldToIndex(xyz), result); - return result; - } - - /// @return the velocity at the coordinate space position ijk - inline VectorType operator() (const Coord& ijk, ScalarType) const - { - return mAccessor.getValue(ijk); - } - -private: - const typename VelGridT::ConstAccessor mAccessor;//Not thread-safe - const math::Transform* mTransform; - -}; // end of DiscreteField - -/// @brief Analytical, divergence-free and periodic vecloity field -/// @note Primarily intended for debugging! -/// @warning This analytical velocity only produce meaningfull values -/// in the unitbox in world space. In other words make sure any level -/// set surface in fully enclodes in the axis aligned bounding box -/// spanning 0->1 in world units. -template -class EnrightField -{ -public: - typedef ScalarT ScalarType; - typedef math::Vec3 VectorType; - - EnrightField() {} - - /// @return const reference to the identity transfrom between world and index space - /// @note Use this method to determine if a client grid is - /// aligned with the coordinate space of this velocity field - math::Transform transform() const { return math::Transform(); } - - /// @return the velocity in world units, evaluated at the world - /// position xyz and at the specified time - inline VectorType operator() (const Vec3d& xyz, ScalarType time) const; - - /// @return the velocity at the coordinate space position ijk - inline VectorType operator() (const Coord& ijk, ScalarType time) const - { - return (*this)(ijk.asVec3d(), time); - } -}; // end of EnrightField - -/// @brief Hyperbolic advection of narrow-band level sets in an -/// external velocity field -/// -/// The @c FieldType template argument below refers to any functor -/// with the following interface (see tools/VelocityFields.h -/// for examples): -/// -/// @code -/// class VelocityField { -/// ... -/// public: -/// openvdb::VectorType operator() (const openvdb::Coord& xyz, ScalarType time) const; -/// ... -/// }; -/// @endcode -/// -/// @note The functor method returns the velocity field at coordinate -/// position xyz of the advection grid, and for the specified -/// time. Note that since the velocity is returned in the local -/// coordinate space of the grid that is being advected, the functor -/// typically depends on the transformation of that grid. This design -/// is chosen for performance reasons. -/// -/// The @c InterruptType template argument below refers to any class -/// with the following interface: -/// @code -/// class Interrupter { -/// ... -/// public: -/// void start(const char* name = NULL)// called when computations begin -/// void end() // called when computations end -/// bool wasInterrupted(int percent=-1)// return true to break computation -///}; -/// @endcode -/// -/// @note If no template argument is provided for this InterruptType -/// the util::NullInterrupter is used which implies that all -/// interrupter calls are no-ops (i.e. incurs no computational overhead). -/// - -template, - typename InterruptT = util::NullInterrupter> -class LevelSetAdvection -{ -public: - typedef GridT GridType; - typedef LevelSetTracker TrackerT; - typedef typename TrackerT::RangeType RangeType; - typedef typename TrackerT::LeafType LeafType; - typedef typename TrackerT::BufferType BufferType; - typedef typename TrackerT::ValueType ScalarType; - typedef typename FieldT::VectorType VectorType; - - /// Main constructor - LevelSetAdvection(GridT& grid, const FieldT& field, InterruptT* interrupt = NULL): - mTracker(grid, interrupt), mField(field), - mSpatialScheme(math::HJWENO5_BIAS), - mTemporalScheme(math::TVD_RK2) {} - - virtual ~LevelSetAdvection() {}; - - /// @return the spatial finite difference scheme - math::BiasedGradientScheme getSpatialScheme() const { return mSpatialScheme; } - /// @brief Set the spatial finite difference scheme - void setSpatialScheme(math::BiasedGradientScheme scheme) { mSpatialScheme = scheme; } - - /// @return the temporal integration scheme - math::TemporalIntegrationScheme getTemporalScheme() const { return mTemporalScheme; } - /// @brief Set the spatial finite difference scheme - void setTemporalScheme(math::TemporalIntegrationScheme scheme) { mTemporalScheme = scheme; } - - /// @return the spatial finite difference scheme - math::BiasedGradientScheme getTrackerSpatialScheme() const { return mTracker.getSpatialScheme(); } - /// @brief Set the spatial finite difference scheme - void setTrackerSpatialScheme(math::BiasedGradientScheme scheme) { mTracker.setSpatialScheme(scheme); } - - /// @return the temporal integration scheme - math::TemporalIntegrationScheme getTrackerTemporalScheme() const { return mTracker.getTemporalScheme(); } - /// @brief Set the spatial finite difference scheme - void setTrackerTemporalScheme(math::TemporalIntegrationScheme scheme) { mTracker.setTemporalScheme(scheme); } - - /// @return The number of normalizations performed per track or - /// normalize call. - int getNormCount() const { return mTracker.getNormCount(); } - /// @brief Set the number of normalizations performed per track or - /// normalize call. - void setNormCount(int n) { mTracker.setNormCount(n); } - - /// @return the grain-size used for multi-threading - int getGrainSize() const { return mTracker.getGrainSize(); } - /// @brief Set the grain-size used for multi-threading. - /// @note A grainsize of 0 or less disables multi-threading! - void setGrainSize(int grainsize) { mTracker.setGrainSize(grainsize); } - - /// Advect the level set from it's current time, time0, to it's - /// final time, time1. If time0>time1 backward advection is performed. - /// - /// @return number of CFL iterations used to advect from time0 to time1 - size_t advect(ScalarType time0, ScalarType time1); - -private: - - // This templated private class implements all the level set magic. - template - class LevelSetAdvect - { - public: - /// Main constructor - LevelSetAdvect(LevelSetAdvection& parent); - /// Shallow copy constructor called by tbb::parallel_for() threads - LevelSetAdvect(const LevelSetAdvect& other); - /// Shallow copy constructor called by tbb::parallel_reduce() threads - LevelSetAdvect(LevelSetAdvect& other, tbb::split); - /// destructor - virtual ~LevelSetAdvect() {if (mIsMaster) this->clearField();}; - /// Advect the level set from it's current time, time0, to it's final time, time1. - /// @return number of CFL iterations - size_t advect(ScalarType time0, ScalarType time1); - /// Used internally by tbb::parallel_for() - void operator()(const RangeType& r) const - { - if (mTask) mTask(const_cast(this), r); - else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly"); - } - /// Used internally by tbb::parallel_reduce() - void operator()(const RangeType& r) - { - if (mTask) mTask(this, r); - else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly"); - } - /// This is only called by tbb::parallel_reduce() threads - void join(const LevelSetAdvect& other) { mMaxAbsV = math::Max(mMaxAbsV, other.mMaxAbsV); } - private: - typedef typename boost::function FuncType; - LevelSetAdvection& mParent; - VectorType** mVec; - const ScalarType mMinAbsV; - ScalarType mMaxAbsV; - const MapT* mMap; - FuncType mTask; - const bool mIsMaster; - /// Enum to defeing the type of multi-threading - enum ThreadingMode { PARALLEL_FOR, PARALLEL_REDUCE }; // for internal use - // method calling tbb - void cook(ThreadingMode mode, size_t swapBuffer = 0); - /// Sample field and return the CFT time step - typename GridT::ValueType sampleField(ScalarType time0, ScalarType time1); - void clearField(); - void sampleXformedField(const RangeType& r, ScalarType time0, ScalarType time1); - void sampleAlignedField(const RangeType& r, ScalarType time0, ScalarType time1); - // Forward Euler advection steps: Phi(result) = Phi(0) - dt * V.Grad(0); - void euler1(const RangeType& r, ScalarType dt, Index resultBuffer); - // Convex combination of Phi and a forward Euler advection steps: - // Phi(result) = alpha * Phi(phi) + (1-alpha) * (Phi(0) - dt * V.Grad(0)); - void euler2(const RangeType& r, ScalarType dt, ScalarType alpha, Index phiBuffer, Index resultBuffer); - }; // end of private LevelSetAdvect class - - template - size_t advect1(ScalarType time0, ScalarType time1); - - template - size_t advect2(ScalarType time0, ScalarType time1); - - template - size_t advect3(ScalarType time0, ScalarType time1); - - TrackerT mTracker; - //each thread needs a deep copy of the field since it might contain a ValueAccessor - const FieldT mField; - math::BiasedGradientScheme mSpatialScheme; - math::TemporalIntegrationScheme mTemporalScheme; - - // disallow copy by assignment - void operator=(const LevelSetAdvection& other) {} - -};//end of LevelSetAdvection - -template -inline size_t -LevelSetAdvection::advect(ScalarType time0, ScalarType time1) -{ - switch (mSpatialScheme) { - case math::FIRST_BIAS: - return this->advect1(time0, time1); - case math::SECOND_BIAS: - return this->advect1(time0, time1); - case math::THIRD_BIAS: - return this->advect1(time0, time1); - case math::WENO5_BIAS: - return this->advect1(time0, time1); - case math::HJWENO5_BIAS: - return this->advect1(time0, time1); - default: - OPENVDB_THROW(ValueError, "Spatial difference scheme not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetAdvection::advect1(ScalarType time0, ScalarType time1) -{ - switch (mTemporalScheme) { - case math::TVD_RK1: - return this->advect2(time0, time1); - case math::TVD_RK2: - return this->advect2(time0, time1); - case math::TVD_RK3: - return this->advect2(time0, time1); - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetAdvection::advect2(ScalarType time0, ScalarType time1) -{ - const math::Transform& trans = mTracker.grid().transform(); - if (trans.mapType() == math::UniformScaleMap::mapType()) { - return this->advect3(time0, time1); - } else if (trans.mapType() == math::UniformScaleTranslateMap::mapType()) { - return this->advect3(time0, time1); - } else if (trans.mapType() == math::UnitaryMap::mapType()) { - return this->advect3(time0, time1); - } else if (trans.mapType() == math::TranslationMap::mapType()) { - return this->advect3(time0, time1); - } else { - OPENVDB_THROW(ValueError, "MapType not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetAdvection::advect3(ScalarType time0, ScalarType time1) -{ - LevelSetAdvect tmp(*this); - return tmp.advect(time0, time1); -} - -/////////////////////////////////////////////////////////////////////// - -template -inline math::Vec3 -EnrightField::operator() (const Vec3d& xyz, ScalarType time) const -{ - const ScalarT pi = boost::math::constants::pi(); - const ScalarT phase = pi / ScalarT(3.0); - const ScalarT Px = pi * ScalarT(xyz[0]), Py = pi * ScalarT(xyz[1]), Pz = pi * ScalarT(xyz[2]); - const ScalarT tr = cos(ScalarT(time) * phase); - const ScalarT a = sin(ScalarT(2.0)*Py); - const ScalarT b = -sin(ScalarT(2.0)*Px); - const ScalarT c = sin(ScalarT(2.0)*Pz); - return math::Vec3( - tr * ( ScalarT(2) * math::Pow2(sin(Px)) * a * c ), - tr * ( b * math::Pow2(sin(Py)) * c ), - tr * ( b * a * math::Pow2(sin(Pz)) )); -} - - -/////////////////////////////////////////////////////////////////////// - - -template -template -inline -LevelSetAdvection:: -LevelSetAdvect:: -LevelSetAdvect(LevelSetAdvection& parent): - mParent(parent), - mVec(NULL), - mMinAbsV(ScalarType(1e-6)), - mMap(parent.mTracker.grid().transform().template constMap().get()), - mTask(0), - mIsMaster(true) -{ -} - -template -template -inline -LevelSetAdvection:: -LevelSetAdvect:: -LevelSetAdvect(const LevelSetAdvect& other): - mParent(other.mParent), - mVec(other.mVec), - mMinAbsV(other.mMinAbsV), - mMaxAbsV(other.mMaxAbsV), - mMap(other.mMap), - mTask(other.mTask), - mIsMaster(false) -{ -} - -template -template -inline -LevelSetAdvection:: -LevelSetAdvect:: -LevelSetAdvect(LevelSetAdvect& other, tbb::split): - mParent(other.mParent), - mVec(other.mVec), - mMinAbsV(other.mMinAbsV), - mMaxAbsV(other.mMaxAbsV), - mMap(other.mMap), - mTask(other.mTask), - mIsMaster(false) -{ -} - -template -template -inline size_t -LevelSetAdvection:: -LevelSetAdvect:: -advect(ScalarType time0, ScalarType time1) -{ - size_t countCFL = 0; - if ( math::isZero(time0 - time1) ) return countCFL; - const bool isForward = time0 < time1; - while ((isForward ? time0time1) && mParent.mTracker.checkInterrupter()) { - /// Make sure we have enough temporal auxiliary buffers - mParent.mTracker.leafs().rebuildAuxBuffers(TemporalScheme == math::TVD_RK3 ? 2 : 1); - - const ScalarType dt = this->sampleField(time0, time1); - if ( math::isZero(dt) ) break;//V is essentially zero so terminate - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN //switch is resolved at compile-time - switch(TemporalScheme) { - case math::TVD_RK1: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(0) - mTask = boost::bind(&LevelSetAdvect::euler1, _1, _2, dt, /*result=*/1); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - break; - case math::TVD_RK2: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(0) - mTask = boost::bind(&LevelSetAdvect::euler1, _1, _2, dt, /*result=*/1); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - - // Convex combine explict Euler step: t2 = t0 + dt - // Phi_t2(1) = 1/2 * Phi_t0(1) + 1/2 * (Phi_t1(0) - dt * V.Grad_t1(0)) - mTask = boost::bind(&LevelSetAdvect::euler2, _1, _2, dt, ScalarType(0.5), /*phi=*/1, /*result=*/1); - // Cook and swap buffer 0 and 1 such that Phi_t2(0) and Phi_t1(1) - this->cook(PARALLEL_FOR, 1); - break; - case math::TVD_RK3: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(0) - mTask = boost::bind(&LevelSetAdvect::euler1, _1, _2, dt, /*result=*/1); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - - // Convex combine explict Euler step: t2 = t0 + dt/2 - // Phi_t2(2) = 3/4 * Phi_t0(1) + 1/4 * (Phi_t1(0) - dt * V.Grad_t1(0)) - mTask = boost::bind(&LevelSetAdvect::euler2, _1, _2, dt, ScalarType(0.75), /*phi=*/1, /*result=*/2); - // Cook and swap buffer 0 and 2 such that Phi_t2(0) and Phi_t1(2) - this->cook(PARALLEL_FOR, 2); - - // Convex combine explict Euler step: t3 = t0 + dt - // Phi_t3(2) = 1/3 * Phi_t0(1) + 2/3 * (Phi_t2(0) - dt * V.Grad_t2(0) - mTask = boost::bind(&LevelSetAdvect::euler2, _1, _2, dt, ScalarType(1.0/3.0), /*phi=*/1, /*result=*/2); - // Cook and swap buffer 0 and 2 such that Phi_t3(0) and Phi_t2(2) - this->cook(PARALLEL_FOR, 2); - break; - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - }//end of compile-time resolved switch - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - - time0 += isForward ? dt : -dt; - ++countCFL; - mParent.mTracker.leafs().removeAuxBuffers(); - this->clearField(); - /// Track the narrow band - mParent.mTracker.track(); - }//end wile-loop over time - return countCFL;//number of CLF propagation steps -} - -template -template -inline typename GridT::ValueType -LevelSetAdvection:: -LevelSetAdvect:: -sampleField(ScalarType time0, ScalarType time1) -{ - mMaxAbsV = mMinAbsV; - const size_t leafCount = mParent.mTracker.leafs().leafCount(); - if (leafCount==0) return ScalarType(0.0); - mVec = new VectorType*[leafCount]; - if (mParent.mField.transform() == mParent.mTracker.grid().transform()) { - mTask = boost::bind(&LevelSetAdvect::sampleAlignedField, _1, _2, time0, time1); - } else { - mTask = boost::bind(&LevelSetAdvect::sampleXformedField, _1, _2, time0, time1); - } - this->cook(PARALLEL_REDUCE); - if (math::isExactlyEqual(mMinAbsV, mMaxAbsV)) return ScalarType(0.0);//V is essentially zero -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const ScalarType CFL = (TemporalScheme == math::TVD_RK1 ? ScalarType(0.3) : - TemporalScheme == math::TVD_RK2 ? ScalarType(0.9) : - ScalarType(1.0))/math::Sqrt(ScalarType(3.0)); - const ScalarType dt = math::Abs(time1 - time0), dx = mParent.mTracker.voxelSize(); - return math::Min(dt, ScalarType(CFL*dx/math::Sqrt(mMaxAbsV))); -} - -template -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -sampleXformedField(const RangeType& range, ScalarType time0, ScalarType time1) -{ - const bool isForward = time0 < time1; - typedef typename LeafType::ValueOnCIter VoxelIterT; - const MapT& map = *mMap; - mParent.mTracker.checkInterrupter(); - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - const LeafType& leaf = mParent.mTracker.leafs().leaf(n); - VectorType* vec = new VectorType[leaf.onVoxelCount()]; - int m = 0; - for (VoxelIterT iter = leaf.cbeginValueOn(); iter; ++iter, ++m) { - const VectorType V = mParent.mField(map.applyMap(iter.getCoord().asVec3d()), time0); - mMaxAbsV = math::Max(mMaxAbsV, ScalarType(math::Pow2(V[0])+math::Pow2(V[1])+math::Pow2(V[2]))); - vec[m] = isForward ? V : -V; - } - mVec[n] = vec; - } -} - -template -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -sampleAlignedField(const RangeType& range, ScalarType time0, ScalarType time1) -{ - const bool isForward = time0 < time1; - typedef typename LeafType::ValueOnCIter VoxelIterT; - mParent.mTracker.checkInterrupter(); - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - const LeafType& leaf = mParent.mTracker.leafs().leaf(n); - VectorType* vec = new VectorType[leaf.onVoxelCount()]; - int m = 0; - for (VoxelIterT iter = leaf.cbeginValueOn(); iter; ++iter, ++m) { - const VectorType V = mParent.mField(iter.getCoord(), time0); - mMaxAbsV = math::Max(mMaxAbsV, ScalarType(math::Pow2(V[0])+math::Pow2(V[1])+math::Pow2(V[2]))); - vec[m] = isForward ? V : -V; - } - mVec[n] = vec; - } -} - -template -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -clearField() -{ - if (mVec == NULL) return; - for (size_t n=0, e=mParent.mTracker.leafs().leafCount(); n -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -cook(ThreadingMode mode, size_t swapBuffer) -{ - mParent.mTracker.startInterrupter("Advecting level set"); - - if (mParent.mTracker.getGrainSize()==0) { - (*this)(mParent.mTracker.leafs().getRange()); - } else if (mode == PARALLEL_FOR) { - tbb::parallel_for(mParent.mTracker.leafs().getRange(mParent.mTracker.getGrainSize()), *this); - } else if (mode == PARALLEL_REDUCE) { - tbb::parallel_reduce(mParent.mTracker.leafs().getRange(mParent.mTracker.getGrainSize()), *this); - } else { - throw std::runtime_error("Undefined threading mode"); - } - - mParent.mTracker.leafs().swapLeafBuffer(swapBuffer, mParent.mTracker.getGrainSize()==0); - - mParent.mTracker.endInterrupter(); -} - -// Forward Euler advection steps: -// Phi(result) = Phi(0) - dt * V.Grad(0); -template -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -euler1(const RangeType& range, ScalarType dt, Index resultBuffer) -{ - typedef math::BIAS_SCHEME Scheme; - typedef typename Scheme::template ISStencil::StencilType Stencil; - typedef typename LeafType::ValueOnCIter VoxelIterT; - mParent.mTracker.checkInterrupter(); - const MapT& map = *mMap; - typename TrackerT::LeafManagerType& leafs = mParent.mTracker.leafs(); - Stencil stencil(mParent.mTracker.grid()); - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - BufferType& result = leafs.getBuffer(n, resultBuffer); - const VectorType* vec = mVec[n]; - int m=0; - for (VoxelIterT iter = leafs.leaf(n).cbeginValueOn(); iter; ++iter, ++m) { - stencil.moveTo(iter); - const VectorType V = vec[m], G = math::GradientBiased::result(map, stencil, V); - result.setValue(iter.pos(), *iter - dt * V.dot(G)); - } - } -} - -// Convex combination of Phi and a forward Euler advection steps: -// Phi(result) = alpha * Phi(phi) + (1-alpha) * (Phi(0) - dt * V.Grad(0)); -template -template -inline void -LevelSetAdvection:: -LevelSetAdvect:: -euler2(const RangeType& range, ScalarType dt, ScalarType alpha, Index phiBuffer, Index resultBuffer) -{ - typedef math::BIAS_SCHEME Scheme; - typedef typename Scheme::template ISStencil::StencilType Stencil; - typedef typename LeafType::ValueOnCIter VoxelIterT; - mParent.mTracker.checkInterrupter(); - const MapT& map = *mMap; - typename TrackerT::LeafManagerType& leafs = mParent.mTracker.leafs(); - const ScalarType beta = ScalarType(1.0) - alpha; - Stencil stencil(mParent.mTracker.grid()); - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - const BufferType& phi = leafs.getBuffer(n, phiBuffer); - BufferType& result = leafs.getBuffer(n, resultBuffer); - const VectorType* vec = mVec[n]; - int m=0; - for (VoxelIterT iter = leafs.leaf(n).cbeginValueOn(); iter; ++iter, ++m) { - stencil.moveTo(iter); - const VectorType V = vec[m], G = math::GradientBiased::result(map, stencil, V); - result.setValue(iter.pos(), alpha*phi[iter.pos()] + beta*(*iter - dt * V.dot(G))); - } - } -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVEL_SET_ADVECT_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetFilter.h b/openvdb_3_0_0_library/tools/LevelSetFilter.h deleted file mode 100755 index 1542b66..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetFilter.h +++ /dev/null @@ -1,527 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file LevelSetFilter.h -/// -/// @brief Performs various types of level set deformations with -/// interface tracking. These unrestricted deformations include -/// surface smoothing (e.g., Laplacian flow), filtering (e.g., mean -/// value) and morphological operations (e.g., morphological opening). -/// All these operations can optionally be masked with another grid that -/// acts as an alpha-mask. - -#ifndef OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED - -#include -#include -#include "LevelSetTracker.h" -#include "Interpolation.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Filtering (e.g. diffusion) of narrow-band level sets. An -/// optional scalar field can be used to produce a (smooth) alpha mask -/// for the filtering. -/// -/// @note This class performs propper interface tracking which allows -/// for unrestricted surface deformations -template::Type, - typename InterruptT = util::NullInterrupter> -class LevelSetFilter : public LevelSetTracker -{ -public: - typedef LevelSetTracker BaseType; - typedef GridT GridType; - typedef MaskT MaskType; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename MaskType::ValueType AlphaType; - typedef typename tree::LeafManager::LeafRange RangeType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Main constructor from a grid - /// @param grid The level set to be filtered. - /// @param interrupt Optional interrupter. - LevelSetFilter(GridType& grid, InterruptT* interrupt = NULL) - : BaseType(grid, interrupt) - , mTask(0) - , mMask(NULL) - , mMinMask(0) - , mMaxMask(1) - , mInvertMask(false) - { - } - /// @brief Shallow copy constructor called by tbb::parallel_for() - /// threads during filtering. - /// @param other The other LevelSetFilter from which to copy. - LevelSetFilter(const LevelSetFilter& other) - : BaseType(other) - , mTask(other.mTask) - , mMask(other.mMask) - , mMinMask(other.mMinMask) - , mMaxMask(other.mMaxMask) - , mInvertMask(other.mInvertMask) - { - } - /// @brief Destructor - virtual ~LevelSetFilter() {}; - - /// @brief Used internally by tbb::parallel_for(). - /// @param range The range over which to perform multi-threading. - /// @warning Never call this method directly! - void operator()(const RangeType& range) const - { - if (mTask) mTask(const_cast(this), range); - else OPENVDB_THROW(ValueError, "task is undefined - call offset(), etc"); - } - - /// @brief Return the minimum value of the mask to be used for the - /// derivation of a smooth alpha value. - AlphaType minMask() const { return mMinMask; } - /// @brief Return the maximum value of the mask to be used for the - /// derivation of a smooth alpha value. - AlphaType maxMask() const { return mMaxMask; } - /// @brief Define the range for the (optional) scalar mask. - /// @param min Minimum value of the range. - /// @param max Maximum value of the range. - /// @details Mask values outside the range maps to alpha values of - /// respectfully zero and one, and values inside the range maps - /// smoothly to 0->1 (unless of course the mask is inverted). - /// @throw ValueError if @a min is not smaller then @a max. - void setMaskRange(AlphaType min, AlphaType max) - { - if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)"); - mMinMask = min; - mMaxMask = max; - } - - /// @brief Return true if the mask is inverted, i.e. min->max in the - /// original mask maps to 1->0 in the inverted alpha mask. - bool isMaskInverted() const { return mInvertMask; } - /// @brief Invert the optional mask, i.e. min->max in the original - /// mask maps to 1->0 in the inverted alpha mask. - void invertMask(bool invert=true) { mInvertMask = invert; } - - /// @brief One iteration of mean-curvature flow of the level set. - /// @param mask Optional alpha mask. - void meanCurvature(const MaskType* mask = NULL); - - /// @brief One iteration of laplacian flow of the level set. - /// @param mask Optional alpha mask. - void laplacian(const MaskType* mask = NULL); - - /// @brief One iteration of a fast separable gaussian filter. - /// @param width Width of the gaussian kernel in voxel units. - /// @param mask Optional alpha mask. - /// - /// @note This is approximated as 4 iterations of a separable mean filter - /// which typically leads an approximation that's better than 95%! - void gaussian(int width = 1, const MaskType* mask = NULL); - - /// @brief Offset the level set by the specified (world) distance. - /// @param offset Value of the offset. - /// @param mask Optional alpha mask. - void offset(ValueType offset, const MaskType* mask = NULL); - - /// @brief One iteration of median-value flow of the level set. - /// @param width Width of the median-value kernel in voxel units. - /// @param mask Optional alpha mask. - /// - /// @warning This filter is not separable and is hence relatively - /// slow! - void median(int width = 1, const MaskType* mask = NULL); - - /// @brief One iteration of mean-value flow of the level set. - /// @param width Width of the mean-value kernel in voxel units. - /// @param mask Optional alpha mask. - /// - /// @note This filter is separable so it's fast! - void mean(int width = 1, const MaskType* mask = NULL); - -private: - typedef typename TreeType::LeafNodeType LeafT; - typedef typename LeafT::ValueOnIter VoxelIterT; - typedef typename LeafT::ValueOnCIter VoxelCIterT; - typedef typename tree::LeafManager::BufferType BufferT; - typedef typename RangeType::Iterator LeafIterT; - typedef tools::AlphaMask AlphaMaskT; - - // Only two private member data - typename boost::function mTask; - const MaskType* mMask; - AlphaType mMinMask, mMaxMask; - bool mInvertMask; - - // Private cook method calling tbb::parallel_for - void cook(bool swap) - { - const int n = BaseType::getGrainSize(); - if (n>0) { - tbb::parallel_for(BaseType::leafs().leafRange(n), *this); - } else { - (*this)(BaseType::leafs().leafRange()); - } - if (swap) BaseType::leafs().swapLeafBuffer(1, n==0); - } - - // Private driver method for mean and gaussian filtering - void box(int width); - - template - struct Avg { - Avg(const GridT& grid, Int32 w) : - acc(grid.tree()), width(w), frac(1/ValueType(2*w+1)) - { - } - ValueType operator()(Coord xyz) - { - ValueType sum = zeroVal(); - Int32& i = xyz[Axis], j = i + width; - for (i -= width; i <= j; ++i) sum += acc.getValue(xyz); - return sum*frac; - } - typename GridT::ConstAccessor acc; - const Int32 width; - const ValueType frac; - }; - - // Private methods called by tbb::parallel_for threads - template - void doBox( const RangeType& r, Int32 w); - void doBoxX(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doBoxZ(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doBoxY(const RangeType& r, Int32 w) { this->doBox >(r,w); } - void doMedian(const RangeType&, int); - void doMeanCurvature(const RangeType&); - void doLaplacian(const RangeType&); - void doOffset(const RangeType&, ValueType); - -}; // end of LevelSetFilter class - - -//////////////////////////////////////// - -template -inline void -LevelSetFilter::median(int width, const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Median-value flow of level set"); - - BaseType::leafs().rebuildAuxBuffers(1, BaseType::getGrainSize()==0); - - mTask = boost::bind(&LevelSetFilter::doMedian, _1, _2, std::max(1, width)); - this->cook(true); - - BaseType::track(); - - BaseType::endInterrupter(); -} - -template -inline void -LevelSetFilter::mean(int width, const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Mean-value flow of level set"); - - this->box(width); - - BaseType::endInterrupter(); -} - -template -inline void -LevelSetFilter::gaussian(int width, const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Gaussian flow of level set"); - - for (int n=0; n<4; ++n) this->box(width); - - BaseType::endInterrupter(); -} - -template -inline void -LevelSetFilter::box(int width) -{ - BaseType::leafs().rebuildAuxBuffers(1, BaseType::getGrainSize()==0); - - width = std::max(1, width); - - mTask = boost::bind(&LevelSetFilter::doBoxX, _1, _2, width); - this->cook(true); - - mTask = boost::bind(&LevelSetFilter::doBoxY, _1, _2, width); - this->cook(true); - - mTask = boost::bind(&LevelSetFilter::doBoxZ, _1, _2, width); - this->cook(true); - - BaseType::track(); -} - -template -inline void -LevelSetFilter::meanCurvature(const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Mean-curvature flow of level set"); - - BaseType::leafs().rebuildAuxBuffers(1, BaseType::getGrainSize()==0); - - mTask = boost::bind(&LevelSetFilter::doMeanCurvature, _1, _2); - this->cook(true); - - BaseType::track(); - - BaseType::endInterrupter(); -} - -template -inline void -LevelSetFilter::laplacian(const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Laplacian flow of level set"); - - BaseType::leafs().rebuildAuxBuffers(1, BaseType::getGrainSize()==0); - - mTask = boost::bind(&LevelSetFilter::doLaplacian, _1, _2); - this->cook(true); - - BaseType::track(); - - BaseType::endInterrupter(); -} - -template -inline void -LevelSetFilter::offset(ValueType value, const MaskType* mask) -{ - mMask = mask; - - BaseType::startInterrupter("Offsetting level set"); - - BaseType::leafs().removeAuxBuffers();// no auxiliary buffers required - - const ValueType CFL = ValueType(0.5) * BaseType::voxelSize(), offset = openvdb::math::Abs(value); - ValueType dist = 0.0; - while (offset-dist > ValueType(0.001)*CFL && BaseType::checkInterrupter()) { - const ValueType delta = openvdb::math::Min(offset-dist, CFL); - dist += delta; - - mTask = boost::bind(&LevelSetFilter::doOffset, _1, _2, copysign(delta, value)); - this->cook(false); - - BaseType::track(); - } - - BaseType::endInterrupter(); -} - - -///////////////////////// PRIVATE METHODS ////////////////////// - -/// Performs parabolic mean-curvature diffusion -template -inline void -LevelSetFilter::doMeanCurvature(const RangeType& range) -{ - BaseType::checkInterrupter(); - //const float CFL = 0.9f, dt = CFL * mDx * mDx / 6.0f; - const ValueType dx = BaseType::voxelSize(), dt = math::Pow2(dx) / ValueType(3.0); - math::CurvatureStencil stencil(BaseType::grid(), dx); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(BaseType::grid(), *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) { - stencil.moveTo(iter); - const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.meanCurvatureNormGrad(); - buffer.setValue(iter.pos(), b*phi0 + a*phi1); - } - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), *iter + dt*stencil.meanCurvatureNormGrad()); - } - } - } -} - -/// Performs laplacian diffusion. Note if the grids contains a true -/// signed distance field (e.g. a solution to the Eikonal equation) -/// Laplacian diffusions (e.g. geometric heat equation) is actually -/// identical to mean curvature diffusion, yet less computationally -/// expensive! In other words if you're performing renormalization -/// anyway (e.g. rebuilding the narrow-band) you should consider -/// performing laplacian diffusion over mean curvature flow! -template -inline void -LevelSetFilter::doLaplacian(const RangeType& range) -{ - BaseType::checkInterrupter(); - //const float CFL = 0.9f, half_dt = CFL * mDx * mDx / 12.0f; - const ValueType dx = BaseType::voxelSize(), dt = math::Pow2(dx) / ValueType(6.0); - math::GradStencil stencil(BaseType::grid(), dx); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(BaseType::grid(), *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) { - stencil.moveTo(iter); - const ValueType phi0 = *iter, phi1 = phi0 + dt*stencil.laplacian(); - buffer.setValue(iter.pos(), b*phi0 + a*phi1); - } - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), *iter + dt*stencil.laplacian()); - } - } - } -} - -/// Offsets the values by a constant -template -inline void -LevelSetFilter::doOffset(const RangeType& range, ValueType offset) -{ - BaseType::checkInterrupter(); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(BaseType::grid(), *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) iter.setValue(*iter + a*offset); - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - for (VoxelIterT iter = leafIter->beginValueOn(); iter; ++iter) { - iter.setValue(*iter + offset); - } - } - } -} - -/// Performs simple but slow median-value diffusion -template -inline void -LevelSetFilter::doMedian(const RangeType& range, int width) -{ - BaseType::checkInterrupter(); - typename math::DenseStencil stencil(BaseType::grid(), width);//creates local cache! - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(BaseType::grid(), *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - if (alpha(iter.getCoord(), a, b)) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), b*(*iter) + a*stencil.median()); - } - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - stencil.moveTo(iter); - buffer.setValue(iter.pos(), stencil.median()); - } - } - } -} - -/// One dimensional convolution of a separable box filter -template -template -inline void -LevelSetFilter::doBox(const RangeType& range, Int32 w) -{ - BaseType::checkInterrupter(); - AvgT avg(BaseType::grid(), w); - if (mMask) { - typename AlphaMaskT::FloatType a, b; - AlphaMaskT alpha(BaseType::grid(), *mMask, mMinMask, mMaxMask, mInvertMask); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - const Coord xyz = iter.getCoord(); - if (alpha(xyz, a, b)) buffer.setValue(iter.pos(), b*(*iter)+ a*avg(xyz)); - } - } - } else { - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - BufferT& buffer = leafIter.buffer(1); - for (VoxelCIterT iter = leafIter->cbeginValueOn(); iter; ++iter) { - buffer.setValue(iter.pos(), avg(iter.getCoord())); - } - } - } -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETFILTER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetFracture.h b/openvdb_3_0_0_library/tools/LevelSetFracture.h deleted file mode 100755 index c5dc455..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetFracture.h +++ /dev/null @@ -1,362 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file tools/LevelSetFracture.h -/// -/// @brief Divide volumes represented by level set grids into multiple, -/// disjoint pieces by intersecting them with one or more "cutter" volumes, -/// also represented by level sets. - -#ifndef OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "Composite.h" // for csgIntersection() and csgDifference() -#include "GridTransformer.h" // for resampleToMatch() -#include "LevelSetUtil.h" // for MinMaxVoxel() -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Level set fracturing -template -class LevelSetFracture -{ -public: - typedef std::vector Vec3sList; - typedef std::vector QuatsList; - typedef std::list GridPtrList; - typedef typename GridPtrList::iterator GridPtrListIter; - - - /// @brief Default constructor - /// - /// @param interrupter optional interrupter object - explicit LevelSetFracture(InterruptType* interrupter = NULL); - - /// @brief Divide volumes represented by level set grids into multiple, - /// disjoint pieces by intersecting them with one or more "cutter" volumes, - /// also represented by level sets. - /// @details If desired, the process can be applied iteratively, so that - /// fragments created with one cutter are subdivided by other cutters. - /// - /// @note The incoming @a grids and the @a cutter are required to have matching - /// transforms and narrow band widths! - /// - /// @param grids list of grids to fracture. The residuals of the - /// fractured grids will remain in this list - /// @param cutter a level set grid to use as the cutter object - /// @param segment toggle to split disjoint fragments into their own grids - /// @param points optional list of world space points at which to instance the - /// cutter object (if null, use the cutter's current position only) - /// @param rotations optional list of custom rotations for each cutter instance - /// @param cutterOverlap toggle to allow consecutive cutter instances to fracture - /// previously generated fragments - void fracture(GridPtrList& grids, const GridType& cutter, bool segment = false, - const Vec3sList* points = NULL, const QuatsList* rotations = NULL, - bool cutterOverlap = true); - - /// Return a list of new fragments, not including the residuals from the input grids. - GridPtrList& fragments() { return mFragments; } - - /// Remove all elements from the fragment list. - void clear() { mFragments.clear(); } - -private: - // disallow copy by assignment - void operator=(const LevelSetFracture&) {} - - bool wasInterrupted(int percent = -1) const { - return mInterrupter && mInterrupter->wasInterrupted(percent); - } - - bool isValidFragment(GridType&) const; - void segmentFragments(GridPtrList&) const; - void process(GridPtrList&, const GridType& cutter); - - InterruptType* mInterrupter; - GridPtrList mFragments; -}; - - -//////////////////////////////////////// - - -// Internal utility objects and implementation details - -namespace internal { - -/// @brief Segmentation scheme, splits disjoint fragments into separate grids. -/// @note This is a temporary solution and it will be replaced soon. -template -inline std::vector -segment(GridType& grid, InterruptType* interrupter = NULL) -{ - typedef typename GridType::Ptr GridPtr; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::Ptr TreePtr; - typedef typename TreeType::ValueType ValueType; - - std::vector segments; - - while (grid.activeVoxelCount() > 0) { - - if (interrupter && interrupter->wasInterrupted()) break; - - // Deep copy the grid's metadata (tree and transform are shared) - GridPtr segment(new GridType(grid, ShallowCopy())); - // Make the transform unique and insert an empty tree - segment->setTransform(grid.transform().copy()); - TreePtr tree(new TreeType(grid.background())); - segment->setTree(tree); - - std::deque coordList; - coordList.push_back(grid.tree().beginLeaf()->beginValueOn().getCoord()); - - Coord ijk, n_ijk; - ValueType value; - - typename tree::ValueAccessor sourceAcc(grid.tree()); - typename tree::ValueAccessor targetAcc(segment->tree()); - - while (!coordList.empty()) { - - if (interrupter && interrupter->wasInterrupted()) break; - - ijk = coordList.back(); - coordList.pop_back(); - - if (!sourceAcc.probeValue(ijk, value)) continue; - if (targetAcc.isValueOn(ijk)) continue; - - targetAcc.setValue(ijk, value); - sourceAcc.setValueOff(ijk); - - for (int n = 0; n < 6; n++) { - n_ijk = ijk + util::COORD_OFFSETS[n]; - if (!targetAcc.isValueOn(n_ijk) && sourceAcc.isValueOn(n_ijk)) { - coordList.push_back(n_ijk); - } - } - } - - tools::pruneInactive(grid.tree()); - tools::signedFloodFill(segment->tree()); - segments.push_back(segment); - } - return segments; -} - -} // namespace internal - - -//////////////////////////////////////// - - -template -LevelSetFracture::LevelSetFracture(InterruptType* interrupter) - : mInterrupter(interrupter) - , mFragments() -{ -} - - -template -void -LevelSetFracture::fracture(GridPtrList& grids, const GridType& cutter, - bool segmentation, const Vec3sList* points, const QuatsList* rotations, bool cutterOverlap) -{ - // We can process all incoming grids with the same cutter instance, - // this optimization is enabled by the requirement of having matching - // transforms between all incoming grids and the cutter object. - if (points && points->size() != 0) { - - math::Transform::Ptr originalCutterTransform = cutter.transform().copy(); - GridType cutterGrid(cutter, ShallowCopy()); - - const bool hasInstanceRotations = - points && rotations && points->size() == rotations->size(); - - // for each instance point.. - for (size_t p = 0, P = points->size(); p < P; ++p) { - - int percent = int((float(p) / float(P)) * 100.0); - if (wasInterrupted(percent)) break; - - GridType instCutterGrid; - instCutterGrid.setTransform(originalCutterTransform->copy()); - math::Transform::Ptr xform = originalCutterTransform->copy(); - - if (hasInstanceRotations) { - const Vec3s& rot = (*rotations)[p].eulerAngles(math::XYZ_ROTATION); - xform->preRotate(rot[0], math::X_AXIS); - xform->preRotate(rot[1], math::Y_AXIS); - xform->preRotate(rot[2], math::Z_AXIS); - xform->postTranslate((*points)[p]); - } else { - xform->postTranslate((*points)[p]); - } - - cutterGrid.setTransform(xform); - - if (wasInterrupted()) break; - - // Since there is no scaling, use the generic resampler instead of - // the more expensive level set rebuild tool. - if (mInterrupter != NULL) { - doResampleToMatch(cutterGrid, instCutterGrid, *mInterrupter); - } else { - util::NullInterrupter interrupter; - doResampleToMatch(cutterGrid, instCutterGrid, interrupter); - } - - if (cutterOverlap && !mFragments.empty()) process(mFragments, instCutterGrid); - process(grids, instCutterGrid); - } - - } else { - // use cutter in place - if (cutterOverlap && !mFragments.empty()) process(mFragments, cutter); - process(grids, cutter); - } - - if (segmentation) { - segmentFragments(mFragments); - segmentFragments(grids); - } -} - - -template -bool -LevelSetFracture::isValidFragment(GridType& grid) const -{ - typedef typename GridType::TreeType TreeType; - if (grid.activeVoxelCount() < 27) return false; - - // Check if valid level-set - { - tree::LeafManager leafs(grid.tree()); - MinMaxVoxel minmax(leafs); - minmax.runParallel(); - - if ((minmax.minVoxel() < 0) == (minmax.maxVoxel() < 0)) return false; - } - - return true; -} - - -template -void -LevelSetFracture::segmentFragments(GridPtrList& grids) const -{ - GridPtrList newFragments; - - for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) { - - if (wasInterrupted()) break; - - std::vector segments = internal::segment(*(*it), mInterrupter); - for (size_t n = 0, N = segments.size(); n < N; ++n) { - - if (wasInterrupted()) break; - - if (isValidFragment(*segments[n])) { - newFragments.push_back(segments[n]); - } - } - } - - grids.swap(newFragments); -} - - -template -void -LevelSetFracture::process( - GridPtrList& grids, const GridType& cutter) -{ - typedef typename GridType::Ptr GridPtr; - - GridPtrList newFragments; - - for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) { - - if (wasInterrupted()) break; - - GridPtr grid = *it; - - // gen new fragment - GridPtr fragment = grid->deepCopy(); - csgIntersection(*fragment, *cutter.deepCopy()); - - if (wasInterrupted()) break; - - if (!isValidFragment(*fragment)) continue; - - // update residual - GridPtr residual = grid->deepCopy(); - csgDifference(*residual, *cutter.deepCopy()); - - if (wasInterrupted()) break; - - if (!isValidFragment(*residual)) continue; - - newFragments.push_back(fragment); - - grid->tree().clear(); - grid->tree().merge(residual->tree()); - } - - if (!newFragments.empty()) { - mFragments.splice(mFragments.end(), newFragments); - } -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetMeasure.h b/openvdb_3_0_0_library/tools/LevelSetMeasure.h deleted file mode 100755 index b02654e..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetMeasure.h +++ /dev/null @@ -1,560 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file LevelSetMeasure.h - -#ifndef OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include //for Pi -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Return the surface area of a narrow-band level set. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param useWorldSpace if true the area is computed in -/// world space units, else in voxel units. -/// -/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set. -template -inline Real -levelSetArea(const GridType& grid, bool useWorldSpace = true); - -/// @brief Return the volume of a narrow-band level set surface. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param useWorldSpace if true the volume is computed in -/// world space units, else in voxel units. -/// -/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set. -template -inline Real -levelSetVolume(const GridType& grid, bool useWorldSpace = true); - -/// @brief Compute the surface area and volume of a narrow-band level set. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param area surface area of the level set -/// @param volume volume of the level set surface -/// @param useWorldSpace if true the area and volume are computed in -/// world space units, else in voxel units. -/// -/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set. -template -inline void -levelSetMeasure(const GridType& grid, Real& area, Real& volume, bool useWorldSpace = true); - -/// @brief Compute the surface area and volume of a narrow-band level set. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param area surface area of the level set -/// @param volume volume of the level set surface -/// @param avgCurvature average mean curvature of the level set surface -/// @param useWorldSpace if true the area, volume and curvature are computed in -/// world space units, else in voxel units. -/// -/// @throw TypeError if @a grid is not scalar or not floating-point or not a level set. -template -inline void -levelSetMeasure(const GridType& grid, Real& area, Real& volume, Real& avgCurvature, - bool useWorldSpace = true); - -/// @brief Smeared-out and continuous Dirac Delta function. -template -class DiracDelta -{ -public: - DiracDelta(RealT eps) : mC(0.5/eps), mD(2*boost::math::constants::pi()*mC), mE(eps) {} - inline RealT operator()(RealT phi) const { return math::Abs(phi) > mE ? 0 : mC*(1+cos(mD*phi)); } -private: - const RealT mC, mD, mE; -}; - - -/// @brief Multi-threaded computation of surface area, volume and -/// average mean-curvature for narrow band level sets. -/// -/// @details To reduce the risk of round-off errors (primarily due to -/// catastrophic cancellation) and guarantee determinism during -/// multi-threading this class is implemented using parallel_for, and -/// delayed reduction of a sorted list. -template -class LevelSetMeasure -{ -public: - typedef GridT GridType; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename tree::LeafManager ManagerType; - typedef typename ManagerType::LeafRange RangeType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Main constructor from a grid - /// @param grid The level set to be measured. - /// @param interrupt Optional interrupter. - /// @throw RuntimeError if the grid is not a level set. - LevelSetMeasure(const GridType& grid, InterruptT* interrupt = NULL); - - LevelSetMeasure(ManagerType& leafs, Real Dx, InterruptT* interrupt); - - /// @brief Re-initialize using the specified grid. - void reinit(const GridType& grid); - - /// @brief Re-initialize using the specified LeafManager and voxelSize. - void reinit(ManagerType& leafs, Real dx); - - /// @brief Destructor - ~LevelSetMeasure() {} - - /// @return the grain-size used for multi-threading - int getGrainSize() const { return mGrainSize; } - - /// @brief Set the grain-size used for multi-threading. - /// @note A grainsize of 0 or less disables multi-threading! - void setGrainSize(int grainsize) { mGrainSize = grainsize; } - - /// @brief Compute the surface area and volume of the level - /// set. Use the last argument to specify the result in world or - /// voxel units. - /// @note This method is faster (about 3x) then the measure method - /// below that also computes the average mean-curvature. - void measure(Real& area, Real& volume, bool useWorldUnits = true); - - /// @brief Compute the surface area, volume, and average - /// mean-curvatue of the level set. Use the last argument to - /// specify the result in world or voxel units. - /// @note This method is slower (about 3x) then the measure method - /// above that only computes the area and volume. - void measure(Real& area, Real& volume, Real& avgMeanCurvature, bool useWorldUnits = true); - - /// @brief Used internally by tbb::parallel_reduce(). - /// @param range The range over which to perform multi-threading. - /// @warning Never call this method directly! - void operator()(const RangeType& range) const - { - if (mTask) mTask(const_cast(this), range); - else OPENVDB_THROW(ValueError, "task is undefined"); - } - -private: - typedef typename GridT::ConstAccessor AccT; - typedef typename TreeType::LeafNodeType LeafT; - typedef typename LeafT::ValueOnCIter VoxelCIterT; - typedef typename ManagerType::BufferType BufferT; - typedef typename RangeType::Iterator LeafIterT; - - AccT mAcc; - ManagerType* mLeafs; - InterruptT* mInterrupter; - double mDx; - double* mArray; - typename boost::function mTask; - int mGrainSize; - - // @brief Return false if the process was interrupted - bool checkInterrupter(); - - // Private methods called by tbb::parallel_reduce threads - void measure2( const RangeType& ); - - // Private methods called by tbb::parallel_reduce threads - void measure3( const RangeType& ); - - inline double reduce(double* first, double scale) - { - double* last = first + mLeafs->leafCount(); - tbb::parallel_sort(first, last);//reduces catastrophic cancellation - Real sum = 0.0; - while(first != last) sum += *first++; - return scale * sum; - } - -}; // end of LevelSetMeasure class - - -template -inline -LevelSetMeasure::LevelSetMeasure(const GridType& grid, InterruptT* interrupt) - : mAcc(grid.tree()) - , mLeafs(NULL) - , mInterrupter(interrupt) - , mDx(grid.voxelSize()[0]) - , mArray(NULL) - , mTask(0) - , mGrainSize(1) -{ - if (!grid.hasUniformVoxels()) { - OPENVDB_THROW(RuntimeError, - "The transform must have uniform scale for the LevelSetMeasure to function"); - } - if (grid.getGridClass() != GRID_LEVEL_SET) { - OPENVDB_THROW(RuntimeError, - "LevelSetMeasure only supports level sets;" - " try setting the grid class to \"level set\""); - } -} - - -template -inline -LevelSetMeasure::LevelSetMeasure( - ManagerType& leafs, Real dx, InterruptT* interrupt) - : mAcc(leafs.tree()) - , mLeafs(&leafs) - , mInterrupter(interrupt) - , mDx(dx) - , mArray(NULL) - , mTask(0) - , mGrainSize(1) -{ -} - -template -inline void -LevelSetMeasure::reinit(const GridType& grid) -{ - if (!grid.hasUniformVoxels()) { - OPENVDB_THROW(RuntimeError, - "The transform must have uniform scale for the LevelSetMeasure to function"); - } - if (grid.getGridClass() != GRID_LEVEL_SET) { - OPENVDB_THROW(RuntimeError, - "LevelSetMeasure only supports level sets;" - " try setting the grid class to \"level set\""); - } - mLeafs = NULL; - mAcc = grid.getConstAccessor(); - mDx = grid.voxelSize()[0]; -} - - -template -inline void -LevelSetMeasure::reinit(ManagerType& leafs, Real dx) -{ - mLeafs = &leafs; - mAcc = AccT(leafs.tree()); - mDx = dx; -} - -//////////////////////////////////////// - - -template -inline void -LevelSetMeasure::measure(Real& area, Real& volume, bool useWorldUnits) -{ - if (mInterrupter) mInterrupter->start("Measuring level set"); - mTask = boost::bind(&LevelSetMeasure::measure2, _1, _2); - - const bool newLeafs = mLeafs == NULL; - if (newLeafs) mLeafs = new ManagerType(mAcc.tree()); - const size_t leafCount = mLeafs->leafCount(); - if (leafCount == 0) { - area = volume = 0; - return; - } - mArray = new double[2*leafCount]; - - if (mGrainSize>0) { - tbb::parallel_for(mLeafs->leafRange(mGrainSize), *this); - } else { - (*this)(mLeafs->leafRange()); - } - - const double dx = useWorldUnits ? mDx : 1.0; - area = this->reduce(mArray, math::Pow2(dx)); - volume = this->reduce(mArray + leafCount, math::Pow3(dx) / 3.0); - - if (newLeafs) { - delete mLeafs; - mLeafs = NULL; - } - delete [] mArray; - - if (mInterrupter) mInterrupter->end(); -} - - -template -inline void -LevelSetMeasure::measure(Real& area, Real& volume, Real& avgMeanCurvature, - bool useWorldUnits) -{ - if (mInterrupter) mInterrupter->start("Measuring level set"); - mTask = boost::bind(&LevelSetMeasure::measure3, _1, _2); - - const bool newLeafs = mLeafs == NULL; - if (newLeafs) mLeafs = new ManagerType(mAcc.tree()); - const size_t leafCount = mLeafs->leafCount(); - if (leafCount == 0) { - area = volume = avgMeanCurvature = 0; - return; - } - mArray = new double[3*leafCount]; - - if (mGrainSize>0) { - tbb::parallel_for(mLeafs->leafRange(mGrainSize), *this); - } else { - (*this)(mLeafs->leafRange()); - } - - const double dx = useWorldUnits ? mDx : 1.0; - area = this->reduce(mArray, math::Pow2(dx)); - volume = this->reduce(mArray + leafCount, math::Pow3(dx) / 3.0); - avgMeanCurvature = this->reduce(mArray + 2*leafCount, dx/area); - - if (newLeafs) { - delete mLeafs; - mLeafs = NULL; - } - delete [] mArray; - - if (mInterrupter) mInterrupter->end(); -} - - -///////////////////////// PRIVATE METHODS ////////////////////// - - -template -inline bool -LevelSetMeasure::checkInterrupter() -{ - if (util::wasInterrupted(mInterrupter)) { - tbb::task::self().cancel_group_execution(); - return false; - } - return true; -} - -template -inline void -LevelSetMeasure::measure2(const RangeType& range) -{ - typedef math::Vec3 Vec3T; - typedef math::ISGradient Grad; - this->checkInterrupter(); - const Real invDx = 1.0/mDx; - const DiracDelta DD(1.5); - const size_t leafCount = mLeafs->leafCount(); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - Real sumA = 0, sumV = 0;//reduce risk of catastrophic cancellation - for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Real dd = DD(invDx * (*voxelIter)); - if (dd > 0.0) { - const Coord p = voxelIter.getCoord(); - const Vec3T g = invDx*Grad::result(mAcc, p);//voxel units - sumA += dd * g.dot(g); - sumV += dd * (g[0]*p[0]+g[1]*p[1]+g[2]*p[2]); - } - } - double* v = mArray + leafIter.pos(); - *v = sumA; - v += leafCount; - *v = sumV; - } -} - - -template -inline void -LevelSetMeasure::measure3(const RangeType& range) -{ - typedef math::Vec3 Vec3T; - typedef math::ISGradient Grad; - typedef math::ISMeanCurvature Curv; - this->checkInterrupter(); - const Real invDx = 1.0/mDx; - const DiracDelta DD(1.5); - ValueType alpha, beta; - const size_t leafCount = mLeafs->leafCount(); - for (LeafIterT leafIter=range.begin(); leafIter; ++leafIter) { - Real sumA = 0, sumV = 0, sumC = 0;//reduce risk of catastrophic cancellation - for (VoxelCIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Real dd = DD(invDx * (*voxelIter)); - if (dd > 0.0) { - const Coord p = voxelIter.getCoord(); - const Vec3T g = invDx*Grad::result(mAcc, p);//voxel units - const Real dA = dd * g.dot(g); - sumA += dA; - sumV += dd * (g[0]*p[0]+g[1]*p[1]+g[2]*p[2]); - Curv::result(mAcc, p, alpha, beta); - sumC += dA * alpha/(2*math::Pow2(beta))*invDx; - } - } - double* v = mArray + leafIter.pos(); - *v = sumA; - v += leafCount; - *v = sumV; - v += leafCount; - *v = sumC; - } -} - -//////////////////////////////////////// - -template -inline typename boost::enable_if, Real>::type -doLevelSetArea(const GridT& grid, bool useWorldSpace) -{ - Real area, volume; - LevelSetMeasure m(grid); - m.measure(area, volume, useWorldSpace); - return area; -} - -template -inline typename boost::disable_if, Real>::type -doLevelSetArea(const GridT&, bool) -{ - OPENVDB_THROW(TypeError, - "level set area is supported only for scalar, floating-point grids"); -} - -template -inline Real -levelSetArea(const GridT& grid, bool useWorldSpace) -{ - return doLevelSetArea(grid, useWorldSpace); -} - -//////////////////////////////////////// - -template -inline typename boost::enable_if, Real>::type -doLevelSetVolume(const GridT& grid, bool useWorldSpace) -{ - Real area, volume; - LevelSetMeasure m(grid); - m.measure(area, volume, useWorldSpace); - return volume; -} - -template -inline typename boost::disable_if, Real>::type -doLevelSetVolume(const GridT&, bool) -{ - OPENVDB_THROW(TypeError, - "level set volume is supported only for scalar, floating-point grids"); -} - -template -inline Real -levelSetVolume(const GridT& grid, bool useWorldSpace) -{ - return doLevelSetVolume(grid, useWorldSpace); -} - -//////////////////////////////////////// - -template -inline typename boost::enable_if >::type -doLevelSetMeasure(const GridT& grid, Real& area, Real& volume, bool useWorldSpace) -{ - LevelSetMeasure m(grid); - m.measure(area, volume, useWorldSpace); -} - -template -inline typename boost::disable_if >::type -doLevelSetMeasure(const GridT&, Real&, Real&, bool) -{ - OPENVDB_THROW(TypeError, - "level set measure is supported only for scalar, floating-point grids"); -} - -template -inline void -levelSetMeasure(const GridT& grid, Real& area, Real& volume, bool useWorldSpace) -{ - doLevelSetMeasure(grid, area, volume, useWorldSpace); -} - -//////////////////////////////////////// - -template -inline typename boost::enable_if >::type -doLevelSetMeasure(const GridT& grid, Real& area, Real& volume, Real& avgCurvature, - bool useWorldSpace) -{ - LevelSetMeasure m(grid); - m.measure(area, volume, avgCurvature, useWorldSpace); -} - -template -inline typename boost::disable_if >::type -doLevelSetMeasure(const GridT&, Real&, Real&, Real&, bool) -{ - OPENVDB_THROW(TypeError, - "level set measure is supported only for scalar, floating-point grids"); -} - -template -inline void -levelSetMeasure(const GridT& grid, Real& area, Real& volume, Real& avgCurvature, bool useWorldSpace) -{ - doLevelSetMeasure(grid, area, volume, avgCurvature, useWorldSpace); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETMEASURE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetMorph.h b/openvdb_3_0_0_library/tools/LevelSetMorph.h deleted file mode 100755 index db84ab5..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetMorph.h +++ /dev/null @@ -1,681 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file LevelSetMorph.h -/// -/// @brief Shape morphology of level sets. Morphing from a source -/// narrow-band level sets to a target narrow-band level set. - -#ifndef OPENVDB_TOOLS_LEVEL_SET_MORPH_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVEL_SET_MORPH_HAS_BEEN_INCLUDED - -#include "LevelSetTracker.h" -#include "Interpolation.h" // for BoxSampler, etc. -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -/// @brief Shape morphology of level sets. Morphing from a source -/// narrow-band level sets to a target narrow-band level set. -/// -/// @details -/// The @c InterruptType template argument below refers to any class -/// with the following interface: -/// @code -/// class Interrupter { -/// ... -/// public: -/// void start(const char* name = NULL)// called when computations begin -/// void end() // called when computations end -/// bool wasInterrupted(int percent=-1)// return true to break computation -/// }; -/// @endcode -/// -/// @note If no template argument is provided for this InterruptType, -/// the util::NullInterrupter is used, which implies that all interrupter -/// calls are no-ops (i.e., they incur no computational overhead). -template -class LevelSetMorphing -{ -public: - typedef GridT GridType; - typedef typename GridT::TreeType TreeType; - typedef LevelSetTracker TrackerT; - typedef typename TrackerT::LeafRange LeafRange; - typedef typename TrackerT::LeafType LeafType; - typedef typename TrackerT::BufferType BufferType; - typedef typename TrackerT::ValueType ScalarType; - - /// Main constructor - LevelSetMorphing(GridT& sourceGrid, - const GridT& targetGrid, - InterruptT* interrupt = NULL) - : mTracker(sourceGrid, interrupt) - , mTarget(&targetGrid) - , mMask(NULL) - , mSpatialScheme(math::HJWENO5_BIAS) - , mTemporalScheme(math::TVD_RK2) - , mMinMask(0) - , mDeltaMask(1) - , mInvertMask(false) - { - } - - virtual ~LevelSetMorphing() {}; - - /// Redefine the target level set - void setTarget(const GridT& targetGrid) { mTarget = &targetGrid; } - - /// Define the alpha mask - void setAlphaMask(const GridT& maskGrid) { mMask = &maskGrid; } - - /// Return the spatial finite-difference scheme - math::BiasedGradientScheme getSpatialScheme() const { return mSpatialScheme; } - /// Set the spatial finite-difference scheme - void setSpatialScheme(math::BiasedGradientScheme scheme) { mSpatialScheme = scheme; } - - /// Return the temporal integration scheme - math::TemporalIntegrationScheme getTemporalScheme() const { return mTemporalScheme; } - /// Set the temporal integration scheme - void setTemporalScheme(math::TemporalIntegrationScheme scheme) { mTemporalScheme = scheme; } - - /// Return the spatial finite-difference scheme - math::BiasedGradientScheme getTrackerSpatialScheme() const - { - return mTracker.getSpatialScheme(); - } - /// Set the spatial finite-difference scheme - void setTrackerSpatialScheme(math::BiasedGradientScheme scheme) - { - mTracker.setSpatialScheme(scheme); - } - /// Return the temporal integration scheme - math::TemporalIntegrationScheme getTrackerTemporalScheme() const - { - return mTracker.getTemporalScheme(); - } - /// Set the temporal integration scheme - void setTrackerTemporalScheme(math::TemporalIntegrationScheme scheme) - { - mTracker.setTemporalScheme(scheme); - } - /// Return the number of normalizations performed per track or normalize call. - int getNormCount() const { return mTracker.getNormCount(); } - /// Set the number of normalizations performed per track or normalize call. - void setNormCount(int n) { mTracker.setNormCount(n); } - - /// Return the grain size used for multithreading - int getGrainSize() const { return mTracker.getGrainSize(); } - /// @brief Set the grain size used for multithreading. - /// @note A grain size of 0 or less disables multithreading! - void setGrainSize(int grainsize) { mTracker.setGrainSize(grainsize); } - - /// @brief Return the minimum value of the mask to be used for the - /// derivation of a smooth alpha value. - ScalarType minMask() const { return mMinMask; } - - /// @brief Return the maximum value of the mask to be used for the - /// derivation of a smooth alpha value. - ScalarType maxMask() const { return mDeltaMask + mMinMask; } - - /// @brief Define the range for the (optional) scalar mask. - /// @param min Minimum value of the range. - /// @param max Maximum value of the range. - /// @details Mask values outside the range maps to alpha values of - /// respectfully zero and one, and values inside the range maps - /// smoothly to 0->1 (unless of course the mask is inverted). - /// @throw ValueError if @a min is not smaller then @a max. - void setMaskRange(ScalarType min, ScalarType max) - { - if (!(min < max)) OPENVDB_THROW(ValueError, "Invalid mask range (expects min < max)"); - mMinMask = min; - mDeltaMask = max-min; - } - - /// @brief Return true if the mask is inverted, i.e. min->max in the - /// original mask maps to 1->0 in the inverted alpha mask. - bool isMaskInverted() const { return mInvertMask; } - /// @brief Invert the optional mask, i.e. min->max in the original - /// mask maps to 1->0 in the inverted alpha mask. - void invertMask(bool invert=true) { mInvertMask = invert; } - - /// @brief Advect the level set from its current time, @a time0, to its - /// final time, @a time1. If @a time0 > @a time1, perform backward advection. - /// - /// @return the number of CFL iterations used to advect from @a time0 to @a time1 - size_t advect(ScalarType time0, ScalarType time1); - -private: - - template - size_t advect1(ScalarType time0, ScalarType time1); - - template - size_t advect2(ScalarType time0, ScalarType time1); - - template - size_t advect3(ScalarType time0, ScalarType time1); - - TrackerT mTracker; - const GridT *mTarget, *mMask; - math::BiasedGradientScheme mSpatialScheme; - math::TemporalIntegrationScheme mTemporalScheme; - ScalarType mMinMask, mDeltaMask; - bool mInvertMask; - - // disallow copy by assignment - void operator=(const LevelSetMorphing& other) {} - - // This templated private class implements all the level set magic. - template - class LevelSetMorph - { - public: - /// Main constructor - LevelSetMorph(LevelSetMorphing& parent); - /// Shallow copy constructor called by tbb::parallel_for() threads - LevelSetMorph(const LevelSetMorph& other); - /// Shallow copy constructor called by tbb::parallel_reduce() threads - LevelSetMorph(LevelSetMorph& other, tbb::split); - /// destructor - virtual ~LevelSetMorph() {} - /// Advect the level set from it's current time, time0, to it's final time, time1. - /// @return number of CFL iterations - size_t advect(ScalarType time0, ScalarType time1); - /// Used internally by tbb::parallel_for() - void operator()(const LeafRange& r) const - { - if (mTask) mTask(const_cast(this), r); - else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly"); - } - /// Used internally by tbb::parallel_reduce() - void operator()(const LeafRange& r) - { - if (mTask) mTask(this, r); - else OPENVDB_THROW(ValueError, "task is undefined - don\'t call this method directly"); - } - /// This is only called by tbb::parallel_reduce() threads - void join(const LevelSetMorph& other) { mMaxAbsS = math::Max(mMaxAbsS, other.mMaxAbsS); } - private: - typedef typename boost::function FuncType; - LevelSetMorphing* mParent; - ScalarType mMinAbsS, mMaxAbsS; - const MapT* mMap; - FuncType mTask; - - /// Enum to define the type of multithreading - enum ThreadingMode { PARALLEL_FOR, PARALLEL_REDUCE }; // for internal use - // method calling tbb - void cook(ThreadingMode mode, size_t swapBuffer = 0); - - /// Sample field and return the CFT time step - typename GridT::ValueType sampleSpeed(ScalarType time0, ScalarType time1, Index speedBuffer); - void sampleXformedSpeed(const LeafRange& r, Index speedBuffer); - void sampleAlignedSpeed(const LeafRange& r, Index speedBuffer); - - // Forward Euler advection steps: Phi(result) = Phi(0) - dt * Speed(speed)*|Grad[Phi(0)]|; - void euler1(const LeafRange& r, ScalarType dt, Index resultBuffer, Index speedBuffer); - - // Convex combination of Phi and a forward Euler advection steps: - // Phi(result) = alpha * Phi(phi) + (1-alpha) * (Phi(0) - dt * Speed(speed)*|Grad[Phi(0)]|); - void euler2(const LeafRange& r, ScalarType dt, ScalarType alpha, - Index phiBuffer, Index resultBuffer, Index speedBuffer); - - }; // end of private LevelSetMorph class - -};//end of LevelSetMorphing - -template -inline size_t -LevelSetMorphing::advect(ScalarType time0, ScalarType time1) -{ - switch (mSpatialScheme) { - case math::FIRST_BIAS: - return this->advect1(time0, time1); - //case math::SECOND_BIAS: - //return this->advect1(time0, time1); - //case math::THIRD_BIAS: - //return this->advect1(time0, time1); - //case math::WENO5_BIAS: - //return this->advect1(time0, time1); - case math::HJWENO5_BIAS: - return this->advect1(time0, time1); - default: - OPENVDB_THROW(ValueError, "Spatial difference scheme not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetMorphing::advect1(ScalarType time0, ScalarType time1) -{ - switch (mTemporalScheme) { - case math::TVD_RK1: - return this->advect2(time0, time1); - case math::TVD_RK2: - return this->advect2(time0, time1); - case math::TVD_RK3: - return this->advect2(time0, time1); - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetMorphing::advect2(ScalarType time0, ScalarType time1) -{ - const math::Transform& trans = mTracker.grid().transform(); - if (trans.mapType() == math::UniformScaleMap::mapType()) { - return this->advect3(time0, time1); - } else if (trans.mapType() == math::UniformScaleTranslateMap::mapType()) { - return this->advect3( - time0, time1); - } else if (trans.mapType() == math::UnitaryMap::mapType()) { - return this->advect3(time0, time1); - } else if (trans.mapType() == math::TranslationMap::mapType()) { - return this->advect3(time0, time1); - } else { - OPENVDB_THROW(ValueError, "MapType not supported!"); - } - return 0; -} - -template -template -inline size_t -LevelSetMorphing::advect3(ScalarType time0, ScalarType time1) -{ - LevelSetMorph tmp(*this); - return tmp.advect(time0, time1); -} - - -/////////////////////////////////////////////////////////////////////// - -template -template -inline -LevelSetMorphing:: -LevelSetMorph:: -LevelSetMorph(LevelSetMorphing& parent) - : mParent(&parent) - , mMinAbsS(ScalarType(1e-6)) - , mMap(parent.mTracker.grid().transform().template constMap().get()) - , mTask(0) -{ -} - -template -template -inline -LevelSetMorphing:: -LevelSetMorph:: -LevelSetMorph(const LevelSetMorph& other) - : mParent(other.mParent) - , mMinAbsS(other.mMinAbsS) - , mMaxAbsS(other.mMaxAbsS) - , mMap(other.mMap) - , mTask(other.mTask) -{ -} - -template -template -inline -LevelSetMorphing:: -LevelSetMorph:: -LevelSetMorph(LevelSetMorph& other, tbb::split) - : mParent(other.mParent) - , mMinAbsS(other.mMinAbsS) - , mMaxAbsS(other.mMaxAbsS) - , mMap(other.mMap) - , mTask(other.mTask) -{ -} - -template -template -inline size_t -LevelSetMorphing:: -LevelSetMorph:: -advect(ScalarType time0, ScalarType time1) -{ - // Make sure we have enough temporal auxiliary buffers for the time - // integration AS WELL AS an extra buffer with the speed function! - static const Index auxBuffers = 1 + (TemporalScheme == math::TVD_RK3 ? 2 : 1); - size_t countCFL = 0; - while (time0 < time1 && mParent->mTracker.checkInterrupter()) { - mParent->mTracker.leafs().rebuildAuxBuffers(auxBuffers); - - const ScalarType dt = this->sampleSpeed(time0, time1, auxBuffers); - if ( math::isZero(dt) ) break;//V is essentially zero so terminate - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN //switch is resolved at compile-time - switch(TemporalScheme) { - case math::TVD_RK1: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * Speed(2) * |Grad[Phi(0)]| - mTask = boost::bind(&LevelSetMorph::euler1, _1, _2, dt, /*result=*/1, /*speed*/2); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - break; - case math::TVD_RK2: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * Speed(2) * |Grad[Phi(0)]| - mTask = boost::bind(&LevelSetMorph::euler1, _1, _2, dt, /*result=*/1, /*speed*/2); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - - // Convex combine explict Euler step: t2 = t0 + dt - // Phi_t2(1) = 1/2 * Phi_t0(1) + 1/2 * (Phi_t1(0) - dt * Speed(2) * |Grad[Phi(0)]|) - mTask = boost::bind(&LevelSetMorph::euler2, _1, _2, dt, ScalarType(0.5), - /*phi=*/1, /*result=*/1, /*speed*/2); - // Cook and swap buffer 0 and 1 such that Phi_t2(0) and Phi_t1(1) - this->cook(PARALLEL_FOR, 1); - break; - case math::TVD_RK3: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * Speed(3) * |Grad[Phi(0)]| - mTask = boost::bind(&LevelSetMorph::euler1, _1, _2, dt, /*result=*/1, /*speed*/3); - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(PARALLEL_FOR, 1); - - // Convex combine explict Euler step: t2 = t0 + dt/2 - // Phi_t2(2) = 3/4 * Phi_t0(1) + 1/4 * (Phi_t1(0) - dt * Speed(3) * |Grad[Phi(0)]|) - mTask = boost::bind(&LevelSetMorph::euler2, _1, _2, dt, ScalarType(0.75), - /*phi=*/1, /*result=*/2, /*speed*/3); - // Cook and swap buffer 0 and 2 such that Phi_t2(0) and Phi_t1(2) - this->cook(PARALLEL_FOR, 2); - - // Convex combine explict Euler step: t3 = t0 + dt - // Phi_t3(2) = 1/3 * Phi_t0(1) + 2/3 * (Phi_t2(0) - dt * Speed(3) * |Grad[Phi(0)]|) - mTask = boost::bind(&LevelSetMorph::euler2, _1, _2, dt, ScalarType(1.0/3.0), - /*phi=*/1, /*result=*/2, /*speed*/3); - // Cook and swap buffer 0 and 2 such that Phi_t3(0) and Phi_t2(2) - this->cook(PARALLEL_FOR, 2); - break; - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - }//end of compile-time resolved switch - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - - time0 += dt; - ++countCFL; - mParent->mTracker.leafs().removeAuxBuffers(); - - // Track the narrow band - mParent->mTracker.track(); - }//end wile-loop over time - - return countCFL;//number of CLF propagation steps -} - -template -template -inline typename GridT::ValueType -LevelSetMorphing:: -LevelSetMorph:: -sampleSpeed(ScalarType time0, ScalarType time1, Index speedBuffer) -{ - mMaxAbsS = mMinAbsS; - const size_t leafCount = mParent->mTracker.leafs().leafCount(); - if (leafCount==0 || time0 >= time1) return ScalarType(0); - - const math::Transform& xform = mParent->mTracker.grid().transform(); - if (mParent->mTarget->transform() == xform && - (mParent->mMask == NULL || mParent->mMask->transform() == xform)) { - mTask = boost::bind(&LevelSetMorph::sampleAlignedSpeed, _1, _2, speedBuffer); - } else { - mTask = boost::bind(&LevelSetMorph::sampleXformedSpeed, _1, _2, speedBuffer); - } - this->cook(PARALLEL_REDUCE); - if (math::isApproxEqual(mMinAbsS, mMaxAbsS)) return ScalarType(0);//speed is essentially zero - static const ScalarType CFL = (TemporalScheme == math::TVD_RK1 ? ScalarType(0.3) : - TemporalScheme == math::TVD_RK2 ? ScalarType(0.9) : - ScalarType(1.0))/math::Sqrt(ScalarType(3.0)); - const ScalarType dt = math::Abs(time1 - time0), dx = mParent->mTracker.voxelSize(); - return math::Min(dt, ScalarType(CFL*dx/mMaxAbsS)); -} - -template -template -inline void -LevelSetMorphing:: -LevelSetMorph:: -sampleXformedSpeed(const LeafRange& range, Index speedBuffer) -{ - typedef typename LeafType::ValueOnCIter VoxelIterT; - typedef tools::GridSampler SamplerT; - const MapT& map = *mMap; - mParent->mTracker.checkInterrupter(); - - typename GridT::ConstAccessor targetAcc = mParent->mTarget->getAccessor(); - SamplerT target(targetAcc, mParent->mTarget->transform()); - if (mParent->mMask == NULL) { - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& speed = leafIter.buffer(speedBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - ScalarType& s = const_cast(speed.getValue(voxelIter.pos())); - s -= target.wsSample(map.applyMap(voxelIter.getCoord().asVec3d())); - mMaxAbsS = math::Max(mMaxAbsS, math::Abs(s)); - } - } - } else { - const ScalarType min = mParent->mMinMask, invNorm = 1.0f/(mParent->mDeltaMask); - const bool invMask = mParent->isMaskInverted(); - typename GridT::ConstAccessor maskAcc = mParent->mMask->getAccessor(); - SamplerT mask(maskAcc, mParent->mMask->transform()); - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& source = leafIter.buffer(speedBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Vec3R xyz = map.applyMap(voxelIter.getCoord().asVec3d());//world space - const ScalarType a = math::SmoothUnitStep((mask.wsSample(xyz)-min)*invNorm); - ScalarType& s = const_cast(source.getValue(voxelIter.pos())); - s -= target.wsSample(xyz); - s *= invMask ? 1 - a : a; - mMaxAbsS = math::Max(mMaxAbsS, math::Abs(s)); - } - } - } -} - -template -template -inline void -LevelSetMorphing:: -LevelSetMorph:: -sampleAlignedSpeed(const LeafRange& range, Index speedBuffer) -{ - typedef typename LeafType::ValueOnCIter VoxelIterT; - mParent->mTracker.checkInterrupter(); - - typename GridT::ConstAccessor target = mParent->mTarget->getAccessor(); - - if (mParent->mMask == NULL) { - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& source = leafIter.buffer(speedBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - ScalarType& s = const_cast(source.getValue(voxelIter.pos())); - s -= target.getValue(voxelIter.getCoord()); - mMaxAbsS = math::Max(mMaxAbsS, math::Abs(s)); - } - } - } else { - const ScalarType min = mParent->mMinMask, invNorm = 1.0f/(mParent->mDeltaMask); - const bool invMask = mParent->isMaskInverted(); - typename GridT::ConstAccessor mask = mParent->mMask->getAccessor(); - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& source = leafIter.buffer(speedBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Coord ijk = voxelIter.getCoord();//index space - const ScalarType a = math::SmoothUnitStep((mask.getValue(ijk)-min)*invNorm); - ScalarType& s = const_cast(source.getValue(voxelIter.pos())); - s -= target.getValue(ijk); - s *= invMask ? 1 - a : a; - mMaxAbsS = math::Max(mMaxAbsS, math::Abs(s)); - } - } - } -} - -template -template -inline void -LevelSetMorphing:: -LevelSetMorph:: -cook(ThreadingMode mode, size_t swapBuffer) -{ - mParent->mTracker.startInterrupter("Morphing level set"); - - const int grainSize = mParent->mTracker.getGrainSize(); - const LeafRange range = mParent->mTracker.leafs().leafRange(grainSize); - - if (mParent->mTracker.getGrainSize()==0) { - (*this)(range); - } else if (mode == PARALLEL_FOR) { - tbb::parallel_for(range, *this); - } else if (mode == PARALLEL_REDUCE) { - tbb::parallel_reduce(range, *this); - } else { - throw std::runtime_error("Undefined threading mode"); - } - - mParent->mTracker.leafs().swapLeafBuffer(swapBuffer, grainSize == 0); - - mParent->mTracker.endInterrupter(); -} - -// Forward Euler advection steps: -// Phi(result) = Phi(0) - dt * Phi(speed) * |Grad[Phi(0)]| -template -template -inline void -LevelSetMorphing:: -LevelSetMorph:: -euler1(const LeafRange& range, ScalarType dt, Index resultBuffer, Index speedBuffer) -{ - typedef math::BIAS_SCHEME SchemeT; - typedef typename SchemeT::template ISStencil::StencilType StencilT; - typedef typename LeafType::ValueOnCIter VoxelIterT; - typedef math::GradientNormSqrd NumGrad; - - mParent->mTracker.checkInterrupter(); - const MapT& map = *mMap; - StencilT stencil(mParent->mTracker.grid()); - - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& speed = leafIter.buffer(speedBuffer); - BufferType& result = leafIter.buffer(resultBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Index n = voxelIter.pos(); - const ScalarType S = speed.getValue(n); - if (math::isApproxZero(S)) continue; - stencil.moveTo(voxelIter); - result.setValue(n, *voxelIter - dt * S * NumGrad::result(map, stencil)); - } - } -} - -// Convex combination of Phi and a forward Euler advection steps: -// Phi(result) = alpha * Phi(phi) + (1-alpha) * (Phi(0) - dt * Phi(speed) * |Grad[Phi(0)]|) -template -template -inline void -LevelSetMorphing:: -LevelSetMorph:: -euler2(const LeafRange& range, ScalarType dt, ScalarType alpha, - Index phiBuffer, Index resultBuffer, Index speedBuffer) -{ - typedef math::BIAS_SCHEME SchemeT; - typedef typename SchemeT::template ISStencil::StencilType StencilT; - typedef typename LeafType::ValueOnCIter VoxelIterT; - typedef math::GradientNormSqrd NumGrad; - - mParent->mTracker.checkInterrupter(); - const MapT& map = *mMap; - const ScalarType beta = ScalarType(1.0) - alpha; - StencilT stencil(mParent->mTracker.grid()); - - for (typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) { - BufferType& speed = leafIter.buffer(speedBuffer); - BufferType& result = leafIter.buffer(resultBuffer); - BufferType& phi = leafIter.buffer(phiBuffer); - for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) { - const Index n = voxelIter.pos(); - const ScalarType S = speed.getValue(n); - if (math::isApproxZero(S)) continue; - stencil.moveTo(voxelIter); - const ScalarType G = NumGrad::result(map, stencil); - result.setValue(n, alpha * phi.getValue(n) + beta * (*voxelIter - dt * S * G)); - } - } -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVEL_SET_MORPH_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetRebuild.h b/openvdb_3_0_0_library/tools/LevelSetRebuild.h deleted file mode 100755 index ac07cec..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetRebuild.h +++ /dev/null @@ -1,348 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -/// @brief Return a new grid of type @c GridType that contains a narrow-band level set -/// representation of an isosurface of a given grid. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param isovalue the isovalue that defines the implicit surface (defaults to zero, -/// which is typical if the input grid is already a level set or a SDF). -/// @param halfWidth half the width of the narrow band, in voxel units -/// (defaults to 3 voxels, which is required for some level set operations) -/// @param xform optional transform for the output grid -/// (if not provided, the transform of the input @a grid will be matched) -/// -/// @throw TypeError if @a grid is not scalar or not floating-point -/// -/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost. -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float isovalue = 0, - float halfWidth = float(LEVEL_SET_HALF_WIDTH), const math::Transform* xform = NULL); - - -/// @brief Return a new grid of type @c GridType that contains a narrow-band level set -/// representation of an isosurface of a given grid. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param isovalue the isovalue that defines the implicit surface -/// @param exBandWidth the exterior narrow-band width in voxel units -/// @param inBandWidth the interior narrow-band width in voxel units -/// @param xform optional transform for the output grid -/// (if not provided, the transform of the input @a grid will be matched) -/// -/// @throw TypeError if @a grid is not scalar or not floating-point -/// -/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost. -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth, - const math::Transform* xform = NULL); - - -/// @brief Return a new grid of type @c GridType that contains a narrow-band level set -/// representation of an isosurface of a given grid. -/// -/// @param grid a scalar, floating-point grid with one or more disjoint, -/// closed isosurfaces at the given @a isovalue -/// @param isovalue the isovalue that defines the implicit surface -/// @param exBandWidth the exterior narrow-band width in voxel units -/// @param inBandWidth the interior narrow-band width in voxel units -/// @param xform optional transform for the output grid -/// (if not provided, the transform of the input @a grid will be matched) -/// @param interrupter optional interrupter object -/// -/// @throw TypeError if @a grid is not scalar or not floating-point -/// -/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost. -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth, - const math::Transform* xform = NULL, InterruptT* interrupter = NULL); - - -//////////////////////////////////////// - - -// Internal utility objects and implementation details - -namespace internal { - -class PointListTransform -{ -public: - PointListTransform(const PointList& pointsIn, std::vector& pointsOut, - const math::Transform& xform) - : mPointsIn(pointsIn) - , mPointsOut(&pointsOut) - , mXform(xform) - { - } - - void runParallel() - { - tbb::parallel_for(tbb::blocked_range(0, mPointsOut->size()), *this); - } - - void runSerial() - { - (*this)(tbb::blocked_range(0, mPointsOut->size())); - } - - inline void operator()(const tbb::blocked_range& range) const - { - for (size_t n = range.begin(); n < range.end(); ++n) { - (*mPointsOut)[n] = Vec3s(mXform.worldToIndex(mPointsIn[n])); - } - } - -private: - const PointList& mPointsIn; - std::vector * const mPointsOut; - const math::Transform& mXform; -}; - - -class PrimCpy -{ -public: - PrimCpy(const PolygonPoolList& primsIn, const std::vector& indexList, - std::vector& primsOut) - : mPrimsIn(primsIn) - , mIndexList(indexList) - , mPrimsOut(&primsOut) - { - } - - void runParallel() - { - tbb::parallel_for(tbb::blocked_range(0, mIndexList.size()), *this); - } - - void runSerial() - { - (*this)(tbb::blocked_range(0, mIndexList.size())); - } - - inline void operator()(const tbb::blocked_range& range) const - { - openvdb::Vec4I quad; - quad[3] = openvdb::util::INVALID_IDX; - std::vector& primsOut = *mPrimsOut; - - for (size_t n = range.begin(); n < range.end(); ++n) { - size_t index = mIndexList[n]; - PolygonPool& polygons = mPrimsIn[n]; - - // Copy quads - for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) { - primsOut[index++] = polygons.quad(i); - } - polygons.clearQuads(); - - // Copy triangles (adaptive mesh) - for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) { - const openvdb::Vec3I& triangle = polygons.triangle(i); - quad[0] = triangle[0]; - quad[1] = triangle[1]; - quad[2] = triangle[2]; - primsOut[index++] = quad; - } - - polygons.clearTriangles(); - } - } - -private: - const PolygonPoolList& mPrimsIn; - const std::vector& mIndexList; - std::vector * const mPrimsOut; -}; - -} // namespace internal - - -//////////////////////////////////////// - - -/// The normal entry points for level set rebuild are the levelSetRebuild() functions. -/// doLevelSetRebuild() is mainly for internal use, but when the isovalue and half band -/// widths are given in ValueType units (for example, if they are queried from -/// a grid), it might be more convenient to call this function directly. -/// -/// @internal This overload is enabled only for grids with a scalar, floating-point ValueType. -template -inline typename boost::enable_if, -typename GridType::Ptr>::type -doLevelSetRebuild(const GridType& grid, typename GridType::ValueType iso, - typename GridType::ValueType exWidth, typename GridType::ValueType inWidth, - const math::Transform* xform, InterruptT* interrupter) -{ - const float - isovalue = float(iso), - exBandWidth = float(exWidth), - inBandWidth = float(inWidth); - - tools::VolumeToMesh mesher(isovalue); - mesher(grid); - - math::Transform::Ptr transform = (xform != NULL) ? xform->copy() : grid.transform().copy(); - - std::vector points(mesher.pointListSize()); - - { // Copy and transform (required for MeshToVolume) points to grid space. - internal::PointListTransform ptnXForm(mesher.pointList(), points, *transform); - ptnXForm.runParallel(); - mesher.pointList().reset(NULL); - } - - std::vector primitives; - - { // Copy primitives. - PolygonPoolList& polygonPoolList = mesher.polygonPoolList(); - - size_t numPrimitives = 0; - std::vector indexlist(mesher.polygonPoolListSize()); - - for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) { - const openvdb::tools::PolygonPool& polygons = polygonPoolList[n]; - indexlist[n] = numPrimitives; - numPrimitives += polygons.numQuads(); - numPrimitives += polygons.numTriangles(); - } - - primitives.resize(numPrimitives); - internal::PrimCpy primCpy(polygonPoolList, indexlist, primitives); - primCpy.runParallel(); - } - - MeshToVolume vol(transform, OUTPUT_RAW_DATA, interrupter); - vol.convertToLevelSet(points, primitives, exBandWidth, inBandWidth); - - return vol.distGridPtr(); -} - - -/// @internal This overload is enabled only for grids that do not have a scalar, -/// floating-point ValueType. -template -inline typename boost::disable_if, -typename GridType::Ptr>::type -doLevelSetRebuild(const GridType&, typename GridType::ValueType /*isovalue*/, - typename GridType::ValueType /*exWidth*/, typename GridType::ValueType /*inWidth*/, - const math::Transform*, InterruptT*) -{ - OPENVDB_THROW(TypeError, - "level set rebuild is supported only for scalar, floating-point grids"); -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth, - const math::Transform* xform, InterruptT* interrupter) -{ - typedef typename GridType::ValueType ValueT; - ValueT - isovalue(zeroVal() + iso), - exBandWidth(zeroVal() + exWidth), - inBandWidth(zeroVal() + inWidth); - - return doLevelSetRebuild(grid, isovalue, exBandWidth, inBandWidth, xform, interrupter); -} - - -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth, - const math::Transform* xform) -{ - typedef typename GridType::ValueType ValueT; - ValueT - isovalue(zeroVal() + iso), - exBandWidth(zeroVal() + exWidth), - inBandWidth(zeroVal() + inWidth); - - return doLevelSetRebuild( - grid, isovalue, exBandWidth, inBandWidth, xform, NULL); -} - - -template -inline typename GridType::Ptr -levelSetRebuild(const GridType& grid, float iso, float halfVal, const math::Transform* xform) -{ - typedef typename GridType::ValueType ValueT; - ValueT - isovalue(zeroVal() + iso), - halfWidth(zeroVal() + halfVal); - - return doLevelSetRebuild( - grid, isovalue, halfWidth, halfWidth, xform, NULL); -} - - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetSphere.h b/openvdb_3_0_0_library/tools/LevelSetSphere.h deleted file mode 100755 index 411ca71..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetSphere.h +++ /dev/null @@ -1,222 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file LevelSetSphere.h -/// -/// @brief Generate a narrow-band level set of sphere. -/// -/// @note By definition a level set has a fixed narrow band width -/// (the half width is defined by LEVEL_SET_HALF_WIDTH in Types.h), -/// whereas an SDF can have a variable narrow band width. - -#ifndef OPENVDB_TOOLS_LEVELSETSPHERE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETSPHERE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "SignedFloodFill.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Return a grid of type @c GridType containing a narrow-band level set -/// representation of a sphere. -/// -/// @param radius radius of the sphere in world units -/// @param center center of the sphere in world units -/// @param voxelSize voxel size in world units -/// @param halfWidth half the width of the narrow band, in voxel units -/// @param interrupt a pointer adhering to the util::NullInterrupter interface -/// -/// @note @c GridType::ValueType must be a floating-point scalar. -/// @note The leapfrog algorithm employed in this method is best suited -/// for a single large sphere. For multiple small spheres consider -/// using the faster algorithm in ParticlesToLevelSet.h -template -typename GridType::Ptr -createLevelSetSphere(float radius, const openvdb::Vec3f& center, float voxelSize, - float halfWidth = float(LEVEL_SET_HALF_WIDTH), InterruptT* interrupt = NULL); - -/// @brief Return a grid of type @c GridType containing a narrow-band level set -/// representation of a sphere. -/// -/// @param radius radius of the sphere in world units -/// @param center center of the sphere in world units -/// @param voxelSize voxel size in world units -/// @param halfWidth half the width of the narrow band, in voxel units -/// -/// @note @c GridType::ValueType must be a floating-point scalar. -/// @note The leapfrog algorithm employed in this method is best suited -/// for a single large sphere. For multiple small spheres consider -/// using the faster algorithm in ParticlesToLevelSet.h -template -typename GridType::Ptr -createLevelSetSphere(float radius, const openvdb::Vec3f& center, float voxelSize, - float halfWidth = float(LEVEL_SET_HALF_WIDTH)) -{ - return createLevelSetSphere(radius,center,voxelSize,halfWidth); -} - - -//////////////////////////////////////// - - -/// @brief Generates a signed distance field (or narrow band level -/// set) to a single sphere. -/// -/// @note The leapfrog algorithm employed in this class is best -/// suited for a single large sphere. For multiple small spheres consider -/// using the faster algorithm in tools/ParticlesToLevelSet.h -template -class LevelSetSphere -{ -public: - typedef typename GridT::ValueType ValueT; - typedef typename math::Vec3 Vec3T; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Constructor - /// - /// @param radius radius of the sphere in world units - /// @param center center of the sphere in world units - /// @param interrupt pointer to optional interrupter. Use template - /// argument util::NullInterrupter if no interruption is desired. - /// - /// @note If the radius of the sphere is smaller then - /// 1.5*voxelSize, i.e. the sphere is smaller then the Nyquist - /// frequency of the grid, it is ignored! - LevelSetSphere(ValueT radius, const Vec3T ¢er, InterruptT* interrupt = NULL) - : mRadius(radius), mCenter(center), mInterrupt(interrupt) - { - if (mRadius<=0) OPENVDB_THROW(ValueError, "radius must be positive"); - } - - /// @return a narrow-band level set of the sphere - /// - /// @param voxelSize Size of voxels in world units - /// @param halfWidth Half-width of narrow-band in voxel units - typename GridT::Ptr getLevelSet(ValueT voxelSize, ValueT halfWidth) - { - mGrid = createLevelSet(voxelSize, halfWidth); - this->rasterSphere(voxelSize, halfWidth); - mGrid->setGridClass(GRID_LEVEL_SET); - return mGrid; - } - -private: - void rasterSphere(ValueT dx, ValueT w) - { - if (!(dx>0.0f)) OPENVDB_THROW(ValueError, "voxel size must be positive"); - if (!(w>1)) OPENVDB_THROW(ValueError, "half-width must be larger than one"); - - // Define radius of sphere and narrow-band in voxel units - const ValueT r0 = mRadius/dx, rmax = r0 + w; - - // Radius below the Nyquist frequency - if (r0 < 1.5f) return; - - // Define center of sphere in voxel units - const Vec3T c(mCenter[0]/dx, mCenter[1]/dx, mCenter[2]/dx); - - // Define index coordinates and their respective bounds - openvdb::Coord ijk; - int &i = ijk[0], &j = ijk[1], &k = ijk[2], m=1; - const int imin=math::Floor(c[0]-rmax), imax=math::Ceil(c[0]+rmax); - const int jmin=math::Floor(c[1]-rmax), jmax=math::Ceil(c[1]+rmax); - const int kmin=math::Floor(c[2]-rmax), kmax=math::Ceil(c[2]+rmax); - - // Allocate an ValueAccessor for accelerated random access - typename GridT::Accessor accessor = mGrid->getAccessor(); - - if (mInterrupt) mInterrupt->start("Generating level set of sphere"); - // Compute signed distances to sphere using leapfrogging in k - for ( i = imin; i <= imax; ++i ) { - if (util::wasInterrupted(mInterrupt)) return; - const float x2 = math::Pow2(i - c[0]); - for ( j = jmin; j <= jmax; ++j ) { - const float x2y2 = math::Pow2(j - c[1]) + x2; - for (k=kmin; k<=kmax; k += m) { - m = 1; - /// Distance in voxel units to sphere - const float v = math::Sqrt(x2y2 + math::Pow2(k-c[2]))-r0, - d = math::Abs(v); - if ( d < w ){ // inside narrow band - accessor.setValue(ijk, dx*v);// distance in world units - } else {// outside narrow band - m += math::Floor(d-w);// leapfrog - } - }//end leapfrog over k - }//end loop over j - }//end loop over i - - // Define consistant signed distances outside the narrow-band - tools::signedFloodFill(mGrid->tree()); - - if (mInterrupt) mInterrupt->end(); - } - - const ValueT mRadius; - const Vec3T mCenter; - InterruptT* mInterrupt; - typename GridT::Ptr mGrid; -};// LevelSetSphere - - -//////////////////////////////////////// - - -template -typename GridType::Ptr -createLevelSetSphere(float radius, const openvdb::Vec3f& center, float voxelSize, - float halfWidth, InterruptT* interrupt) -{ - // GridType::ValueType is required to be a floating-point scalar. - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - typedef typename GridType::ValueType ValueT; - LevelSetSphere factory(ValueT(radius), center, interrupt); - return factory.getLevelSet(ValueT(voxelSize), ValueT(halfWidth)); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETSPHERE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetTracker.h b/openvdb_3_0_0_library/tools/LevelSetTracker.h deleted file mode 100755 index 6437fba..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetTracker.h +++ /dev/null @@ -1,626 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file LevelSetTracker.h -/// -/// @brief Performs multi-threaded interface tracking of narrow band -/// level sets. This is the building-block for most level set -/// computations that involve dynamic topology, e.g. advection. - -#ifndef OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ChangeBackground.h"// for changeLevelSetBackground -#include "Morphology.h"//for dilateVoxels -#include "Prune.h"// for pruneLevelSet - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Performs multi-threaded interface tracking of narrow band level sets -template -class LevelSetTracker -{ -public: - typedef GridT GridType; - typedef typename GridT::TreeType TreeType; - typedef typename TreeType::LeafNodeType LeafType; - typedef typename TreeType::ValueType ValueType; - typedef typename tree::LeafManager LeafManagerType; // leafs + buffers - typedef typename LeafManagerType::RangeType RangeType; - typedef typename LeafManagerType::LeafRange LeafRange; - typedef typename LeafManagerType::BufferType BufferType; - typedef typename TreeType::template ValueConverter::Type BoolMaskType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Main constructor - /// @throw RuntimeError if the grid is not a level set - LevelSetTracker(GridT& grid, InterruptT* interrupt = NULL); - - /// @brief Shallow copy constructor called by tbb::parallel_for() threads during filtering - LevelSetTracker(const LevelSetTracker& other); - - virtual ~LevelSetTracker() { if (mIsMaster) delete mLeafs; } - - /// @brief Iterative normalization, i.e. solving the Eikonal equation - /// @note The mask it optional and by default it is ignored. - template - void normalize(const MaskType* mask); - - /// @brief Iterative normalization, i.e. solving the Eikonal equation - void normalize() { this->normalize(NULL); } - - /// @brief Track the level set interface, i.e. rebuild and normalize the - /// narrow band of the level set. - void track(); - - /// @brief Remove voxels that are outside the narrow band. (substep of track) - void prune(); - - /// @brief Fast but approximate dilation of the narrow band - /// @note This method works fine with low-order temporal and spatial schemes. - void dilate(int iterations = 1); - - /// @brief Erodes the width of the narrow-band and update the background values - /// @throw ValueError if @a iterations is larger then the current half-width. - void erode(int iterations = 1); - - /// @return the spatial finite difference scheme - math::BiasedGradientScheme getSpatialScheme() const { return mSpatialScheme; } - - /// @brief Set the spatial finite difference scheme - void setSpatialScheme(math::BiasedGradientScheme scheme) { mSpatialScheme = scheme; } - - /// @return the temporal integration scheme - math::TemporalIntegrationScheme getTemporalScheme() const { return mTemporalScheme; } - - /// @brief Set the spatial finite difference scheme - void setTemporalScheme(math::TemporalIntegrationScheme scheme) { mTemporalScheme = scheme; } - - /// @return The number of normalizations performed per track or - /// normalize call. - int getNormCount() const { return mNormCount; } - - /// @brief Set the number of normalizations performed per track or - /// normalize call. - void setNormCount(int n) { mNormCount = n; } - - /// @return the grain-size used for multi-threading - int getGrainSize() const { return mGrainSize; } - - /// @brief Set the grain-size used for multi-threading. - /// @note A grainsize of 0 or less disables multi-threading! - void setGrainSize(int grainsize) { mGrainSize = grainsize; } - - ValueType voxelSize() const { return mDx; } - - void startInterrupter(const char* msg); - - void endInterrupter(); - - /// @return false if the process was interrupted - bool checkInterrupter(); - - const GridType& grid() const { return *mGrid; } - - LeafManagerType& leafs() { return *mLeafs; } - - const LeafManagerType& leafs() const { return *mLeafs; } - -private: - - // Private class to perform multi-threaded trimming of - // voxels that are too far away from the zero-crossing. - struct Trim - { - Trim(LevelSetTracker& tracker) : mTracker(tracker) {} - void trim(); - void operator()(const RangeType& r) const; - LevelSetTracker& mTracker; - };// Trim - - // Private class to perform multi-threaded normalization - template - struct Normalizer - { - typedef math::BIAS_SCHEME SchemeT; - typedef typename SchemeT::template ISStencil::StencilType StencilT; - typedef typename MaskT::LeafNodeType MaskLeafT; - typedef typename MaskLeafT::ValueOnCIter MaskIterT; - typedef typename LeafType::ValueOnCIter VoxelIterT; - Normalizer(LevelSetTracker& tracker, const MaskT* mask); - void normalize(); - void operator()(const RangeType& r) const {mTask(const_cast(this), r);} - void cook(int swapBuffer=0); - template - void euler(const RangeType& range, Index phiBuffer, Index resultBuffer); - inline void euler01(const RangeType& r) {this->euler<0,1>(r, 0, 1);} - inline void euler12(const RangeType& r, Index n, Index m) {this->euler<1,2>(r, n, m);} - inline void euler34(const RangeType& r, Index n, Index m) {this->euler<3,4>(r, n, m);} - inline void euler13(const RangeType& r, Index n, Index m) {this->euler<1,3>(r, n, m);} - template - void eval(StencilT& stencil, const BufferType& phi, BufferType& result, Index n) const; - typedef typename boost::function FuncType; - LevelSetTracker& mTracker; - const MaskT* mMask; - const ValueType mDt, mInvDx; - FuncType mTask; - }; // Normalizer - - template - void normalize1(const MaskT* mask); - - template - void normalize2(const MaskT* mask); - - // Throughout the methods below mLeafs is always assumed to contain - // a list of the current LeafNodes! The auxiliary buffers on the - // other hand always have to be allocated locally, since some - // methods need them and others don't! - GridType* mGrid; - LeafManagerType* mLeafs; - InterruptT* mInterrupter; - const ValueType mDx; - math::BiasedGradientScheme mSpatialScheme; - math::TemporalIntegrationScheme mTemporalScheme; - int mNormCount;// Number of iteratations of normalization - int mGrainSize; - const bool mIsMaster; - - // disallow copy by assignment - void operator=(const LevelSetTracker& other) {} - -}; // end of LevelSetTracker class - -template -LevelSetTracker:: -LevelSetTracker(GridT& grid, InterruptT* interrupt): - mGrid(&grid), - mLeafs(new LeafManagerType(grid.tree())), - mInterrupter(interrupt), - mDx(static_cast(grid.voxelSize()[0])), - mSpatialScheme(math::HJWENO5_BIAS), - mTemporalScheme(math::TVD_RK1), - mNormCount(static_cast(LEVEL_SET_HALF_WIDTH)), - mGrainSize(1), - mIsMaster(true)// N.B. -{ - if ( !grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "The transform must have uniform scale for the LevelSetTracker to function"); - } - if ( grid.getGridClass() != GRID_LEVEL_SET) { - OPENVDB_THROW(RuntimeError, - "LevelSetTracker expected a level set, got a grid of class \"" - + grid.gridClassToString(grid.getGridClass()) - + "\" [hint: Grid::setGridClass(openvdb::GRID_LEVEL_SET)]"); - } -} - -template -LevelSetTracker:: -LevelSetTracker(const LevelSetTracker& other): - mGrid(other.mGrid), - mLeafs(other.mLeafs), - mInterrupter(other.mInterrupter), - mDx(other.mDx), - mSpatialScheme(other.mSpatialScheme), - mTemporalScheme(other.mTemporalScheme), - mNormCount(other.mNormCount), - mGrainSize(other.mGrainSize), - mIsMaster(false)// N.B. -{ -} - -template -inline void -LevelSetTracker:: -prune() -{ - this->startInterrupter("Pruning Level Set"); - - // Prune voxels that are too far away from the zero-crossing - Trim t(*this); - t.trim(); - - // Remove inactive nodes from tree - tools::pruneLevelSet(mGrid->tree()); - - // The tree topology has changes so rebuild the list of leafs - mLeafs->rebuildLeafArray(); - this->endInterrupter(); -} - -template -inline void -LevelSetTracker:: -track() -{ - // Dilate narrow-band (this also rebuilds the leaf array!) - tools::dilateVoxels(*mLeafs); - - // Compute signed distances in dilated narrow-band - this->normalize(); - - // Remove voxels that are outside the narrow band - this->prune(); -} - -template -inline void -LevelSetTracker:: -dilate(int iterations) -{ - if (mNormCount == 0) { - for (int i=0; i < iterations; ++i) { - tools::dilateVoxels(*mLeafs); - mLeafs->rebuildLeafArray(); - tools::changeLevelSetBackground(leafs(), mDx + mGrid->background()); - } - } else { - for (int i=0; i < iterations; ++i) { - BoolMaskType mask0(mGrid->tree(), false, TopologyCopy()); - tools::dilateVoxels(*mLeafs); - mLeafs->rebuildLeafArray(); - tools::changeLevelSetBackground(leafs(), mDx + mGrid->background()); - BoolMaskType mask(mGrid->tree(), false, TopologyCopy()); - mask.topologyDifference(mask0); - this->normalize(&mask); - } - } -} - -template -inline void -LevelSetTracker:: -erode(int iterations) -{ - tools::erodeVoxels(*mLeafs, iterations); - mLeafs->rebuildLeafArray(); - const ValueType background = mGrid->background() - iterations*mDx; - tools::changeLevelSetBackground(leafs(), background); -} - -template -inline void -LevelSetTracker:: -startInterrupter(const char* msg) -{ - if (mInterrupter) mInterrupter->start(msg); -} - -template -inline void -LevelSetTracker:: -endInterrupter() -{ - if (mInterrupter) mInterrupter->end(); -} - -template -inline bool -LevelSetTracker:: -checkInterrupter() -{ - if (util::wasInterrupted(mInterrupter)) { - tbb::task::self().cancel_group_execution(); - return false; - } - return true; -} - -template -template -inline void -LevelSetTracker:: -normalize(const MaskT* mask) -{ - switch (mSpatialScheme) { - case math::FIRST_BIAS: - this->normalize1(mask); break; - case math::SECOND_BIAS: - this->normalize1(mask); break; - case math::THIRD_BIAS: - this->normalize1(mask); break; - case math::WENO5_BIAS: - this->normalize1(mask); break; - case math::HJWENO5_BIAS: - this->normalize1(mask); break; - default: - OPENVDB_THROW(ValueError, "Spatial difference scheme not supported!"); - } -} - -template -template -inline void -LevelSetTracker:: -normalize1(const MaskT* mask) -{ - switch (mTemporalScheme) { - case math::TVD_RK1: - this->normalize2(mask); break; - case math::TVD_RK2: - this->normalize2(mask); break; - case math::TVD_RK3: - this->normalize2(mask); break; - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - } -} - -template -template -inline void -LevelSetTracker:: -normalize2(const MaskT* mask) -{ - Normalizer tmp(*this, mask); - tmp.normalize(); -} - -//////////////////////////////////////////////////////////////////////////// - -template -inline void -LevelSetTracker:: -Trim::trim() -{ - const int grainSize = mTracker.getGrainSize(); - if (grainSize>0) { - tbb::parallel_for(mTracker.mLeafs->getRange(grainSize), *this); - } else { - (*this)(mTracker.mLeafs->getRange()); - } -} - -/// Prunes away voxels that have moved outside the narrow band -template -inline void -LevelSetTracker:: -Trim::operator()(const RangeType& range) const -{ - typedef typename LeafType::ValueOnIter VoxelIterT; - mTracker.checkInterrupter(); - const ValueType gamma = mTracker.mGrid->background(); - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - LeafType &leaf = mTracker.mLeafs->leaf(n); - for (VoxelIterT iter = leaf.beginValueOn(); iter; ++iter) { - const ValueType val = *iter; - if (val <= -gamma) - leaf.setValueOff(iter.pos(), -gamma); - else if (val >= gamma) - leaf.setValueOff(iter.pos(), gamma); - } - } -} - -//////////////////////////////////////////////////////////////////////////// - -template -template -inline -LevelSetTracker:: -Normalizer:: -Normalizer(LevelSetTracker& tracker, const MaskT* mask) - : mTracker(tracker) - , mMask(mask) - , mDt(tracker.voxelSize()*(TemporalScheme == math::TVD_RK1 ? 0.3f : - TemporalScheme == math::TVD_RK2 ? 0.9f : 1.0f)) - , mInvDx(1.0f/tracker.voxelSize()) - , mTask(0) -{ -} - -template -template -inline void -LevelSetTracker:: -Normalizer:: -normalize() -{ - /// Make sure we have enough temporal auxiliary buffers - mTracker.mLeafs->rebuildAuxBuffers(TemporalScheme == math::TVD_RK3 ? 2 : 1); - - for (int n=0, e=mTracker.getNormCount(); n < e; ++n) { - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - switch(TemporalScheme) {//switch is resolved at compile-time - case math::TVD_RK1: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(0) = Phi_t0(0) - dt * VdotG_t0(1) - mTask = boost::bind(&Normalizer::euler01, _1, _2); - - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(1); - break; - case math::TVD_RK2: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(1) - mTask = boost::bind(&Normalizer::euler01, _1, _2); - - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(1); - - // Convex combine explict Euler step: t2 = t0 + dt - // Phi_t2(1) = 1/2 * Phi_t0(1) + 1/2 * (Phi_t1(0) - dt * V.Grad_t1(0)) - mTask = boost::bind(&Normalizer::euler12, _1, _2, /*phi=*/1, /*result=*/1); - - // Cook and swap buffer 0 and 1 such that Phi_t2(0) and Phi_t1(1) - this->cook(1); - break; - case math::TVD_RK3: - // Perform one explicit Euler step: t1 = t0 + dt - // Phi_t1(1) = Phi_t0(0) - dt * VdotG_t0(1) - mTask = boost::bind(&Normalizer::euler01, _1, _2); - - // Cook and swap buffer 0 and 1 such that Phi_t1(0) and Phi_t0(1) - this->cook(1); - - // Convex combine explict Euler step: t2 = t0 + dt/2 - // Phi_t2(2) = 3/4 * Phi_t0(1) + 1/4 * (Phi_t1(0) - dt * V.Grad_t1(0)) - mTask = boost::bind(&Normalizer::euler34, _1, _2, /*phi=*/1, /*result=*/2); - - // Cook and swap buffer 0 and 2 such that Phi_t2(0) and Phi_t1(2) - this->cook(2); - - // Convex combine explict Euler step: t3 = t0 + dt - // Phi_t3(2) = 1/3 * Phi_t0(1) + 2/3 * (Phi_t2(0) - dt * V.Grad_t2(0) - mTask = boost::bind(&Normalizer::euler13, _1, _2, /*phi=*/1, /*result=*/2); - - // Cook and swap buffer 0 and 2 such that Phi_t3(0) and Phi_t2(2) - this->cook(2); - break; - default: - OPENVDB_THROW(ValueError, "Temporal integration scheme not supported!"); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - mTracker.mLeafs->removeAuxBuffers(); -} - -/// Private method to perform the task (serial or threaded) and -/// subsequently swap the leaf buffers. -template -template -inline void -LevelSetTracker:: -Normalizer:: -cook(int swapBuffer) -{ - mTracker.startInterrupter("Normalizing Level Set"); - - if (mTracker.getGrainSize()>0) { - tbb::parallel_for(mTracker.mLeafs->getRange(mTracker.getGrainSize()), *this); - } else { - (*this)(mTracker.mLeafs->getRange()); - } - - mTracker.mLeafs->swapLeafBuffer(swapBuffer, mTracker.getGrainSize()==0); - - mTracker.endInterrupter(); -} - -template -template -template -inline void -LevelSetTracker:: -Normalizer:: -eval(StencilT& stencil, const BufferType& phi, BufferType& result, Index n) const -{ - typedef typename math::ISGradientNormSqrd GradientT; - static const ValueType alpha = ValueType(Nominator)/ValueType(Denominator); - static const ValueType beta = ValueType(1) - alpha; - - const ValueType normSqGradPhi = GradientT::result(stencil); - const ValueType phi0 = stencil.getValue(); - ValueType v = phi0 / (math::Sqrt(math::Pow2(phi0) + normSqGradPhi)); - v = phi0 - mDt * v * (math::Sqrt(normSqGradPhi) * mInvDx - 1.0f); - result.setValue(n, Nominator ? alpha * phi[n] + beta * v : v); -} - -template -template -template -inline void -LevelSetTracker:: -Normalizer:: -euler(const RangeType& range, Index phiBuffer, Index resultBuffer) -{ - typedef typename LeafType::ValueOnCIter VoxelIterT; - - mTracker.checkInterrupter(); - - StencilT stencil(mTracker.grid()); - - for (size_t n=range.begin(), e=range.end(); n != e; ++n) { - const BufferType& phi = mTracker.mLeafs->getBuffer(n, phiBuffer); - BufferType& result = mTracker.mLeafs->getBuffer(n, resultBuffer); - const LeafType& leaf = mTracker.mLeafs->leaf(n); - - if (mMask == NULL) { - for (VoxelIterT iter = leaf.cbeginValueOn(); iter; ++iter) { - stencil.moveTo(iter); - this->eval(stencil, phi, result, iter.pos()); - }//loop over active voxels in the leaf of the level set - } else if (const MaskLeafT* mask = mMask->probeLeaf(leaf.origin())) { - for (MaskIterT iter = mask->cbeginValueOn(); iter; ++iter) { - const Index i = iter.pos(); - stencil.moveTo(iter.getCoord(), leaf.getValue(i)); - this->eval(stencil, phi, result, i); - }//loop over active voxels in the leaf of the mask - } - }//loop over leafs of the level set -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVEL_SET_TRACKER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/LevelSetUtil.h b/openvdb_3_0_0_library/tools/LevelSetUtil.h deleted file mode 100755 index 29ae5f2..0000000 --- a/openvdb_3_0_0_library/tools/LevelSetUtil.h +++ /dev/null @@ -1,400 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file tools/LevelSetUtil.h -/// -/// @brief Miscellaneous utilities that operate primarily or exclusively -/// on level set grids - -#ifndef OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -// MS Visual C++ requires this extra level of indirection in order to compile -// THIS MUST EXIST IN AN UNNAMED NAMESPACE IN ORDER TO COMPILE ON WINDOWS -namespace { - -template -inline typename GridType::ValueType lsutilGridMax() -{ - return std::numeric_limits::max(); -} - -template -inline typename GridType::ValueType lsutilGridZero() -{ - return zeroVal(); -} - -} // unnamed namespace - - -//////////////////////////////////////// - - -/// @brief Threaded method to convert a sparse level set/SDF into a sparse fog volume -/// -/// @details For a level set, the active and negative-valued interior half of the -/// narrow band becomes a linear ramp from 0 to 1; the inactive interior becomes -/// active with a constant value of 1; and the exterior, including the background -/// and the active exterior half of the narrow band, becomes inactive with a constant -/// value of 0. The interior, though active, remains sparse. -/// @details For a generic SDF, a specified cutoff distance determines the width -/// of the ramp, but otherwise the result is the same as for a level set. -/// -/// @param grid level set/SDF grid to transform -/// @param cutoffDistance optional world space cutoff distance for the ramp -/// (automatically clamped if greater than the interior -/// narrow band width) -template -inline void -sdfToFogVolume( - GridType& grid, - typename GridType::ValueType cutoffDistance = lsutilGridMax()); - - -//////////////////////////////////////// - - -/// @brief Threaded method to extract an interior region mask from a level set/SDF grid -/// -/// @return a shared pointer to a new boolean grid with the same tree configuration and -/// transform as the incoming @c grid and whose active voxels correspond to -/// the interior of the input SDF -/// -/// @param grid a level set/SDF grid -/// @param iso threshold below which values are considered to be part of the interior region -/// -template -inline typename Grid::Type>::Ptr -sdfInteriorMask( - const GridType& grid, - typename GridType::ValueType iso = lsutilGridZero()); - - -//////////////////////////////////////// - - -/// @brief Threaded operator that finds the minimum and maximum values -/// among the active leaf-level voxels of a grid -/// @details This is useful primarily for level set grids, which have -/// no active tiles (all of their active voxels are leaf-level). -template -class MinMaxVoxel -{ -public: - typedef tree::LeafManager LeafArray; - typedef typename TreeType::ValueType ValueType; - - // LeafArray = openvdb::tree::LeafManager leafs(myTree) - MinMaxVoxel(LeafArray&); - - void runParallel(); - void runSerial(); - - const ValueType& minVoxel() const { return mMin; } - const ValueType& maxVoxel() const { return mMax; } - - inline MinMaxVoxel(const MinMaxVoxel&, tbb::split); - inline void operator()(const tbb::blocked_range&); - inline void join(const MinMaxVoxel&); - -private: - LeafArray& mLeafArray; - ValueType mMin, mMax; -}; - - -//////////////////////////////////////// - - -// Internal utility objects and implementation details -namespace internal { - -template -class FogVolumeOp -{ -public: - FogVolumeOp(ValueType cutoffDistance) - : mWeight(ValueType(1.0) / cutoffDistance) - { - } - - // cutoff has to be < 0.0 - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - const ValueType zero = zeroVal(); - - for (typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll(); iter; ++iter) { - ValueType& value = const_cast(iter.getValue()); - if (value > zero) { - value = zero; - iter.setValueOff(); - } else { - value = std::min(ValueType(1.0), value * mWeight); - iter.setValueOn(value > zero); - } - } - } - -private: - ValueType mWeight; -}; // class FogVolumeOp - - -template -class InteriorMaskOp -{ -public: - InteriorMaskOp(const TreeType& tree, typename TreeType::ValueType iso) - : mTree(tree) - , mIso(iso) - { - } - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - const Coord origin = leaf.origin(); - const typename TreeType::LeafNodeType* refLeafPt = mTree.probeConstLeaf(origin); - - if (refLeafPt != NULL) { - - const typename TreeType::LeafNodeType& refLeaf = *refLeafPt; - typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll(); - - for (; iter; ++iter) { - if (refLeaf.getValue(iter.pos()) < mIso) { - iter.setValueOn(); - } else { - iter.setValueOff(); - } - } - } - } - -private: - const TreeType& mTree; - typename TreeType::ValueType mIso; -}; // class InteriorMaskOp - -} // namespace internal - - -//////////////////////////////////////// - - -template -MinMaxVoxel::MinMaxVoxel(LeafArray& leafs) - : mLeafArray(leafs) - , mMin(std::numeric_limits::max()) - , mMax(-mMin) -{ -} - - -template -inline -MinMaxVoxel::MinMaxVoxel(const MinMaxVoxel& rhs, tbb::split) - : mLeafArray(rhs.mLeafArray) - , mMin(rhs.mMin) - , mMax(rhs.mMax) -{ -} - - -template -void -MinMaxVoxel::runParallel() -{ - tbb::parallel_reduce(mLeafArray.getRange(), *this); -} - - -template -void -MinMaxVoxel::runSerial() -{ - (*this)(mLeafArray.getRange()); -} - - -template -inline void -MinMaxVoxel::operator()(const tbb::blocked_range& range) -{ - typename TreeType::LeafNodeType::ValueOnCIter iter; - - for (size_t n = range.begin(); n < range.end(); ++n) { - iter = mLeafArray.leaf(n).cbeginValueOn(); - for (; iter; ++iter) { - const ValueType value = iter.getValue(); - mMin = std::min(mMin, value); - mMax = std::max(mMax, value); - } - } -} - - -template -inline void -MinMaxVoxel::join(const MinMaxVoxel& rhs) -{ - mMin = std::min(mMin, rhs.mMin); - mMax = std::max(mMax, rhs.mMax); -} - - - -//////////////////////////////////////// - - -template -inline void -sdfToFogVolume(GridType& grid, typename GridType::ValueType cutoffDistance) -{ - typedef typename GridType::TreeType TreeType; - typedef typename GridType::ValueType ValueType; - - cutoffDistance = -std::abs(cutoffDistance); - - TreeType& tree = const_cast(grid.tree()); - - { // Transform all voxels (parallel, over leaf nodes) - tree::LeafManager leafs(tree); - - MinMaxVoxel minmax(leafs); - minmax.runParallel(); - - // Clamp to the interior band width. - if (minmax.minVoxel() > cutoffDistance) { - cutoffDistance = minmax.minVoxel(); - } - - leafs.foreach(internal::FogVolumeOp(cutoffDistance)); - } - - // Transform all tile values (serial, but the iteration - // is constrained from descending into leaf nodes) - const ValueType zero = zeroVal(); - typename TreeType::ValueAllIter iter(tree); - iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1); - - for ( ; iter; ++iter) { - ValueType& value = const_cast(iter.getValue()); - - if (value > zero) { - value = zero; - iter.setValueOff(); - } else { - value = ValueType(1.0); - iter.setActiveState(true); - } - } - - // Update the tree background value. - - typename TreeType::Ptr newTree(new TreeType(/*background=*/zero)); - newTree->merge(tree); - // This is faster than calling Tree::setBackground, since we only need - // to update the value that is returned for coordinates that don't fall - // inside an allocated node. All inactive tiles and voxels have already - // been updated in the previous step so the Tree::setBackground method - // will in this case do a redundant traversal of the tree to update the - // inactive values once more. - - //newTree->pruneInactive(); - grid.setTree(newTree); - - grid.setGridClass(GRID_FOG_VOLUME); -} - - -//////////////////////////////////////// - - -template -inline typename Grid::Type>::Ptr -sdfInteriorMask(const GridType& grid, typename GridType::ValueType iso) -{ - typedef typename GridType::TreeType::template ValueConverter::Type BoolTreeType; - typedef Grid BoolGridType; - - typename BoolGridType::Ptr maskGrid(BoolGridType::create(false)); - maskGrid->setTransform(grid.transform().copy()); - BoolTreeType& maskTree = maskGrid->tree(); - - maskTree.topologyUnion(grid.tree()); - - { // Evaluate voxels (parallel, over leaf nodes) - - tree::LeafManager leafs(maskTree); - - leafs.foreach(internal::InteriorMaskOp(grid.tree(), iso)); - } - - // Evaluate tile values (serial, but the iteration - // is constrained from descending into leaf nodes) - - tree::ValueAccessor acc(grid.tree()); - typename BoolTreeType::ValueAllIter iter(maskTree); - iter.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 1); - - for ( ; iter; ++iter) { - iter.setActiveState(acc.getValue(iter.getCoord()) < iso); - } - - tools::pruneInactive(maskTree); - - return maskGrid; -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/MeshToVolume.h b/openvdb_3_0_0_library/tools/MeshToVolume.h deleted file mode 100755 index 1016c7c..0000000 --- a/openvdb_3_0_0_library/tools/MeshToVolume.h +++ /dev/null @@ -1,3235 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED - -#include -#include -#include // for ISGradientNormSqrd -#include // for closestPointOnTriangleToPoint() -#include // for dilateVoxels() -#include -#include // for nearestCoord() -#include "ChangeBackground.h" -#include "Prune.h"// for pruneInactive and pruneLevelSet -#include "SignedFloodFill.h" // for signedFloodFillWithValues - -#include -#include -#include - -#include // for isfinite() - -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -//////////////////////////////////////// - - -// Wrapper functions for the MeshToVolume converter - - -/// @brief Convert a triangle mesh to a level set volume. -/// -/// @return a grid of type @c GridType containing a narrow-band level set -/// representation of the input mesh. -/// -/// @throw TypeError if @c GridType is not scalar or not floating-point -/// -/// @note Requires a closed surface but not necessarily a manifold surface. -/// Supports surfaces with self intersections and degenerate faces -/// and is independent of mesh surface normals. -/// -/// @param xform transform for the output grid -/// @param points list of world space point positions -/// @param triangles triangle index list -/// @param halfWidth half the width of the narrow band, in voxel units -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - float halfWidth = float(LEVEL_SET_HALF_WIDTH)); - - -/// @brief Convert a quad mesh to a level set volume. -/// -/// @return a grid of type @c GridType containing a narrow-band level set -/// representation of the input mesh. -/// -/// @throw TypeError if @c GridType is not scalar or not floating-point -/// -/// @note Requires a closed surface but not necessarily a manifold surface. -/// Supports surfaces with self intersections and degenerate faces -/// and is independent of mesh surface normals. -/// -/// @param xform transform for the output grid -/// @param points list of world space point positions -/// @param quads quad index list -/// @param halfWidth half the width of the narrow band, in voxel units -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& quads, - float halfWidth = float(LEVEL_SET_HALF_WIDTH)); - - -/// @brief Convert a triangle and quad mesh to a level set volume. -/// -/// @return a grid of type @c GridType containing a narrow-band level set -/// representation of the input mesh. -/// -/// @throw TypeError if @c GridType is not scalar or not floating-point -/// -/// @note Requires a closed surface but not necessarily a manifold surface. -/// Supports surfaces with self intersections and degenerate faces -/// and is independent of mesh surface normals. -/// -/// @param xform transform for the output grid -/// @param points list of world space point positions -/// @param triangles triangle index list -/// @param quads quad index list -/// @param halfWidth half the width of the narrow band, in voxel units -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float halfWidth = float(LEVEL_SET_HALF_WIDTH)); - - -/// @brief Convert a triangle and quad mesh to a signed distance field -/// with an asymmetrical narrow band. -/// -/// @return a grid of type @c GridType containing a narrow-band signed -/// distance field representation of the input mesh. -/// -/// @throw TypeError if @c GridType is not scalar or not floating-point -/// -/// @note Requires a closed surface but not necessarily a manifold surface. -/// Supports surfaces with self intersections and degenerate faces -/// and is independent of mesh surface normals. -/// -/// @param xform transform for the output grid -/// @param points list of world space point positions -/// @param triangles triangle index list -/// @param quads quad index list -/// @param exBandWidth the exterior narrow-band width in voxel units -/// @param inBandWidth the interior narrow-band width in voxel units -template -inline typename GridType::Ptr -meshToSignedDistanceField( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float exBandWidth, - float inBandWidth); - - -/// @brief Convert a triangle and quad mesh to an unsigned distance field. -/// -/// @return a grid of type @c GridType containing a narrow-band unsigned -/// distance field representation of the input mesh. -/// -/// @throw TypeError if @c GridType is not scalar or not floating-point -/// -/// @note Does not requires a closed surface. -/// -/// @param xform transform for the output grid -/// @param points list of world space point positions -/// @param triangles triangle index list -/// @param quads quad index list -/// @param bandWidth the width of the narrow band, in voxel units -template -inline typename GridType::Ptr -meshToUnsignedDistanceField( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float bandWidth); - - -//////////////////////////////////////// - - -/// Conversion flags, used to control the MeshToVolume output -enum { GENERATE_PRIM_INDEX_GRID = 0x1, OUTPUT_RAW_DATA = 0x2}; - - -// MeshToVolume -template -class MeshToVolume -{ -public: - typedef typename FloatGridT::TreeType FloatTreeT; - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef Grid IntGridT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef Grid BoolGridT; - - MeshToVolume(openvdb::math::Transform::Ptr&, int conversionFlags = 0, - InterruptT *interrupter = NULL, int signSweeps = 1); - - /// @brief Mesh to Level Set / Signed Distance Field conversion - /// - /// @note Requires a closed surface but not necessarily a manifold surface. - /// Supports surfaces with self intersections, degenerate faces and - /// is independent of mesh surface normals. - /// - /// @param pointList List of points in grid index space, preferably unique - /// and shared by different polygons. - /// @param polygonList List of triangles and/or quads. - /// @param exBandWidth The exterior narrow-band width in voxel units. - /// @param inBandWidth The interior narrow-band width in voxel units. - void convertToLevelSet( - const std::vector& pointList, - const std::vector& polygonList, - FloatValueT exBandWidth = FloatValueT(LEVEL_SET_HALF_WIDTH), - FloatValueT inBandWidth = FloatValueT(LEVEL_SET_HALF_WIDTH)); - - /// @brief Mesh to Unsigned Distance Field conversion - /// - /// @note Does not requires a closed surface. - /// - /// @param pointList List of points in grid index space, preferably unique - /// and shared by different polygons. - /// @param polygonList List of triangles and/or quads. - /// @param exBandWidth The narrow-band width in voxel units. - void convertToUnsignedDistanceField(const std::vector& pointList, - const std::vector& polygonList, FloatValueT exBandWidth); - - void clear(); - - /// Returns a narrow-band (signed) distance field / level set grid. - typename FloatGridT::Ptr distGridPtr() const { return mDistGrid; } - - /// Returns a grid containing the closest-primitive index for each - /// voxel in the narrow-band. - typename IntGridT::Ptr indexGridPtr() const { return mIndexGrid; } - -private: - // disallow copy by assignment - void operator=(const MeshToVolume&) {} - - void doConvert(const std::vector&, const std::vector&, - FloatValueT exBandWidth, FloatValueT inBandWidth, bool unsignedDistField = false); - - bool wasInterrupted(int percent = -1) const { - return mInterrupter && mInterrupter->wasInterrupted(percent); - } - - openvdb::math::Transform::Ptr mTransform; - int mConversionFlags, mSignSweeps; - - typename FloatGridT::Ptr mDistGrid; - typename IntGridT::Ptr mIndexGrid; - typename BoolGridT::Ptr mIntersectingVoxelsGrid; - - InterruptT *mInterrupter; -}; - - -//////////////////////////////////////// - - -/// @brief Extracts and stores voxel edge intersection data from a mesh. -class MeshToVoxelEdgeData -{ -public: - - ////////// - - ///@brief Internal edge data type. - struct EdgeData { - EdgeData(float dist = 1.0) - : mXDist(dist), mYDist(dist), mZDist(dist) - , mXPrim(util::INVALID_IDX) - , mYPrim(util::INVALID_IDX) - , mZPrim(util::INVALID_IDX) - { - } - - //@{ - /// Required by several of the tree nodes - /// @note These methods don't perform meaningful operations. - bool operator< (const EdgeData&) const { return false; } - bool operator> (const EdgeData&) const { return false; } - template EdgeData operator+(const T&) const { return *this; } - template EdgeData operator-(const T&) const { return *this; } - EdgeData operator-() const { return *this; } - //@} - - bool operator==(const EdgeData& rhs) const - { - return mXPrim == rhs.mXPrim && mYPrim == rhs.mYPrim && mZPrim == rhs.mZPrim; - } - - float mXDist, mYDist, mZDist; - Index32 mXPrim, mYPrim, mZPrim; - }; - - typedef tree::Tree4::Type TreeType; - typedef tree::ValueAccessor Accessor; - - - ////////// - - - MeshToVoxelEdgeData(); - - - /// @brief Threaded method to extract voxel edge data, the closest - /// intersection point and corresponding primitive index, - /// from the given mesh. - /// - /// @param pointList List of points in grid index space, preferably unique - /// and shared by different polygons. - /// @param polygonList List of triangles and/or quads. - void convert(const std::vector& pointList, const std::vector& polygonList); - - - /// @brief Returns intersection points with corresponding primitive - /// indices for the given @c ijk voxel. - void getEdgeData(Accessor& acc, const Coord& ijk, - std::vector& points, std::vector& primitives); - - /// @return An accessor of @c MeshToVoxelEdgeData::Accessor type that - /// provides random read access to the internal tree. - Accessor getAccessor() { return Accessor(mTree); } - -private: - void operator=(const MeshToVoxelEdgeData&) {} - TreeType mTree; - class GenEdgeData; -}; - - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - - -// Internal utility objects and implementation details - -namespace internal { - - -class PointTransform -{ -public: - PointTransform(const std::vector& pointsIn, std::vector& pointsOut, - const math::Transform& xform) - : mPointsIn(pointsIn) - , mPointsOut(&pointsOut) - , mXform(xform) - { - } - - void run(bool threaded = true) - { - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mPointsOut->size()), *this); - } else { - (*this)(tbb::blocked_range(0, mPointsOut->size())); - } - } - - inline void operator()(const tbb::blocked_range& range) const - { - for (size_t n = range.begin(); n < range.end(); ++n) { - (*mPointsOut)[n] = Vec3s(mXform.worldToIndex(mPointsIn[n])); - } - } - -private: - const std::vector& mPointsIn; - std::vector * const mPointsOut; - const math::Transform& mXform; -}; - - -template -struct Tolerance -{ - static ValueType epsilon() { return ValueType(1e-7); } - static ValueType minNarrowBandWidth() { return ValueType(1.0 + 1e-6); } -}; - - -template -inline void -combine(FloatTreeT& lhsDist, IntTreeT& lhsIndex, FloatTreeT& rhsDist, IntTreeT& rhsIndex) -{ - typedef typename FloatTreeT::ValueType FloatValueT; - typename tree::ValueAccessor lhsDistAccessor(lhsDist); - typename tree::ValueAccessor lhsIndexAccessor(lhsIndex); - typename tree::ValueAccessor rhsIndexAccessor(rhsIndex); - typename FloatTreeT::LeafCIter iter = rhsDist.cbeginLeaf(); - - FloatValueT rhsValue; - Coord ijk; - - for ( ; iter; ++iter) { - typename FloatTreeT::LeafNodeType::ValueOnCIter it = iter->cbeginValueOn(); - - for ( ; it; ++it) { - - ijk = it.getCoord(); - rhsValue = it.getValue(); - FloatValueT& lhsValue = const_cast(lhsDistAccessor.getValue(ijk)); - - if (-rhsValue < std::abs(lhsValue)) { - lhsValue = rhsValue; - lhsIndexAccessor.setValue(ijk, rhsIndexAccessor.getValue(ijk)); - } - } - } -} - - -//////////////////////////////////////// - - -/// MeshVoxelizer -/// @brief TBB body object to voxelize a mesh of triangles and/or quads into a collection -/// of VDB grids, namely a squared distance grid, a closest primitive grid and an -/// intersecting voxels grid (masks the mesh intersecting voxels) -/// @note Only the leaf nodes that intersect the mesh are allocated, and only voxels in -/// a narrow band (of two to three voxels in proximity to the mesh's surface) are activated. -/// They are populated with distance values and primitive indices. -template -class MeshVoxelizer -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename FloatTreeT::LeafNodeType FloatLeafT; - typedef typename tree::ValueAccessor FloatAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef typename tree::ValueAccessor IntAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef typename tree::ValueAccessor BoolAccessorT; - - - MeshVoxelizer(const std::vector& pointList, - const std::vector& polygonList, InterruptT *interrupter = NULL); - - ~MeshVoxelizer() {} - - void run(bool threaded = true); - - MeshVoxelizer(MeshVoxelizer& rhs, tbb::split); - void operator() (const tbb::blocked_range &range); - void join(MeshVoxelizer& rhs); - - FloatTreeT& sqrDistTree() { return mSqrDistTree; } - IntTreeT& primIndexTree() { return mPrimIndexTree; } - BoolTreeT& intersectionTree() { return mIntersectionTree; } - -private: - // disallow copy by assignment - void operator=(const MeshVoxelizer&) {} - bool wasInterrupted() const { return mInterrupter && mInterrupter->wasInterrupted(); } - - bool evalVoxel(const Coord& ijk, const Int32 polyIdx); - - const std::vector& mPointList; - const std::vector& mPolygonList; - - FloatTreeT mSqrDistTree; - FloatAccessorT mSqrDistAccessor; - - IntTreeT mPrimIndexTree; - IntAccessorT mPrimIndexAccessor; - - BoolTreeT mIntersectionTree; - BoolAccessorT mIntersectionAccessor; - - // Used internally for acceleration - IntTreeT mLastPrimTree; - IntAccessorT mLastPrimAccessor; - - InterruptT *mInterrupter; - - - struct Primitive { Vec3d a, b, c, d; Int32 index; }; - - template - bool evalPrimitive(const Coord&, const Primitive&); - - template - void voxelize(const Primitive&); -}; - - -template -void -MeshVoxelizer::run(bool threaded) -{ - if (threaded) { - tbb::parallel_reduce(tbb::blocked_range(0, mPolygonList.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mPolygonList.size())); - } -} - -template -MeshVoxelizer::MeshVoxelizer( - const std::vector& pointList, const std::vector& polygonList, - InterruptT *interrupter) - : mPointList(pointList) - , mPolygonList(polygonList) - , mSqrDistTree(std::numeric_limits::max()) - , mSqrDistAccessor(mSqrDistTree) - , mPrimIndexTree(Int32(util::INVALID_IDX)) - , mPrimIndexAccessor(mPrimIndexTree) - , mIntersectionTree(false) - , mIntersectionAccessor(mIntersectionTree) - , mLastPrimTree(Int32(util::INVALID_IDX)) - , mLastPrimAccessor(mLastPrimTree) - , mInterrupter(interrupter) -{ -} - -template -MeshVoxelizer::MeshVoxelizer( - MeshVoxelizer& rhs, tbb::split) - : mPointList(rhs.mPointList) - , mPolygonList(rhs.mPolygonList) - , mSqrDistTree(std::numeric_limits::max()) - , mSqrDistAccessor(mSqrDistTree) - , mPrimIndexTree(Int32(util::INVALID_IDX)) - , mPrimIndexAccessor(mPrimIndexTree) - , mIntersectionTree(false) - , mIntersectionAccessor(mIntersectionTree) - , mLastPrimTree(Int32(util::INVALID_IDX)) - , mLastPrimAccessor(mLastPrimTree) - , mInterrupter(rhs.mInterrupter) -{ -} - - -template -void -MeshVoxelizer::operator()(const tbb::blocked_range &range) -{ - Primitive prim; - - for (size_t n = range.begin(); n < range.end(); ++n) { - - if (mInterrupter && mInterrupter->wasInterrupted()) { - tbb::task::self().cancel_group_execution(); - break; - } - - const Vec4I& verts = mPolygonList[n]; - - prim.index = Int32(n); - prim.a = Vec3d(mPointList[verts[0]]); - prim.b = Vec3d(mPointList[verts[1]]); - prim.c = Vec3d(mPointList[verts[2]]); - - if (util::INVALID_IDX != verts[3]) { - prim.d = Vec3d(mPointList[verts[3]]); - voxelize(prim); - } else { - voxelize(prim); - } - } -} - - -template -template -void -MeshVoxelizer::voxelize(const Primitive& prim) -{ - std::deque coordList; - Coord ijk, nijk; - - ijk = util::nearestCoord(prim.a); - coordList.push_back(ijk); - - evalPrimitive(ijk, prim); - - while (!coordList.empty()) { - if(wasInterrupted()) break; - - ijk = coordList.back(); - coordList.pop_back(); - - mIntersectionAccessor.setActiveState(ijk, true); - - for (Int32 i = 0; i < 26; ++i) { - nijk = ijk + util::COORD_OFFSETS[i]; - if (prim.index != mLastPrimAccessor.getValue(nijk)) { - mLastPrimAccessor.setValue(nijk, prim.index); - if(evalPrimitive(nijk, prim)) coordList.push_back(nijk); - } - } - } -} - - -template -template -bool -MeshVoxelizer::evalPrimitive(const Coord& ijk, const Primitive& prim) -{ - Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]); - - // Evaluate first triangle - FloatValueT dist = FloatValueT((voxelCenter - - closestPointOnTriangleToPoint(prim.a, prim.c, prim.b, voxelCenter, uvw)).lengthSqr()); - - if (IsQuad) { - // Split quad into a second triangle and calculate distance. - FloatValueT secondDist = FloatValueT((voxelCenter - - closestPointOnTriangleToPoint(prim.a, prim.d, prim.c, voxelCenter, uvw)).lengthSqr()); - - if (secondDist < dist) dist = secondDist; - } - - FloatValueT oldDist = std::abs(mSqrDistAccessor.getValue(ijk)); - - if (dist < oldDist) { - mSqrDistAccessor.setValue(ijk, -dist); - mPrimIndexAccessor.setValue(ijk, prim.index); - } else if (math::isExactlyEqual(dist, oldDist)) { - // makes reduction deterministic when different polygons - // produce the same distance value. - mPrimIndexAccessor.setValue(ijk, std::min(prim.index, mPrimIndexAccessor.getValue(ijk))); - } - - return (dist < 0.86602540378443861); -} - - -template -void -MeshVoxelizer::join(MeshVoxelizer& rhs) -{ - typedef typename FloatTreeT::RootNodeType FloatRootNodeT; - typedef typename FloatRootNodeT::NodeChainType FloatNodeChainT; - BOOST_STATIC_ASSERT(boost::mpl::size::value > 1); - typedef typename boost::mpl::at >::type FloatInternalNodeT; - - typedef typename IntTreeT::RootNodeType IntRootNodeT; - typedef typename IntRootNodeT::NodeChainType IntNodeChainT; - BOOST_STATIC_ASSERT(boost::mpl::size::value > 1); - typedef typename boost::mpl::at >::type IntInternalNodeT; - - const FloatValueT background = std::numeric_limits::max(); - - Coord ijk; - Index offset; - - rhs.mSqrDistTree.clearAllAccessors(); - rhs.mPrimIndexTree.clearAllAccessors(); - - typename FloatTreeT::LeafIter leafIt = rhs.mSqrDistTree.beginLeaf(); - for ( ; leafIt; ++leafIt) { - - ijk = leafIt->origin(); - FloatLeafT* lhsDistLeafPt = mSqrDistAccessor.probeLeaf(ijk); - - if (!lhsDistLeafPt) { - - // Steals leaf nodes through their parent, always the last internal-node - // stored in the ValueAccessor's node chain, avoiding the overhead of - // the root node. This is significantly faster than going through the - // tree or root node. - mSqrDistAccessor.addLeaf(rhs.mSqrDistAccessor.probeLeaf(ijk)); - FloatInternalNodeT* floatNode = - rhs.mSqrDistAccessor.template getNode(); - floatNode->template stealNode(ijk, background, false); - - mPrimIndexAccessor.addLeaf(rhs.mPrimIndexAccessor.probeLeaf(ijk)); - IntInternalNodeT* intNode = - rhs.mPrimIndexAccessor.template getNode(); - intNode->template stealNode(ijk, util::INVALID_IDX, false); - - } else { - - IntLeafT* lhsIdxLeafPt = mPrimIndexAccessor.probeLeaf(ijk); - IntLeafT* rhsIdxLeafPt = rhs.mPrimIndexAccessor.probeLeaf(ijk); - FloatValueT lhsValue, rhsValue; - - typename FloatLeafT::ValueOnCIter it = leafIt->cbeginValueOn(); - for ( ; it; ++it) { - - offset = it.pos(); - - lhsValue = std::abs(lhsDistLeafPt->getValue(offset)); - rhsValue = std::abs(it.getValue()); - - if (rhsValue < lhsValue) { - lhsDistLeafPt->setValueOn(offset, it.getValue()); - lhsIdxLeafPt->setValueOn(offset, rhsIdxLeafPt->getValue(offset)); - } else if (math::isExactlyEqual(rhsValue, lhsValue)) { - lhsIdxLeafPt->setValueOn(offset, - std::min(lhsIdxLeafPt->getValue(offset), rhsIdxLeafPt->getValue(offset))); - } - } - } - } - - mIntersectionTree.merge(rhs.mIntersectionTree); - - rhs.mSqrDistTree.clear(); - rhs.mPrimIndexTree.clear(); - rhs.mIntersectionTree.clear(); -} - - -//////////////////////////////////////// - - -// ContourTracer -/// @brief TBB body object that partitions a volume into 2D slices that can be processed -/// in parallel and marks the exterior contour of disjoint voxel sets in each slice -template -class ContourTracer -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename tree::ValueAccessor DistAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename tree::ValueAccessor BoolAccessorT; - - ContourTracer(FloatTreeT&, const BoolTreeT&, InterruptT *interrupter = NULL); - ~ContourTracer() {} - - void run(bool threaded = true); - - ContourTracer(const ContourTracer& rhs); - void operator()(const tbb::blocked_range &range) const; - -private: - void operator=(const ContourTracer&) {} - - int sparseScan(int slice) const; - - FloatTreeT& mDistTree; - DistAccessorT mDistAccessor; - - const BoolTreeT& mIntersectionTree; - BoolAccessorT mIntersectionAccessor; - - CoordBBox mBBox; - - /// List of value-depth dependant step sizes. - std::vector mStepSize; - - InterruptT *mInterrupter; -}; - - -template -void -ContourTracer::run(bool threaded) -{ - if (threaded) { - tbb::parallel_for(tbb::blocked_range(mBBox.min()[0], mBBox.max()[0]+1), *this); - } else { - (*this)(tbb::blocked_range(mBBox.min()[0], mBBox.max()[0]+1)); - } -} - - -template -ContourTracer::ContourTracer( - FloatTreeT& distTree, const BoolTreeT& intersectionTree, InterruptT *interrupter) - : mDistTree(distTree) - , mDistAccessor(mDistTree) - , mIntersectionTree(intersectionTree) - , mIntersectionAccessor(mIntersectionTree) - , mBBox(CoordBBox()) - , mStepSize(0) - , mInterrupter(interrupter) -{ - // Build the step size table for different tree value depths. - std::vector dims; - mDistTree.getNodeLog2Dims(dims); - - mStepSize.resize(dims.size()+1, 1); - Index exponent = 0; - for (int idx = static_cast(dims.size()) - 1; idx > -1; --idx) { - exponent += dims[idx]; - mStepSize[idx] = 1 << exponent; - } - - mDistTree.evalLeafBoundingBox(mBBox); - - // Make sure that mBBox coincides with the min and max corners of the internal nodes. - const int tileDim = mStepSize[0]; - - for (size_t i = 0; i < 3; ++i) { - - int n; - double diff = std::abs(double(mBBox.min()[i])) / double(tileDim); - - if (mBBox.min()[i] <= tileDim) { - n = int(std::ceil(diff)); - mBBox.min()[i] = - n * tileDim; - } else { - n = int(std::floor(diff)); - mBBox.min()[i] = n * tileDim; - } - - n = int(std::ceil(std::abs(double(mBBox.max()[i] - mBBox.min()[i])) / double(tileDim))); - mBBox.max()[i] = mBBox.min()[i] + n * tileDim; - } -} - - -template -ContourTracer::ContourTracer( - const ContourTracer &rhs) - : mDistTree(rhs.mDistTree) - , mDistAccessor(mDistTree) - , mIntersectionTree(rhs.mIntersectionTree) - , mIntersectionAccessor(mIntersectionTree) - , mBBox(rhs.mBBox) - , mStepSize(rhs.mStepSize) - , mInterrupter(rhs.mInterrupter) -{ -} - - -template -void -ContourTracer::operator()(const tbb::blocked_range &range) const -{ - // Slice up the volume and trace contours. - int iStep = 1; - for (int n = range.begin(); n < range.end(); n += iStep) { - - if (mInterrupter && mInterrupter->wasInterrupted()) { - tbb::task::self().cancel_group_execution(); - break; - } - - iStep = sparseScan(n); - } -} - - -template -int -ContourTracer::sparseScan(int slice) const -{ - bool lastVoxelWasOut = true; - int last_k = mBBox.min()[2]; - - Coord ijk(slice, mBBox.min()[1], mBBox.min()[2]); - Coord step(mStepSize[mDistAccessor.getValueDepth(ijk) + 1]); - Coord n_ijk; - - for (ijk[1] = mBBox.min()[1]; ijk[1] <= mBBox.max()[1]; ijk[1] += step[1]) { // j - - if (mInterrupter && mInterrupter->wasInterrupted()) { - break; - } - - step[1] = mStepSize[mDistAccessor.getValueDepth(ijk) + 1]; - step[0] = std::min(step[0], step[1]); - - for (ijk[2] = mBBox.min()[2]; ijk[2] <= mBBox.max()[2]; ijk[2] += step[2]) { // k - - step[2] = mStepSize[mDistAccessor.getValueDepth(ijk) + 1]; - step[1] = std::min(step[1], step[2]); - step[0] = std::min(step[0], step[2]); - - // If the current voxel is set? - if (mDistAccessor.isValueOn(ijk)) { - - // Is this a boundary voxel? - if (mIntersectionAccessor.isValueOn(ijk)) { - - lastVoxelWasOut = false; - last_k = ijk[2]; - - } else if (lastVoxelWasOut) { - - FloatValueT& val = const_cast(mDistAccessor.getValue(ijk)); - val = -val; // flip sign - - } else { - - FloatValueT val; - for (Int32 n = 3; n < 6; n += 2) { - n_ijk = ijk + util::COORD_OFFSETS[n]; - - if (mDistAccessor.probeValue(n_ijk, val) && val > 0) { - lastVoxelWasOut = true; - break; - } - } - - if (lastVoxelWasOut) { - - FloatValueT& v = const_cast(mDistAccessor.getValue(ijk)); - v = -v; // flip sign - - const int tmp_k = ijk[2]; - - // backtrace - for (--ijk[2]; ijk[2] >= last_k; --ijk[2]) { - if (mIntersectionAccessor.isValueOn(ijk)) break; - FloatValueT& vb = - const_cast(mDistAccessor.getValue(ijk)); - if (vb < FloatValueT(0.0)) vb = -vb; // flip sign - } - - last_k = tmp_k; - ijk[2] = tmp_k; - - } else { - last_k = std::min(ijk[2], last_k); - } - - } - - } // end isValueOn check - } // end k - } // end j - return step[0]; -} - - -//////////////////////////////////////// - - -/// @brief TBB body object that that finds seed points for the parallel flood fill. -template -class SignMask -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename FloatTreeT::LeafNodeType FloatLeafT; - typedef tree::LeafManager FloatLeafManager; - typedef typename tree::ValueAccessor FloatAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef typename tree::ValueAccessor BoolAccessorT; - typedef typename tree::ValueAccessor BoolConstAccessorT; - - - SignMask(const FloatLeafManager&, const FloatTreeT&, const BoolTreeT&, - InterruptT *interrupter = NULL); - - ~SignMask() {} - - void run(bool threaded = true); - - SignMask(SignMask& rhs, tbb::split); - void operator() (const tbb::blocked_range &range); - void join(SignMask& rhs); - - BoolTreeT& signMaskTree() { return mSignMaskTree; } - -private: - // disallow copy by assignment - void operator=(const SignMask&) {} - bool wasInterrupted() const { return mInterrupter && mInterrupter->wasInterrupted(); } - - const FloatLeafManager& mDistLeafs; - const FloatTreeT& mDistTree; - const BoolTreeT& mIntersectionTree; - - BoolTreeT mSignMaskTree; - - InterruptT *mInterrupter; -}; // class SignMask - - -template -SignMask::SignMask( - const FloatLeafManager& distLeafs, const FloatTreeT& distTree, - const BoolTreeT& intersectionTree, InterruptT *interrupter) - : mDistLeafs(distLeafs) - , mDistTree(distTree) - , mIntersectionTree(intersectionTree) - , mSignMaskTree(false) - , mInterrupter(interrupter) -{ -} - - -template -SignMask::SignMask( - SignMask& rhs, tbb::split) - : mDistLeafs(rhs.mDistLeafs) - , mDistTree(rhs.mDistTree) - , mIntersectionTree(rhs.mIntersectionTree) - , mSignMaskTree(false) - , mInterrupter(rhs.mInterrupter) -{ -} - - -template -void -SignMask::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mDistLeafs.getRange(), *this); - else (*this)(mDistLeafs.getRange()); -} - - -template -void -SignMask::operator()(const tbb::blocked_range &range) -{ - FloatAccessorT distAcc(mDistTree); - BoolConstAccessorT intersectionAcc(mIntersectionTree); - BoolAccessorT maskAcc(mSignMaskTree); - - FloatValueT value; - CoordBBox bbox; - Coord& maxCoord = bbox.max(); - Coord& minCoord = bbox.min(); - Coord ijk; - const int extent = BoolLeafT::DIM - 1; - - for (size_t n = range.begin(); n < range.end(); ++n) { - - const FloatLeafT& distLeaf = mDistLeafs.leaf(n); - - minCoord = distLeaf.origin(); - maxCoord[0] = minCoord[0] + extent; - maxCoord[1] = minCoord[1] + extent; - maxCoord[2] = minCoord[2] + extent; - - const BoolLeafT* intersectionLeaf = intersectionAcc.probeConstLeaf(minCoord); - - BoolLeafT* maskLeafPt = new BoolLeafT(minCoord, false); - BoolLeafT& maskLeaf = *maskLeafPt; - bool addLeaf = false; - - bbox.expand(-1); - - typename FloatLeafT::ValueOnCIter it = distLeaf.cbeginValueOn(); - for (; it; ++it) { - if (intersectionLeaf && intersectionLeaf->isValueOn(it.pos())) continue; - if (it.getValue() < FloatValueT(0.0)) { - ijk = it.getCoord(); - if (bbox.isInside(ijk)) { - for (size_t i = 0; i < 6; ++i) { - if (distLeaf.probeValue(ijk+util::COORD_OFFSETS[i], value) && value>0.0) { - maskLeaf.setValueOn(ijk); - addLeaf = true; - break; - } - } - } else { - for (size_t i = 0; i < 6; ++i) { - if (distAcc.probeValue(ijk+util::COORD_OFFSETS[i], value) && value>0.0) { - maskLeaf.setValueOn(ijk); - addLeaf = true; - break; - } - } - } - } - } - - if (addLeaf) maskAcc.addLeaf(maskLeafPt); - else delete maskLeafPt; - } -} - - -template -void -SignMask::join(SignMask& rhs) -{ - mSignMaskTree.merge(rhs.mSignMaskTree); -} - - -//////////////////////////////////////// - - -/// @brief TBB body object that performs a parallel flood fill -template -class PropagateSign -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename FloatTreeT::LeafNodeType FloatLeafT; - typedef typename tree::ValueAccessor FloatAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef tree::LeafManager BoolLeafManager; - typedef typename tree::ValueAccessor BoolAccessorT; - typedef typename tree::ValueAccessor BoolConstAccessorT; - - PropagateSign(BoolLeafManager&, FloatTreeT&, const BoolTreeT&, InterruptT *interrupter = NULL); - - ~PropagateSign() {} - - void run(bool threaded = true); - - PropagateSign(PropagateSign& rhs, tbb::split); - void operator() (const tbb::blocked_range &range); - void join(PropagateSign& rhs); - - BoolTreeT& signMaskTree() { return mSignMaskTree; } - -private: - // disallow copy by assignment - void operator=(const PropagateSign&); - bool wasInterrupted() const { return mInterrupter && mInterrupter->wasInterrupted(); } - - BoolLeafManager& mOldSignMaskLeafs; - FloatTreeT& mDistTree; - const BoolTreeT& mIntersectionTree; - - BoolTreeT mSignMaskTree; - InterruptT *mInterrupter; -}; - - -template -PropagateSign::PropagateSign(BoolLeafManager& signMaskLeafs, - FloatTreeT& distTree, const BoolTreeT& intersectionTree, InterruptT *interrupter) - : mOldSignMaskLeafs(signMaskLeafs) - , mDistTree(distTree) - , mIntersectionTree(intersectionTree) - , mSignMaskTree(false) - , mInterrupter(interrupter) -{ -} - - -template -PropagateSign::PropagateSign( - PropagateSign& rhs, tbb::split) - : mOldSignMaskLeafs(rhs.mOldSignMaskLeafs) - , mDistTree(rhs.mDistTree) - , mIntersectionTree(rhs.mIntersectionTree) - , mSignMaskTree(false) - , mInterrupter(rhs.mInterrupter) -{ -} - - -template -void -PropagateSign::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mOldSignMaskLeafs.getRange(), *this); - else (*this)(mOldSignMaskLeafs.getRange()); -} - - -template -void -PropagateSign::operator()(const tbb::blocked_range &range) -{ - FloatAccessorT distAcc(mDistTree); - BoolConstAccessorT intersectionAcc(mIntersectionTree); - BoolAccessorT maskAcc(mSignMaskTree); - - std::deque coordList; - - FloatValueT value; - CoordBBox bbox; - Coord& maxCoord = bbox.max(); - Coord& minCoord = bbox.min(); - Coord ijk, nijk; - const int extent = BoolLeafT::DIM - 1; - - for (size_t n = range.begin(); n < range.end(); ++n) { - BoolLeafT& oldMaskLeaf = mOldSignMaskLeafs.leaf(n); - - minCoord = oldMaskLeaf.origin(); - maxCoord[0] = minCoord[0] + extent; - maxCoord[1] = minCoord[1] + extent; - maxCoord[2] = minCoord[2] + extent; - - FloatLeafT& distLeaf = *distAcc.probeLeaf(minCoord); - const BoolLeafT* intersectionLeaf = intersectionAcc.probeConstLeaf(minCoord); - - typename BoolLeafT::ValueOnCIter it = oldMaskLeaf.cbeginValueOn(); - for (; it; ++it) { - coordList.push_back(it.getCoord()); - - while (!coordList.empty()) { - - ijk = coordList.back(); - coordList.pop_back(); - - FloatValueT& dist = const_cast(distLeaf.getValue(ijk)); - if (dist < FloatValueT(0.0)) { - dist = -dist; // flip sign - - for (size_t i = 0; i < 6; ++i) { - nijk = ijk + util::COORD_OFFSETS[i]; - if (bbox.isInside(nijk)) { - if (intersectionLeaf && intersectionLeaf->isValueOn(nijk)) continue; - - if (distLeaf.probeValue(nijk, value) && value < 0.0) { - coordList.push_back(nijk); - } - - } else { - if(!intersectionAcc.isValueOn(nijk) && - distAcc.probeValue(nijk, value) && value < 0.0) { - maskAcc.setValueOn(nijk); - } - } - } - } - } - } - } -} - - -template -void -PropagateSign::join(PropagateSign& rhs) -{ - mSignMaskTree.merge(rhs.mSignMaskTree); -} - - -//////////////////////////////////////// - - -// IntersectingVoxelSign -/// @brief TBB body object that traversers all intersecting voxels (defined by the -/// intersectingVoxelsGrid) and potentially flips their sign, by comparing the "closest point" -/// directions of outside-marked and non-intersecting neighboring voxels -template -class IntersectingVoxelSign -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename tree::ValueAccessor FloatAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef typename tree::ValueAccessor IntAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename tree::ValueAccessor BoolAccessorT; - typedef tree::LeafManager BoolLeafManager; - - IntersectingVoxelSign( - const std::vector& pointList, - const std::vector& polygonList, - FloatTreeT& distTree, - IntTreeT& indexTree, - BoolTreeT& intersectionTree, - BoolLeafManager& leafs); - - ~IntersectingVoxelSign() {} - - void run(bool threaded = true); - - IntersectingVoxelSign(const IntersectingVoxelSign &rhs); - void operator()(const tbb::blocked_range&) const; - -private: - void operator=(const IntersectingVoxelSign&) {} - - Vec3d getClosestPoint(const Coord& ijk, const Vec4I& prim) const; - - std::vector const * const mPointList; - std::vector const * const mPolygonList; - - FloatTreeT& mDistTree; - IntTreeT& mIndexTree; - BoolTreeT& mIntersectionTree; - - BoolLeafManager& mLeafs; -}; - - -template -void -IntersectingVoxelSign::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mLeafs.getRange(), *this); - else (*this)(mLeafs.getRange()); -} - - -template -IntersectingVoxelSign::IntersectingVoxelSign( - const std::vector& pointList, - const std::vector& polygonList, - FloatTreeT& distTree, - IntTreeT& indexTree, - BoolTreeT& intersectionTree, - BoolLeafManager& leafs) - : mPointList(&pointList) - , mPolygonList(&polygonList) - , mDistTree(distTree) - , mIndexTree(indexTree) - , mIntersectionTree(intersectionTree) - , mLeafs(leafs) -{ -} - - -template -IntersectingVoxelSign::IntersectingVoxelSign( - const IntersectingVoxelSign &rhs) - : mPointList(rhs.mPointList) - , mPolygonList(rhs.mPolygonList) - , mDistTree(rhs.mDistTree) - , mIndexTree(rhs.mIndexTree) - , mIntersectionTree(rhs.mIntersectionTree) - , mLeafs(rhs.mLeafs) -{ -} - - -template -void -IntersectingVoxelSign::operator()( - const tbb::blocked_range& range) const -{ - Coord ijk, nijk; - - FloatAccessorT distAcc(mDistTree); - BoolAccessorT maskAcc(mIntersectionTree); - IntAccessorT idxAcc(mIndexTree); - - FloatValueT tmpValue; - Vec3d cpt, center, dir1, dir2; - - typename BoolTreeT::LeafNodeType::ValueOnCIter iter; - for (size_t n = range.begin(); n < range.end(); ++n) { - iter = mLeafs.leaf(n).cbeginValueOn(); - for (; iter; ++iter) { - - ijk = iter.getCoord(); - - FloatValueT value = distAcc.getValue(ijk); - - if (!(value < FloatValueT(0.0))) continue; - - center = Vec3d(ijk[0], ijk[1], ijk[2]); - - for (Int32 i = 0; i < 26; ++i) { - nijk = ijk + util::COORD_OFFSETS[i]; - - if (!maskAcc.isValueOn(nijk) && distAcc.probeValue(nijk, tmpValue)) { - if (tmpValue < FloatValueT(0.0)) continue; - - const Vec4I& prim = (*mPolygonList)[idxAcc.getValue(nijk)]; - - cpt = getClosestPoint(nijk, prim); - - dir1 = center - cpt; - dir1.normalize(); - - dir2 = Vec3d(nijk[0], nijk[1], nijk[2]) - cpt; - dir2.normalize(); - - if (dir2.dot(dir1) > 0.0) { - distAcc.setValue(ijk, -value); - break; - } - } - } - } - } -} - - -template -Vec3d -IntersectingVoxelSign::getClosestPoint(const Coord& ijk, const Vec4I& prim) const -{ - Vec3d voxelCenter(ijk[0], ijk[1], ijk[2]); - - // Evaluate first triangle - const Vec3d a((*mPointList)[prim[0]]); - const Vec3d b((*mPointList)[prim[1]]); - const Vec3d c((*mPointList)[prim[2]]); - - Vec3d uvw; - Vec3d cpt1 = closestPointOnTriangleToPoint(a, c, b, voxelCenter, uvw); - - // Evaluate second triangle if quad. - if (prim[3] != util::INVALID_IDX) { - - Vec3d diff1 = voxelCenter - cpt1; - - const Vec3d d((*mPointList)[prim[3]]); - - Vec3d cpt2 = closestPointOnTriangleToPoint(a, d, c, voxelCenter, uvw); - Vec3d diff2 = voxelCenter - cpt2; - - if (diff2.lengthSqr() < diff1.lengthSqr()) { - return cpt2; - } - } - - return cpt1; -} - - -//////////////////////////////////////// - - -// IntersectingVoxelCleaner -/// @brief TBB body object that removes intersecting voxels that were set via -/// voxelization of self-intersecting parts of a mesh -template -class IntersectingVoxelCleaner -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename tree::ValueAccessor DistAccessorT; - typedef typename FloatTreeT::LeafNodeType DistLeafT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef typename tree::ValueAccessor IntAccessorT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename tree::ValueAccessor BoolAccessorT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef tree::LeafManager BoolLeafManager; - - IntersectingVoxelCleaner(FloatTreeT& distTree, IntTreeT& indexTree, - BoolTreeT& intersectionTree, BoolLeafManager& leafs); - - ~IntersectingVoxelCleaner() {} - - void run(bool threaded = true); - - IntersectingVoxelCleaner(const IntersectingVoxelCleaner &rhs); - void operator()(const tbb::blocked_range&) const; - -private: - void operator=(const IntersectingVoxelCleaner&) {} - - FloatTreeT& mDistTree; - IntTreeT& mIndexTree; - BoolTreeT& mIntersectionTree; - BoolLeafManager& mLeafs; -}; - - -template -void -IntersectingVoxelCleaner::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mLeafs.getRange(), *this); - else (*this)(mLeafs.getRange()); - - tools::pruneInactive(mIntersectionTree, threaded); -} - - -template -IntersectingVoxelCleaner::IntersectingVoxelCleaner( - FloatTreeT& distTree, - IntTreeT& indexTree, - BoolTreeT& intersectionTree, - BoolLeafManager& leafs) - : mDistTree(distTree) - , mIndexTree(indexTree) - , mIntersectionTree(intersectionTree) - , mLeafs(leafs) -{ -} - - -template -IntersectingVoxelCleaner::IntersectingVoxelCleaner( - const IntersectingVoxelCleaner& rhs) - : mDistTree(rhs.mDistTree) - , mIndexTree(rhs.mIndexTree) - , mIntersectionTree(rhs.mIntersectionTree) - , mLeafs(rhs.mLeafs) -{ -} - - -template -void -IntersectingVoxelCleaner::operator()( - const tbb::blocked_range& range) const -{ - Coord ijk, m_ijk; - bool turnOff; - FloatValueT value; - Index offset; - - typename BoolLeafT::ValueOnCIter iter; - - IntAccessorT indexAcc(mIndexTree); - DistAccessorT distAcc(mDistTree); - BoolAccessorT maskAcc(mIntersectionTree); - - for (size_t n = range.begin(); n < range.end(); ++n) { - - BoolLeafT& maskLeaf = mLeafs.leaf(n); - - ijk = maskLeaf.origin(); - - DistLeafT * distLeaf = distAcc.probeLeaf(ijk); - if (distLeaf) { - iter = maskLeaf.cbeginValueOn(); - for (; iter; ++iter) { - - offset = iter.pos(); - - if(distLeaf->getValue(offset) > 0.0) continue; - - ijk = iter.getCoord(); - turnOff = true; - for (Int32 m = 0; m < 26; ++m) { - m_ijk = ijk + util::COORD_OFFSETS[m]; - if (distAcc.probeValue(m_ijk, value)) { - if (value > 0.0) { - turnOff = false; - break; - } - } - } - - if (turnOff) { - maskLeaf.setValueOff(offset); - distLeaf->setValueOn(offset, FloatValueT(-0.86602540378443861)); - } - } - } - } -} - - -//////////////////////////////////////// - - -// ShellVoxelCleaner -/// @brief TBB body object that removes non-intersecting voxels that where set by rasterizing -/// self-intersecting parts of the mesh. -template -class ShellVoxelCleaner -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename tree::ValueAccessor DistAccessorT; - typedef typename FloatTreeT::LeafNodeType DistLeafT; - typedef tree::LeafManager DistArrayT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef typename tree::ValueAccessor IntAccessorT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename tree::ValueAccessor BoolAccessorT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - - ShellVoxelCleaner(FloatTreeT& distTree, DistArrayT& leafs, IntTreeT& indexTree, - BoolTreeT& intersectionTree); - - ~ShellVoxelCleaner() {} - - void run(bool threaded = true); - - ShellVoxelCleaner(const ShellVoxelCleaner &rhs); - void operator()(const tbb::blocked_range&) const; - -private: - void operator=(const ShellVoxelCleaner&) {} - - FloatTreeT& mDistTree; - DistArrayT& mLeafs; - IntTreeT& mIndexTree; - BoolTreeT& mIntersectionTree; -}; - - -template -void -ShellVoxelCleaner::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mLeafs.getRange(), *this); - else (*this)(mLeafs.getRange()); - - tools::pruneInactive(mDistTree, threaded); - tools::pruneInactive(mIndexTree, threaded); -} - - -template -ShellVoxelCleaner::ShellVoxelCleaner( - FloatTreeT& distTree, - DistArrayT& leafs, - IntTreeT& indexTree, - BoolTreeT& intersectionTree) - : mDistTree(distTree) - , mLeafs(leafs) - , mIndexTree(indexTree) - , mIntersectionTree(intersectionTree) -{ -} - - -template -ShellVoxelCleaner::ShellVoxelCleaner( - const ShellVoxelCleaner &rhs) - : mDistTree(rhs.mDistTree) - , mLeafs(rhs.mLeafs) - , mIndexTree(rhs.mIndexTree) - , mIntersectionTree(rhs.mIntersectionTree) -{ -} - - -template -void -ShellVoxelCleaner::operator()( - const tbb::blocked_range& range) const -{ - Coord ijk, m_ijk; - bool turnOff; - FloatValueT value; - Index offset; - - typename DistLeafT::ValueOnCIter iter; - const FloatValueT distBG = mDistTree.background(); - const Int32 indexBG = mIntersectionTree.background(); - - IntAccessorT indexAcc(mIndexTree); - DistAccessorT distAcc(mDistTree); - BoolAccessorT maskAcc(mIntersectionTree); - - - for (size_t n = range.begin(); n < range.end(); ++n) { - - DistLeafT& distLeaf = mLeafs.leaf(n); - - ijk = distLeaf.origin(); - - const BoolLeafT* maskLeaf = maskAcc.probeConstLeaf(ijk); - IntLeafT& indexLeaf = *indexAcc.probeLeaf(ijk); - - iter = distLeaf.cbeginValueOn(); - for (; iter; ++iter) { - - value = iter.getValue(); - if(value > 0.0) continue; - - offset = iter.pos(); - if (maskLeaf && maskLeaf->isValueOn(offset)) continue; - - ijk = iter.getCoord(); - turnOff = true; - for (Int32 m = 0; m < 26; ++m) { - m_ijk = ijk + util::COORD_OFFSETS[m]; - if (maskAcc.isValueOn(m_ijk)) { - turnOff = false; - break; - } - } - - if (turnOff) { - distLeaf.setValueOff(offset, distBG); - indexLeaf.setValueOff(offset, indexBG); - } - } - } -} - - -//////////////////////////////////////// - - -template -struct CopyActiveVoxelsOp -{ - typedef typename tree::ValueAccessor AccessorT; - - CopyActiveVoxelsOp(TreeType& tree) : mAcc(tree) { } - - template - void operator()(LeafNodeType &leaf, size_t) const - { - LeafNodeType* rhsLeaf = const_cast(mAcc.probeLeaf(leaf.origin())); - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - for (; iter; ++iter) { - rhsLeaf->setValueOnly(iter.pos(), iter.getValue()); - } - } - -private: - AccessorT mAcc; -}; - - -// ExpandNB -/// @brief TBB body object to expand the level set narrow band -/// @note The interior and exterior widths should be in world space units and squared. -template -class ExpandNB -{ -public: - typedef typename FloatTreeT::ValueType FloatValueT; - typedef typename FloatTreeT::LeafNodeType FloatLeafT; - typedef typename tree::ValueAccessor FloatAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type IntTreeT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef typename tree::ValueAccessor IntAccessorT; - typedef typename FloatTreeT::template ValueConverter::Type BoolTreeT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef tree::LeafManager BoolLeafManager; - typedef typename tree::ValueAccessor BoolAccessorT; - - ExpandNB(BoolLeafManager& leafs, - FloatTreeT& distTree, IntTreeT& indexTree, BoolTreeT& maskTree, - FloatValueT exteriorBandWidth, FloatValueT interiorBandWidth, FloatValueT voxelSize, - const std::vector& pointList, const std::vector& polygonList); - - void run(bool threaded = true); - - void operator()(const tbb::blocked_range&); - void join(ExpandNB&); - ExpandNB(const ExpandNB&, tbb::split); - ~ExpandNB() {} - -private: - void operator=(const ExpandNB&) {} - - double evalVoxelDist(const Coord&, FloatAccessorT&, IntAccessorT&, - BoolAccessorT&, std::vector&, Int32&) const; - - double evalVoxelDist(const Coord&, FloatLeafT&, IntLeafT&, - BoolLeafT&, std::vector&, Int32&) const; - - double closestPrimDist(const Coord&, std::vector&, Int32&) const; - - BoolLeafManager& mMaskLeafs; - - FloatTreeT& mDistTree; - IntTreeT& mIndexTree; - BoolTreeT& mMaskTree; - - const FloatValueT mExteriorBandWidth, mInteriorBandWidth, mVoxelSize; - const std::vector& mPointList; - const std::vector& mPolygonList; - - FloatTreeT mNewDistTree; - IntTreeT mNewIndexTree; - BoolTreeT mNewMaskTree; -}; - - -template -ExpandNB::ExpandNB( - BoolLeafManager& leafs, - FloatTreeT& distTree, - IntTreeT& indexTree, - BoolTreeT& maskTree, - FloatValueT exteriorBandWidth, - FloatValueT interiorBandWidth, - FloatValueT voxelSize, - const std::vector& pointList, - const std::vector& polygonList) - : mMaskLeafs(leafs) - , mDistTree(distTree) - , mIndexTree(indexTree) - , mMaskTree(maskTree) - , mExteriorBandWidth(exteriorBandWidth) - , mInteriorBandWidth(interiorBandWidth) - , mVoxelSize(voxelSize) - , mPointList(pointList) - , mPolygonList(polygonList) - , mNewDistTree(std::numeric_limits::max()) - , mNewIndexTree(Int32(util::INVALID_IDX)) - , mNewMaskTree(false) -{ -} - - -template -ExpandNB::ExpandNB(const ExpandNB& rhs, tbb::split) - : mMaskLeafs(rhs.mMaskLeafs) - , mDistTree(rhs.mDistTree) - , mIndexTree(rhs.mIndexTree) - , mMaskTree(rhs.mMaskTree) - , mExteriorBandWidth(rhs.mExteriorBandWidth) - , mInteriorBandWidth(rhs.mInteriorBandWidth) - , mVoxelSize(rhs.mVoxelSize) - , mPointList(rhs.mPointList) - , mPolygonList(rhs.mPolygonList) - , mNewDistTree(std::numeric_limits::max()) - , mNewIndexTree(Int32(util::INVALID_IDX)) - , mNewMaskTree(false) -{ -} - - -template -void -ExpandNB::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mMaskLeafs.getRange(), *this); - else (*this)(mMaskLeafs.getRange()); - - // Copy only the active voxels (tree::merge does branch stealing - // which also moves indicative values). - mDistTree.topologyUnion(mNewDistTree); - tree::LeafManager leafs(mNewDistTree); - leafs.foreach(CopyActiveVoxelsOp(mDistTree)); - - mIndexTree.merge(mNewIndexTree); - - mMaskTree.clear(); - mMaskTree.merge(mNewMaskTree); - -} - - -template -void -ExpandNB::operator()(const tbb::blocked_range& range) -{ - Coord ijk; - Int32 closestPrim = 0; - Index pos = 0; - FloatValueT distance; - bool inside; - - FloatAccessorT newDistAcc(mNewDistTree); - IntAccessorT newIndexAcc(mNewIndexTree); - BoolAccessorT newMaskAcc(mNewMaskTree); - - FloatAccessorT distAcc(mDistTree); - IntAccessorT indexAcc(mIndexTree); - BoolAccessorT maskAcc(mMaskTree); - - CoordBBox bbox; - std::vector primitives(18); - - for (size_t n = range.begin(); n < range.end(); ++n) { - - BoolLeafT& maskLeaf = mMaskLeafs.leaf(n); - - if (maskLeaf.isEmpty()) continue; - - ijk = maskLeaf.origin(); - - FloatLeafT* distLeafPt = distAcc.probeLeaf(ijk); - - if (!distLeafPt) { - distLeafPt = new FloatLeafT(ijk, distAcc.getValue(ijk)); - newDistAcc.addLeaf(distLeafPt); - } - - IntLeafT* indexLeafPt = indexAcc.probeLeaf(ijk); - if (!indexLeafPt) indexLeafPt = newIndexAcc.touchLeaf(ijk); - - bbox = maskLeaf.getNodeBoundingBox(); - bbox.expand(-1); - - typename BoolLeafT::ValueOnIter iter = maskLeaf.beginValueOn(); - for (; iter; ++iter) { - - ijk = iter.getCoord(); - - if (bbox.isInside(ijk)) { - distance = FloatValueT(evalVoxelDist(ijk, *distLeafPt, *indexLeafPt, maskLeaf, - primitives, closestPrim)); - } else { - distance = FloatValueT(evalVoxelDist(ijk, distAcc, indexAcc, maskAcc, - primitives, closestPrim)); - } - - pos = iter.pos(); - - inside = distLeafPt->getValue(pos) < FloatValueT(0.0); - - if (!inside && distance < mExteriorBandWidth) { - distLeafPt->setValueOn(pos, distance); - indexLeafPt->setValueOn(pos, closestPrim); - } else if (inside && distance < mInteriorBandWidth) { - distLeafPt->setValueOn(pos, -distance); - indexLeafPt->setValueOn(pos, closestPrim); - } else { - continue; - } - - for (Int32 i = 0; i < 6; ++i) { - newMaskAcc.setValueOn(ijk + util::COORD_OFFSETS[i]); - } - } - } -} - - -template -double -ExpandNB::evalVoxelDist( - const Coord& ijk, - FloatAccessorT& distAcc, - IntAccessorT& indexAcc, - BoolAccessorT& maskAcc, - std::vector& prims, - Int32& closestPrim) const -{ - FloatValueT tmpDist, minDist = std::numeric_limits::max(); - prims.clear(); - - // Collect primitive indices from active neighbors and min distance. - Coord n_ijk; - for (Int32 n = 0; n < 18; ++n) { - n_ijk = ijk + util::COORD_OFFSETS[n]; - if (!maskAcc.isValueOn(n_ijk) && distAcc.probeValue(n_ijk, tmpDist)) { - prims.push_back(indexAcc.getValue(n_ijk)); - tmpDist = std::abs(tmpDist); - if (tmpDist < minDist) minDist = tmpDist; - } - } - - // Calc. this voxels distance to the closest primitive. - tmpDist = FloatValueT(closestPrimDist(ijk, prims, closestPrim)); - - // Forces the gradient to be monotonic for non-manifold - // polygonal models with self-intersections. - return tmpDist > minDist ? tmpDist : minDist + mVoxelSize; -} - - -// Leaf specialized version. -template -double -ExpandNB::evalVoxelDist( - const Coord& ijk, - FloatLeafT& distLeaf, - IntLeafT& indexLeaf, - BoolLeafT& maskLeaf, - std::vector& prims, - Int32& closestPrim) const -{ - FloatValueT tmpDist, minDist = std::numeric_limits::max(); - prims.clear(); - - Index pos; - for (Int32 n = 0; n < 18; ++n) { - pos = FloatLeafT::coordToOffset(ijk + util::COORD_OFFSETS[n]); - if (!maskLeaf.isValueOn(pos) && distLeaf.probeValue(pos, tmpDist)) { - prims.push_back(indexLeaf.getValue(pos)); - tmpDist = std::abs(tmpDist); - if (tmpDist < minDist) minDist = tmpDist; - } - } - - tmpDist = FloatValueT(closestPrimDist(ijk, prims, closestPrim)); - return tmpDist > minDist ? tmpDist : minDist + mVoxelSize; -} - - -template -double -ExpandNB::closestPrimDist(const Coord& ijk, - std::vector& prims, Int32& closestPrim) const -{ - std::sort(prims.begin(), prims.end()); - - Int32 lastPrim = -1; - Vec3d uvw, voxelCenter(ijk[0], ijk[1], ijk[2]); - double primDist, tmpDist, dist = std::numeric_limits::max(); - - for (size_t n = 0, N = prims.size(); n < N; ++n) { - if (prims[n] == lastPrim) continue; - - lastPrim = prims[n]; - - const Vec4I& verts = mPolygonList[lastPrim]; - - // Evaluate first triangle - const Vec3d a(mPointList[verts[0]]); - const Vec3d b(mPointList[verts[1]]); - const Vec3d c(mPointList[verts[2]]); - - primDist = (voxelCenter - - closestPointOnTriangleToPoint(a, c, b, voxelCenter, uvw)).lengthSqr(); - - // Split-up quad into a second triangle and calac distance. - if (util::INVALID_IDX != verts[3]) { - const Vec3d d(mPointList[verts[3]]); - - tmpDist = (voxelCenter - - closestPointOnTriangleToPoint(a, d, c, voxelCenter, uvw)).lengthSqr(); - - if (tmpDist < primDist) primDist = tmpDist; - } - - if (primDist < dist) { - dist = primDist; - closestPrim = lastPrim; - } - } - - return std::sqrt(dist) * double(mVoxelSize); -} - - -template -void -ExpandNB::join(ExpandNB& rhs) -{ - mNewDistTree.merge(rhs.mNewDistTree); - mNewIndexTree.merge(rhs.mNewIndexTree); - mNewMaskTree.merge(rhs.mNewMaskTree); -} - - -//////////////////////////////////////// - - -template -struct SqrtAndScaleOp -{ - SqrtAndScaleOp(ValueType voxelSize, bool unsignedDist = false) - : mVoxelSize(voxelSize) - , mUnsigned(unsignedDist) - { - } - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - ValueType w[2]; - w[0] = mVoxelSize; - w[1] = -mVoxelSize; - - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - for (; iter; ++iter) { - ValueType& val = const_cast(iter.getValue()); - val = w[!mUnsigned && int(val < ValueType(0.0))] * std::sqrt(std::abs(val)); - } - } - -private: - ValueType mVoxelSize; - const bool mUnsigned; -}; - - -template -struct VoxelSignOp -{ - VoxelSignOp(ValueType exBandWidth, ValueType inBandWidth) - : mExBandWidth(exBandWidth) - , mInBandWidth(inBandWidth) - { - } - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - ValueType bgValues[2]; - bgValues[0] = mExBandWidth; - bgValues[1] = -mInBandWidth; - - typename LeafNodeType::ValueOffIter iter = leaf.beginValueOff(); - - for (; iter; ++iter) { - ValueType& val = const_cast(iter.getValue()); - val = bgValues[int(val < ValueType(0.0))]; - } - } - -private: - ValueType mExBandWidth, mInBandWidth; -}; - - -template -struct TrimOp -{ - TrimOp(ValueType exBandWidth, ValueType inBandWidth) - : mExBandWidth(exBandWidth) - , mInBandWidth(inBandWidth) - { - } - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - - for (; iter; ++iter) { - ValueType& val = const_cast(iter.getValue()); - const bool inside = val < ValueType(0.0); - - if (inside && !(val > -mInBandWidth)) { - val = -mInBandWidth; - iter.setValueOff(); - } else if (!inside && !(val < mExBandWidth)) { - val = mExBandWidth; - iter.setValueOff(); - } - } - } - -private: - ValueType mExBandWidth, mInBandWidth; -}; - - -template -struct OffsetOp -{ - OffsetOp(ValueType offset): mOffset(offset) {} - - void resetOffset(ValueType offset) { mOffset = offset; } - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - for (; iter; ++iter) { - ValueType& val = const_cast(iter.getValue()); - val += mOffset; - } - } - -private: - ValueType mOffset; -}; - - -template -struct RenormOp -{ - typedef math::BIAS_SCHEME Scheme; - typedef typename Scheme::template ISStencil::StencilType Stencil; - typedef tree::LeafManager LeafManagerType; - typedef typename LeafManagerType::BufferType BufferType; - - RenormOp(GridType& grid, LeafManagerType& leafs, ValueType voxelSize, ValueType cfl = 1.0) - : mGrid(grid) - , mLeafs(leafs) - , mVoxelSize(voxelSize) - , mCFL(cfl) - { - } - - void resetCFL(ValueType cfl) { mCFL = cfl; } - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - const ValueType dt = mCFL * mVoxelSize, one(1.0), invDx = one / mVoxelSize; - Stencil stencil(mGrid); - BufferType& buffer = mLeafs.getBuffer(leafIndex, 1); - - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - for (; iter; ++iter) { - stencil.moveTo(iter); - - const ValueType normSqGradPhi = - math::ISGradientNormSqrd::result(stencil); - - const ValueType phi0 = iter.getValue(); - const ValueType diff = math::Sqrt(normSqGradPhi) * invDx - one; - const ValueType S = phi0 / (math::Sqrt(math::Pow2(phi0) + normSqGradPhi)); - - buffer.setValue(iter.pos(), phi0 - dt * S * diff); - } - } - -private: - GridType& mGrid; - LeafManagerType& mLeafs; - ValueType mVoxelSize, mCFL; -}; - - -template -struct MinOp -{ - typedef tree::LeafManager LeafManagerType; - typedef typename LeafManagerType::BufferType BufferType; - - MinOp(LeafManagerType& leafs): mLeafs(leafs) {} - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - BufferType& buffer = mLeafs.getBuffer(leafIndex, 1); - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - - for (; iter; ++iter) { - ValueType& val = const_cast(iter.getValue()); - val = std::min(val, buffer.getValue(iter.pos())); - } - } - -private: - LeafManagerType& mLeafs; -}; - - -template -struct MergeBufferOp -{ - typedef tree::LeafManager LeafManagerType; - typedef typename LeafManagerType::BufferType BufferType; - - MergeBufferOp(LeafManagerType& leafs, size_t bufferIndex = 1) - : mLeafs(leafs) - , mBufferIndex(bufferIndex) - { - } - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - BufferType& buffer = mLeafs.getBuffer(leafIndex, mBufferIndex); - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - Index offset; - - for (; iter; ++iter) { - offset = iter.pos(); - leaf.setValueOnly(offset, buffer.getValue(offset)); - } - } - -private: - LeafManagerType& mLeafs; - const size_t mBufferIndex; -}; - - -template -struct LeafTopologyDiffOp -{ - typedef typename tree::ValueAccessor AccessorT; - typedef typename TreeType::LeafNodeType LeafNodeT; - - LeafTopologyDiffOp(TreeType& tree) : mAcc(tree) { } - - template - void operator()(LeafNodeType &leaf, size_t) const - { - const LeafNodeT* rhsLeaf = mAcc.probeConstLeaf(leaf.origin()); - if (rhsLeaf) leaf.topologyDifference(*rhsLeaf, false); - } - -private: - AccessorT mAcc; -}; - -} // internal namespace - - -//////////////////////////////////////// - - -// MeshToVolume - -template -MeshToVolume::MeshToVolume( - openvdb::math::Transform::Ptr& transform, int conversionFlags, - InterruptT *interrupter, int signSweeps) - : mTransform(transform) - , mConversionFlags(conversionFlags) - , mSignSweeps(signSweeps) - , mInterrupter(interrupter) -{ - clear(); - mSignSweeps = std::min(mSignSweeps, 1); -} - - -template -void -MeshToVolume::clear() -{ - mDistGrid = FloatGridT::create(std::numeric_limits::max()); - mIndexGrid = IntGridT::create(Int32(util::INVALID_IDX)); - mIntersectingVoxelsGrid = BoolGridT::create(false); -} - - -template -inline void -MeshToVolume::convertToLevelSet( - const std::vector& pointList, const std::vector& polygonList, - FloatValueT exBandWidth, FloatValueT inBandWidth) -{ - // The narrow band width is exclusive, the shortest valid distance has to be > 1 voxel - exBandWidth = std::max(internal::Tolerance::minNarrowBandWidth(), exBandWidth); - inBandWidth = std::max(internal::Tolerance::minNarrowBandWidth(), inBandWidth); - const FloatValueT vs = FloatValueT(mTransform->voxelSize()[0]); - - // Convert from index space units to world-space units. To fill the - // interior, inBandWidth is passed FLOAT_MAX. Don't multiply with vs if so. - exBandWidth *= vs; - if (inBandWidth < std::numeric_limits::max()) { - inBandWidth *= vs; - } - - doConvert(pointList, polygonList, exBandWidth, inBandWidth); - mDistGrid->setGridClass(GRID_LEVEL_SET); -} - - -template -inline void -MeshToVolume::convertToUnsignedDistanceField( - const std::vector& pointList, const std::vector& polygonList, - FloatValueT exBandWidth) -{ - // The narrow band width is exclusive, the shortest valid distance has to be > 1 voxel - exBandWidth = std::max(internal::Tolerance::minNarrowBandWidth(), exBandWidth); - const FloatValueT vs = FloatValueT(mTransform->voxelSize()[0]); - doConvert(pointList, polygonList, vs * exBandWidth, 0.0, true); - mDistGrid->setGridClass(GRID_UNKNOWN); -} - - -template -void -MeshToVolume::doConvert( - const std::vector& pointList, const std::vector& polygonList, - FloatValueT exBandWidth, FloatValueT inBandWidth, bool unsignedDistField) -{ - mDistGrid->setTransform(mTransform); - mIndexGrid->setTransform(mTransform); - const bool rawData = OUTPUT_RAW_DATA & mConversionFlags; - - // Note that inBandWidth is allowed to be infinite when filling the interior. - if (!boost::math::isfinite(exBandWidth) || boost::math::isnan(inBandWidth)) { - std::stringstream msg; - msg << "Illegal narrow band width: exterior = " << exBandWidth - << ", interior = " << inBandWidth; - OPENVDB_THROW(ValueError, msg.str()); - } - - - // The progress estimates given to the interrupter are based on the - // observed average time for each stage and therefore not alway - // accurate. The goal is to give some progression feedback to the user. - - if (wasInterrupted(1)) return; - - // Voxelize mesh - { - internal::MeshVoxelizer - voxelizer(pointList, polygonList, mInterrupter); - - voxelizer.run(); - - if (wasInterrupted(18)) return; - - mDistGrid->tree().merge(voxelizer.sqrDistTree()); - mIndexGrid->tree().merge(voxelizer.primIndexTree()); - mIntersectingVoxelsGrid->tree().merge(voxelizer.intersectionTree()); - } - - if (!unsignedDistField) { - // Determine the inside/outside state for the narrow band of voxels. - { - // Slices up the volume and label the exterior contour of each slice in parallel. - internal::ContourTracer trace( - mDistGrid->tree(), mIntersectingVoxelsGrid->tree(), mInterrupter); - for (int i = 0; i < mSignSweeps; ++i) { - - if (wasInterrupted(19)) return; - - trace.run(); - - if (wasInterrupted(24)) return; - - // Propagate sign information between the slices. - BoolTreeT signMaskTree(false); - { - tree::LeafManager leafs(mDistGrid->tree()); - internal::SignMask signMaskOp(leafs, - mDistGrid->tree(), mIntersectingVoxelsGrid->tree(), mInterrupter); - signMaskOp.run(); - signMaskTree.merge(signMaskOp.signMaskTree()); - } - - if (wasInterrupted(25)) return; - - while (true) { - tree::LeafManager leafs(signMaskTree); - if(leafs.leafCount() == 0) break; - - internal::PropagateSign sign(leafs, - mDistGrid->tree(), mIntersectingVoxelsGrid->tree(), mInterrupter); - - sign.run(); - - signMaskTree.clear(); - signMaskTree.merge(sign.signMaskTree()); - } - } - } - - - if (wasInterrupted(28)) return; - { - tree::LeafManager leafs(mIntersectingVoxelsGrid->tree()); - - // Determine the sign of the mesh intersecting voxels. - internal::IntersectingVoxelSign sign(pointList, polygonList, - mDistGrid->tree(), mIndexGrid->tree(), mIntersectingVoxelsGrid->tree(), leafs); - - sign.run(); - - if (wasInterrupted(34)) return; - - // Remove mesh intersecting voxels that where set by rasterizing - // self-intersecting portions of the mesh. - internal::IntersectingVoxelCleaner cleaner(mDistGrid->tree(), - mIndexGrid->tree(), mIntersectingVoxelsGrid->tree(), leafs); - cleaner.run(); - } - - // Remove shell voxels that where set by rasterizing - // self-intersecting portions of the mesh. - { - tree::LeafManager leafs(mDistGrid->tree()); - - internal::ShellVoxelCleaner cleaner(mDistGrid->tree(), - leafs, mIndexGrid->tree(), mIntersectingVoxelsGrid->tree()); - - cleaner.run(); - } - - if (wasInterrupted(38)) return; - - } else { // if unsigned dist. field - inBandWidth = FloatValueT(0.0); - } - - if (mDistGrid->activeVoxelCount() == 0) { - tools::changeBackground(mDistGrid->tree(), exBandWidth); - return; - } - - mIntersectingVoxelsGrid->clear(); - const FloatValueT voxelSize = FloatValueT(mTransform->voxelSize()[0]); - - { // Transform values (world space scaling etc.) - tree::LeafManager leafs(mDistGrid->tree()); - leafs.foreach(internal::SqrtAndScaleOp(voxelSize, unsignedDistField)); - } - - if (wasInterrupted(40)) return; - - if (!unsignedDistField) { // Propagate sign information to inactive values. - mDistGrid->tree().root().setBackground(exBandWidth, /*updateChildNodes=*/false); - tools::signedFloodFillWithValues(mDistGrid->tree(), exBandWidth, -inBandWidth); - } - - if (wasInterrupted(46)) return; - - // Narrow-band dilation - const FloatValueT minWidth = FloatValueT(voxelSize * 2.0); - if (inBandWidth > minWidth || exBandWidth > minWidth) { - - // Create the initial voxel mask. - BoolTreeT maskTree(false); - maskTree.topologyUnion(mDistGrid->tree()); - - if (wasInterrupted(48)) return; - - internal::LeafTopologyDiffOp diffOp(mDistGrid->tree()); - openvdb::tools::dilateVoxels(maskTree); - - unsigned maxIterations = std::numeric_limits::max(); - float progress = 48, step = 0.0; - // progress estimation.. - double estimated = - 2.0 * std::ceil((std::max(inBandWidth, exBandWidth) - minWidth) / voxelSize); - if (estimated < double(maxIterations)) { - maxIterations = unsigned(estimated); - step = 42.f / float(maxIterations); - } - - unsigned count = 0; - while (true) { - - if (wasInterrupted(int(progress))) return; - - tree::LeafManager leafs(maskTree); - - if (leafs.leafCount() == 0) break; - - leafs.foreach(diffOp); - - internal::ExpandNB expand( - leafs, mDistGrid->tree(), mIndexGrid->tree(), maskTree, - exBandWidth, inBandWidth, voxelSize, pointList, polygonList); - - expand.run(); - - if ((++count) >= maxIterations) break; - progress += step; - } - } - - if (!bool(GENERATE_PRIM_INDEX_GRID & mConversionFlags)) mIndexGrid->clear(); - - if (wasInterrupted(80)) return; - - // Renormalize distances to smooth out bumps caused by self-intersecting - // and overlapping portions of the mesh and renormalize the level set. - if (!unsignedDistField && !rawData) { - - tools::pruneLevelSet(mDistGrid->tree(), exBandWidth, -inBandWidth); - - tree::LeafManager leafs(mDistGrid->tree(), 1); - - const FloatValueT offset = FloatValueT(0.8 * voxelSize); - if (wasInterrupted(82)) return; - - internal::OffsetOp offsetOp(-offset); - - leafs.foreach(offsetOp); - - if (wasInterrupted(84)) return; - - leafs.foreach(internal::RenormOp(*mDistGrid, leafs, voxelSize)); - - leafs.foreach(internal::MinOp(leafs)); - - if (wasInterrupted(95)) return; - - offsetOp.resetOffset(offset - internal::Tolerance::epsilon()); - leafs.foreach(offsetOp); - } - - if (wasInterrupted(98)) return; - - const FloatValueT minTrimWidth = FloatValueT(voxelSize * 4.0); - if (inBandWidth < minTrimWidth || exBandWidth < minTrimWidth) { - - // If the narrow band was not expanded, we might need to trim off - // some of the active voxels in order to respect the narrow band limits. - // (The mesh voxelization step generates some extra 'shell' voxels) - - tree::LeafManager leafs(mDistGrid->tree()); - leafs.foreach(internal::TrimOp( - exBandWidth, unsignedDistField ? exBandWidth : inBandWidth)); - - tools::pruneLevelSet(mDistGrid->tree(), exBandWidth, unsignedDistField ? -exBandWidth : -inBandWidth); - } -} - - -//////////////////////////////////////// - - -/// @internal This overload is enabled only for grids with a scalar, floating-point ValueType. -template -inline typename boost::enable_if, -typename GridType::Ptr>::type -doMeshConversion( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float exBandWidth, - float inBandWidth, - bool unsignedDistanceField = false) -{ - std::vector indexSpacePoints(points.size()); - - { // Copy and transform (required for MeshToVolume) points to grid space. - internal::PointTransform ptnXForm(points, indexSpacePoints, xform); - ptnXForm.run(); - } - - // Copy primitives - std::vector primitives(triangles.size() + quads.size()); - - for (size_t n = 0, N = triangles.size(); n < N; ++n) { - Vec4I& prim = primitives[n]; - const Vec3I& triangle = triangles[n]; - prim[0] = triangle[0]; - prim[1] = triangle[1]; - prim[2] = triangle[2]; - prim[3] = util::INVALID_IDX; - } - - for (size_t n = 0, N = quads.size(); n < N; ++n) { - primitives[n + triangles.size()] = quads[n]; - } - - typename GridType::ValueType exWidth(exBandWidth); - typename GridType::ValueType inWidth(inBandWidth); - - - math::Transform::Ptr transform = xform.copy(); - MeshToVolume vol(transform); - - if (!unsignedDistanceField) { - vol.convertToLevelSet(indexSpacePoints, primitives, exWidth, inWidth); - } else { - vol.convertToUnsignedDistanceField(indexSpacePoints, primitives, exWidth); - } - - return vol.distGridPtr(); -} - - -/// @internal This overload is enabled only for grids that do not have a scalar, -/// floating-point ValueType. -template -inline typename boost::disable_if, -typename GridType::Ptr>::type -doMeshConversion( - const math::Transform& /*xform*/, - const std::vector& /*points*/, - const std::vector& /*triangles*/, - const std::vector& /*quads*/, - float /*exBandWidth*/, - float /*inBandWidth*/, - bool /*unsignedDistanceField*/ = false) -{ - OPENVDB_THROW(TypeError, - "mesh to volume conversion is supported only for scalar, floating-point grids"); -} - - -//////////////////////////////////////// - - -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - float halfWidth) -{ - std::vector quads(0); - return doMeshConversion(xform, points, triangles, quads, - halfWidth, halfWidth); -} - - -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& quads, - float halfWidth) -{ - std::vector triangles(0); - return doMeshConversion(xform, points, triangles, quads, - halfWidth, halfWidth); -} - - -template -inline typename GridType::Ptr -meshToLevelSet( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float halfWidth) -{ - return doMeshConversion(xform, points, triangles, quads, - halfWidth, halfWidth); -} - - -template -inline typename GridType::Ptr -meshToSignedDistanceField( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float exBandWidth, - float inBandWidth) -{ - return doMeshConversion(xform, points, triangles, - quads, exBandWidth, inBandWidth); -} - - -template -inline typename GridType::Ptr -meshToUnsignedDistanceField( - const openvdb::math::Transform& xform, - const std::vector& points, - const std::vector& triangles, - const std::vector& quads, - float bandWidth) -{ - return doMeshConversion(xform, points, triangles, quads, - bandWidth, bandWidth, true); -} - - -//////////////////////////////////////////////////////////////////////////////// - - -// Required by several of the tree nodes -inline std::ostream& -operator<<(std::ostream& ostr, const MeshToVoxelEdgeData::EdgeData& rhs) -{ - ostr << "{[ " << rhs.mXPrim << ", " << rhs.mXDist << "]"; - ostr << " [ " << rhs.mYPrim << ", " << rhs.mYDist << "]"; - ostr << " [ " << rhs.mZPrim << ", " << rhs.mZDist << "]}"; - return ostr; -} - -// Required by math::Abs -inline MeshToVoxelEdgeData::EdgeData -Abs(const MeshToVoxelEdgeData::EdgeData& x) -{ - return x; -} - - -//////////////////////////////////////// - - -class MeshToVoxelEdgeData::GenEdgeData -{ -public: - - GenEdgeData( - const std::vector& pointList, - const std::vector& polygonList); - - void run(bool threaded = true); - - GenEdgeData(GenEdgeData& rhs, tbb::split); - inline void operator() (const tbb::blocked_range &range); - inline void join(GenEdgeData& rhs); - - inline TreeType& tree() { return mTree; } - -private: - void operator=(const GenEdgeData&) {} - - struct Primitive { Vec3d a, b, c, d; Int32 index; }; - - template - inline void voxelize(const Primitive&); - - template - inline bool evalPrimitive(const Coord&, const Primitive&); - - inline bool rayTriangleIntersection( const Vec3d& origin, const Vec3d& dir, - const Vec3d& a, const Vec3d& b, const Vec3d& c, double& t); - - - TreeType mTree; - Accessor mAccessor; - - const std::vector& mPointList; - const std::vector& mPolygonList; - - // Used internally for acceleration - typedef TreeType::ValueConverter::Type IntTreeT; - IntTreeT mLastPrimTree; - tree::ValueAccessor mLastPrimAccessor; -}; // class MeshToVoxelEdgeData::GenEdgeData - - -inline -MeshToVoxelEdgeData::GenEdgeData::GenEdgeData( - const std::vector& pointList, - const std::vector& polygonList) - : mTree(EdgeData()) - , mAccessor(mTree) - , mPointList(pointList) - , mPolygonList(polygonList) - , mLastPrimTree(Int32(util::INVALID_IDX)) - , mLastPrimAccessor(mLastPrimTree) -{ -} - - -inline -MeshToVoxelEdgeData::GenEdgeData::GenEdgeData(GenEdgeData& rhs, tbb::split) - : mTree(EdgeData()) - , mAccessor(mTree) - , mPointList(rhs.mPointList) - , mPolygonList(rhs.mPolygonList) - , mLastPrimTree(Int32(util::INVALID_IDX)) - , mLastPrimAccessor(mLastPrimTree) -{ -} - - -inline void -MeshToVoxelEdgeData::GenEdgeData::run(bool threaded) -{ - if (threaded) { - tbb::parallel_reduce(tbb::blocked_range(0, mPolygonList.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mPolygonList.size())); - } -} - - -inline void -MeshToVoxelEdgeData::GenEdgeData::join(GenEdgeData& rhs) -{ - typedef TreeType::RootNodeType RootNodeType; - typedef RootNodeType::NodeChainType NodeChainType; - BOOST_STATIC_ASSERT(boost::mpl::size::value > 1); - typedef boost::mpl::at >::type InternalNodeType; - - Coord ijk; - Index offset; - - rhs.mTree.clearAllAccessors(); - - TreeType::LeafIter leafIt = rhs.mTree.beginLeaf(); - for ( ; leafIt; ++leafIt) { - ijk = leafIt->origin(); - - TreeType::LeafNodeType* lhsLeafPt = mTree.probeLeaf(ijk); - - if (!lhsLeafPt) { - - mAccessor.addLeaf(rhs.mAccessor.probeLeaf(ijk)); - InternalNodeType* node = rhs.mAccessor.getNode(); - node->stealNode(ijk, EdgeData(), false); - rhs.mAccessor.clear(); - - } else { - - TreeType::LeafNodeType::ValueOnCIter it = leafIt->cbeginValueOn(); - for ( ; it; ++it) { - - offset = it.pos(); - const EdgeData& rhsValue = it.getValue(); - - if (!lhsLeafPt->isValueOn(offset)) { - lhsLeafPt->setValueOn(offset, rhsValue); - } else { - - EdgeData& lhsValue = const_cast(lhsLeafPt->getValue(offset)); - - if (rhsValue.mXDist < lhsValue.mXDist) { - lhsValue.mXDist = rhsValue.mXDist; - lhsValue.mXPrim = rhsValue.mXPrim; - } - - if (rhsValue.mYDist < lhsValue.mYDist) { - lhsValue.mYDist = rhsValue.mYDist; - lhsValue.mYPrim = rhsValue.mYPrim; - } - - if (rhsValue.mZDist < lhsValue.mZDist) { - lhsValue.mZDist = rhsValue.mZDist; - lhsValue.mZPrim = rhsValue.mZPrim; - } - - } - } // end value iteration - } - } // end leaf iteration -} - - -inline void -MeshToVoxelEdgeData::GenEdgeData::operator()(const tbb::blocked_range &range) -{ - Primitive prim; - - for (size_t n = range.begin(); n < range.end(); ++n) { - - const Vec4I& verts = mPolygonList[n]; - - prim.index = Int32(n); - prim.a = Vec3d(mPointList[verts[0]]); - prim.b = Vec3d(mPointList[verts[1]]); - prim.c = Vec3d(mPointList[verts[2]]); - - if (util::INVALID_IDX != verts[3]) { - prim.d = Vec3d(mPointList[verts[3]]); - voxelize(prim); - } else { - voxelize(prim); - } - } -} - - -template -inline void -MeshToVoxelEdgeData::GenEdgeData::voxelize(const Primitive& prim) -{ - std::deque coordList; - Coord ijk, nijk; - - ijk = util::nearestCoord(prim.a); - coordList.push_back(ijk); - - evalPrimitive(ijk, prim); - - while (!coordList.empty()) { - - ijk = coordList.back(); - coordList.pop_back(); - - for (Int32 i = 0; i < 26; ++i) { - nijk = ijk + util::COORD_OFFSETS[i]; - - if (prim.index != mLastPrimAccessor.getValue(nijk)) { - mLastPrimAccessor.setValue(nijk, prim.index); - if(evalPrimitive(nijk, prim)) coordList.push_back(nijk); - } - } - } -} - - -template -inline bool -MeshToVoxelEdgeData::GenEdgeData::evalPrimitive(const Coord& ijk, const Primitive& prim) -{ - Vec3d uvw, org(ijk[0], ijk[1], ijk[2]); - bool intersecting = false; - double t; - - EdgeData edgeData; - mAccessor.probeValue(ijk, edgeData); - - // Evaluate first triangle - double dist = (org - - closestPointOnTriangleToPoint(prim.a, prim.c, prim.b, org, uvw)).lengthSqr(); - - if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.c, prim.b, t)) { - if (t < edgeData.mXDist) { - edgeData.mXDist = float(t); - edgeData.mXPrim = prim.index; - intersecting = true; - } - } - - if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.c, prim.b, t)) { - if (t < edgeData.mYDist) { - edgeData.mYDist = float(t); - edgeData.mYPrim = prim.index; - intersecting = true; - } - } - - if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.c, prim.b, t)) { - if (t < edgeData.mZDist) { - edgeData.mZDist = float(t); - edgeData.mZPrim = prim.index; - intersecting = true; - } - } - - if (IsQuad) { - // Split quad into a second triangle and calculate distance. - double secondDist = (org - - closestPointOnTriangleToPoint(prim.a, prim.d, prim.c, org, uvw)).lengthSqr(); - - if (secondDist < dist) dist = secondDist; - - if (rayTriangleIntersection(org, Vec3d(1.0, 0.0, 0.0), prim.a, prim.d, prim.c, t)) { - if (t < edgeData.mXDist) { - edgeData.mXDist = float(t); - edgeData.mXPrim = prim.index; - intersecting = true; - } - } - - if (rayTriangleIntersection(org, Vec3d(0.0, 1.0, 0.0), prim.a, prim.d, prim.c, t)) { - if (t < edgeData.mYDist) { - edgeData.mYDist = float(t); - edgeData.mYPrim = prim.index; - intersecting = true; - } - } - - if (rayTriangleIntersection(org, Vec3d(0.0, 0.0, 1.0), prim.a, prim.d, prim.c, t)) { - if (t < edgeData.mZDist) { - edgeData.mZDist = float(t); - edgeData.mZPrim = prim.index; - intersecting = true; - } - } - } - - if (intersecting) mAccessor.setValue(ijk, edgeData); - - return (dist < 0.86602540378443861); -} - - -inline bool -MeshToVoxelEdgeData::GenEdgeData::rayTriangleIntersection( - const Vec3d& origin, const Vec3d& dir, - const Vec3d& a, const Vec3d& b, const Vec3d& c, - double& t) -{ - // Check if ray is parallel with triangle - - Vec3d e1 = b - a; - Vec3d e2 = c - a; - Vec3d s1 = dir.cross(e2); - - double divisor = s1.dot(e1); - if (!(std::abs(divisor) > 0.0)) return false; - - // Compute barycentric coordinates - - double inv_divisor = 1.0 / divisor; - Vec3d d = origin - a; - double b1 = d.dot(s1) * inv_divisor; - - if (b1 < 0.0 || b1 > 1.0) return false; - - Vec3d s2 = d.cross(e1); - double b2 = dir.dot(s2) * inv_divisor; - - if (b2 < 0.0 || (b1 + b2) > 1.0) return false; - - // Compute distance to intersection point - - t = e2.dot(s2) * inv_divisor; - return (t < 0.0) ? false : true; -} - - -//////////////////////////////////////// - - -inline -MeshToVoxelEdgeData::MeshToVoxelEdgeData() - : mTree(EdgeData()) -{ -} - - -inline void -MeshToVoxelEdgeData::convert( - const std::vector& pointList, - const std::vector& polygonList) -{ - GenEdgeData converter(pointList, polygonList); - converter.run(); - - mTree.clear(); - mTree.merge(converter.tree()); -} - - -inline void -MeshToVoxelEdgeData::getEdgeData( - Accessor& acc, - const Coord& ijk, - std::vector& points, - std::vector& primitives) -{ - EdgeData data; - Vec3d point; - - Coord coord = ijk; - - if (acc.probeValue(coord, data)) { - - if (data.mXPrim != util::INVALID_IDX) { - point[0] = double(coord[0]) + data.mXDist; - point[1] = double(coord[1]); - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mXPrim); - } - - if (data.mYPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]) + data.mYDist; - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mYPrim); - } - - if (data.mZPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]); - point[2] = double(coord[2]) + data.mZDist; - - points.push_back(point); - primitives.push_back(data.mZPrim); - } - - } - - coord[0] += 1; - - if (acc.probeValue(coord, data)) { - - if (data.mYPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]) + data.mYDist; - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mYPrim); - } - - if (data.mZPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]); - point[2] = double(coord[2]) + data.mZDist; - - points.push_back(point); - primitives.push_back(data.mZPrim); - } - } - - coord[2] += 1; - - if (acc.probeValue(coord, data)) { - if (data.mYPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]) + data.mYDist; - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mYPrim); - } - } - - coord[0] -= 1; - - if (acc.probeValue(coord, data)) { - - if (data.mXPrim != util::INVALID_IDX) { - point[0] = double(coord[0]) + data.mXDist; - point[1] = double(coord[1]); - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mXPrim); - } - - if (data.mYPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]) + data.mYDist; - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mYPrim); - } - } - - - coord[1] += 1; - - if (acc.probeValue(coord, data)) { - - if (data.mXPrim != util::INVALID_IDX) { - point[0] = double(coord[0]) + data.mXDist; - point[1] = double(coord[1]); - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mXPrim); - } - } - - coord[2] -= 1; - - if (acc.probeValue(coord, data)) { - - if (data.mXPrim != util::INVALID_IDX) { - point[0] = double(coord[0]) + data.mXDist; - point[1] = double(coord[1]); - point[2] = double(coord[2]); - - points.push_back(point); - primitives.push_back(data.mXPrim); - } - - if (data.mZPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]); - point[2] = double(coord[2]) + data.mZDist; - - points.push_back(point); - primitives.push_back(data.mZPrim); - } - } - - coord[0] += 1; - - if (acc.probeValue(coord, data)) { - - if (data.mZPrim != util::INVALID_IDX) { - point[0] = double(coord[0]); - point[1] = double(coord[1]); - point[2] = double(coord[2]) + data.mZDist; - - points.push_back(point); - primitives.push_back(data.mZPrim); - } - } -} - - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_MESH_TO_VOLUME_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Morphology.h b/openvdb_3_0_0_library/tools/Morphology.h deleted file mode 100755 index 47c2663..0000000 --- a/openvdb_3_0_0_library/tools/Morphology.h +++ /dev/null @@ -1,914 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Morphology.h -/// -/// @brief Implementation of morphological dilation and erosion. -/// -/// @note By design the morphological operations only change the -/// state of voxels, not their values. If one desires to -/// change the values of voxels that change state an efficient -/// technique is to construct a boolean mask by performing a -/// topology difference between the original and final grids. -/// -/// @todo Extend erosion with 18 and 26 neighbors (coming soon!) -/// -/// @author Ken Museth -/// - -#ifndef OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED - -#include -#include -#include // for isApproxEqual() -#include -#include -#include -#include -#include -#include "Prune.h"// for pruneLevelSet -#include "ValueTransformer.h" // for foreach() - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Voxel topology of nearest neighbors -/// @details -///
-///
NN_FACE -///
face adjacency (6 nearest neighbors, defined as all neighbor -/// voxels connected along one of the primary axes) -/// -///
NN_FACE_EDGE -///
face and edge adjacency (18 nearest neighbors, defined as all -/// neighbor voxels connected along either one or two of the primary axes) -/// -///
NN_FACE_EDGE_VERTEX -///
face, edge and vertex adjacency (26 nearest neighbors, defined -/// as all neighbor voxels connected along either one, two or all -/// three of the primary axes) -///
-enum NearestNeighbors { NN_FACE = 6, NN_FACE_EDGE = 18, NN_FACE_EDGE_VERTEX = 26 }; - - -/// @brief Topologically dilate all leaf-level active voxels in a tree -/// using one of three nearest neighbor connectivity patterns. -/// -/// @param tree tree to be dilated -/// @param iterations number of iterations to apply the dilation -/// @param nn connectivity pattern of the dilation: either -/// face-adjacent (6 nearest neighbors), face- and edge-adjacent -/// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26 -/// nearest neighbors). -/// -/// @note The values of any voxels are unchanged. -/// @todo Currently operates only on leaf voxels; need to extend to tiles. -template OPENVDB_STATIC_SPECIALIZATION -inline void dilateVoxels(TreeType& tree, - int iterations = 1, - NearestNeighbors nn = NN_FACE); - -/// @brief Topologically dilate all leaf-level active voxels in a tree -/// using one of three nearest neighbor connectivity patterns. -/// -/// @param manager LeafManager containing the tree to be dilated. -/// @param iterations number of iterations to apply the dilation -/// @param nn connectivity pattern of the dilation: either -/// face-adjacent (6 nearest neighbors), face- and edge-adjacent -/// (18 nearest neighbors) or face-, edge- and vertex-adjacent (26 -/// nearest neighbors). -/// -/// @note The values of any voxels are unchanged. -/// @todo Currently operates only on leaf voxels; need to extend to tiles. -template OPENVDB_STATIC_SPECIALIZATION -inline void dilateVoxels(tree::LeafManager& manager, - int iterations = 1, - NearestNeighbors nn = NN_FACE); - - -//@{ -/// @brief Topologically erode all leaf-level active voxels in the given tree. -/// @details That is, shrink the set of active voxels by @a iterations voxels -/// in the +x, -x, +y, -y, +z and -z directions, but don't change the values -/// of any voxels, only their active states. -/// @todo Currently operates only on leaf voxels; need to extend to tiles. -template OPENVDB_STATIC_SPECIALIZATION -inline void erodeVoxels(TreeType& tree, - int iterations=1, - NearestNeighbors nn = NN_FACE); - -template OPENVDB_STATIC_SPECIALIZATION -inline void erodeVoxels(tree::LeafManager& manager, - int iterations = 1, - NearestNeighbors nn = NN_FACE); -//@} - - -/// @brief Mark as active any inactive tiles or voxels in the given grid or tree -/// whose values are equal to @a value (optionally to within the given @a tolerance). -template -inline void activate( - GridOrTree&, - const typename GridOrTree::ValueType& value, - const typename GridOrTree::ValueType& tolerance = zeroVal() -); - - -/// @brief Mark as inactive any active tiles or voxels in the given grid or tree -/// whose values are equal to @a value (optionally to within the given @a tolerance). -template -inline void deactivate( - GridOrTree&, - const typename GridOrTree::ValueType& value, - const typename GridOrTree::ValueType& tolerance = zeroVal() -); - - -//////////////////////////////////////// - - -/// Mapping from a Log2Dim to a data type of size 2^Log2Dim bits -template struct DimToWord {}; -template<> struct DimToWord<3> { typedef uint8_t Type; }; -template<> struct DimToWord<4> { typedef uint16_t Type; }; -template<> struct DimToWord<5> { typedef uint32_t Type; }; -template<> struct DimToWord<6> { typedef uint64_t Type; }; - - -//////////////////////////////////////// - - -template -class Morphology -{ -public: - typedef tree::LeafManager ManagerType; - - Morphology(TreeType& tree): - mOwnsManager(true), mManager(new ManagerType(tree)), mAcc(tree), mSteps(1) {} - Morphology(ManagerType* mgr): - mOwnsManager(false), mManager(mgr), mAcc(mgr->tree()), mSteps(1) {} - virtual ~Morphology() { if (mOwnsManager) delete mManager; } - - /// @brief Face-adjacent dilation pattern - void dilateVoxels6(); - /// @brief Face- and edge-adjacent dilation pattern. - void dilateVoxels18(); - /// @brief Face-, edge- and vertex-adjacent dilation pattern. - void dilateVoxels26(); - void dilateVoxels(int iterations = 1, NearestNeighbors nn = NN_FACE); - - /// @brief Face-adjacent erosion pattern. - void erodeVoxels6() { mSteps = 1; this->doErosion(NN_FACE); } - /// @brief Face- and edge-adjacent erosion pattern. - void erodeVoxels18() { mSteps = 1; this->doErosion(NN_FACE_EDGE); } - /// @brief Face-, edge- and vertex-adjacent erosion pattern. - void erodeVoxels26() { mSteps = 1; this->doErosion(NN_FACE_EDGE_VERTEX); } - void erodeVoxels(int iterations = 1, NearestNeighbors nn = NN_FACE) - { - mSteps = iterations; - this->doErosion(nn); - } - -protected: - - void doErosion(NearestNeighbors nn); - - typedef typename TreeType::LeafNodeType LeafType; - typedef typename LeafType::NodeMaskType MaskType; - typedef tree::ValueAccessor AccessorType; - - const bool mOwnsManager; - ManagerType* mManager; - AccessorType mAcc; - int mSteps; - - static const int LEAF_DIM = LeafType::DIM; - static const int LEAF_LOG2DIM = LeafType::LOG2DIM; - typedef typename DimToWord::Type Word; - - struct Neighbor { - LeafType* leaf;//null if a tile - bool init;//true if initialization is required - bool isOn;//true if an active tile - Neighbor() : leaf(NULL), init(true) {} - inline void clear() { leaf = NULL; init = true; } - template - void scatter(AccessorType& acc, const Coord &xyz, int indx, Word mask) - { - if (init) { - init = false; - Coord orig = xyz.offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM); - leaf = acc.probeLeaf(orig); - if (leaf==NULL && !acc.isValueOn(orig)) leaf = acc.touchLeaf(orig); - } -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const int N = (LEAF_DIM - 1)*(DY + DX*LEAF_DIM); - if (leaf) leaf->getValueMask().template getWord(indx-N) |= mask; - } - - template - Word gather(AccessorType& acc, const Coord &xyz, int indx) - { - if (init) { - init = false; - Coord orig = xyz.offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM); - leaf = acc.probeLeaf(orig); - isOn = leaf ? false : acc.isValueOn(orig); - } -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const int N = (LEAF_DIM -1 )*(DY + DX*LEAF_DIM); - return leaf ? leaf->getValueMask().template getWord(indx-N) - : isOn ? ~Word(0) : Word(0); - } - };// Neighbor - - struct LeafCache - { - LeafCache(size_t n, TreeType& tree) : size(n), leafs(new LeafType*[n]), acc(tree) - { - onTile.setValuesOn(); - this->clear(); - } - ~LeafCache() { delete [] leafs; } - LeafType*& operator[](int offset) { return leafs[offset]; } - inline void clear() { for (size_t i=0; igetValueMask().template getWord(indx) |= mask; - } - template - inline void scatter(int n, int indx) - { - if (!leafs[n]) { - const Coord xyz = origin->offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM); - leafs[n] = acc.probeLeaf(xyz); - if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : acc.touchLeaf(xyz); - } - this->scatter(n, indx - (LEAF_DIM - 1)*(DY + DX*LEAF_DIM)); - } - inline Word gather(int n, int indx) - { - assert(leafs[n]); - return leafs[n]->getValueMask().template getWord(indx); - } - template - inline Word gather(int n, int indx) - { - if (!leafs[n]) { - const Coord xyz = origin->offsetBy(DX*LEAF_DIM, DY*LEAF_DIM, DZ*LEAF_DIM); - leafs[n] = acc.probeLeaf(xyz); - if (!leafs[n]) leafs[n] = acc.isValueOn(xyz) ? &onTile : &offTile; - } - return this->gather(n, indx - (LEAF_DIM -1 )*(DY + DX*LEAF_DIM)); - } - // Scatters in the xy face-directions relative to leaf i1 - void scatterFacesXY(int x, int y, int i1, int n, int i2); - - // Scatters in the xy edge-directions relative to leaf i1 - void scatterEdgesXY(int x, int y, int i1, int n, int i2); - - Word gatherFacesXY(int x, int y, int i1, int n, int i2); - - Word gatherEdgesXY(int x, int y, int i1, int n, int i2); - - const Coord* origin; - size_t size; - LeafType** leafs; - LeafType onTile, offTile; - AccessorType acc; - Word mask; - };// LeafCache - - struct ErodeVoxelsOp { - typedef tbb::blocked_range RangeT; - ErodeVoxelsOp(std::vector& masks, ManagerType& manager) - : mTask(0), mSavedMasks(masks) , mManager(manager) {} - void runParallel(NearestNeighbors nn); - void operator()(const RangeT& r) const {mTask(const_cast(this), r);} - void erode6( const RangeT&) const; - void erode18(const RangeT&) const; - void erode26(const RangeT&) const; - private: - typedef typename boost::function FuncT; - FuncT mTask; - std::vector& mSavedMasks; - ManagerType& mManager; - };// ErodeVoxelsOp - - struct MaskManager { - MaskManager(std::vector& masks, ManagerType& manager) - : mMasks(masks) , mManager(manager), mSaveMasks(true) {} - - void save() { mSaveMasks = true; tbb::parallel_for(mManager.getRange(), *this); } - void update() { mSaveMasks = false; tbb::parallel_for(mManager.getRange(), *this); } - void operator()(const tbb::blocked_range& range) const - { - if (mSaveMasks) { - for (size_t i = range.begin(); i < range.end(); ++i) { - mMasks[i] = mManager.leaf(i).getValueMask(); - } - } else { - for (size_t i = range.begin(); i < range.end(); ++i) { - mManager.leaf(i).setValueMask(mMasks[i]); - } - } - } - private: - std::vector& mMasks; - ManagerType& mManager; - bool mSaveMasks; - };// MaskManager - - struct UpdateMasks { - UpdateMasks(const std::vector& masks, ManagerType& manager) - : mMasks(masks), mManager(manager) {} - void update() { tbb::parallel_for(mManager.getRange(), *this); } - void operator()(const tbb::blocked_range& r) const { - for (size_t i=r.begin(); i& mMasks; - ManagerType& mManager; - }; - struct CopyMasks { - CopyMasks(std::vector& masks, const ManagerType& manager) - : mMasks(masks), mManager(manager) {} - void copy() { tbb::parallel_for(mManager.getRange(), *this); } - void operator()(const tbb::blocked_range& r) const { - for (size_t i=r.begin(); i& mMasks; - const ManagerType& mManager; - }; - void copyMasks(std::vector& a, const ManagerType& b) {CopyMasks c(a, b); c.copy();} -};// Morphology - -template -void -Morphology::dilateVoxels(int iterations, NearestNeighbors nn) -{ - for (int i=0; idilateVoxels18(); break; - case NN_FACE_EDGE_VERTEX: this->dilateVoxels26(); break; - default: this->dilateVoxels6(); - } - } -} - -template -void -Morphology::dilateVoxels6() -{ - /// @todo Currently operates only on leaf voxels; need to extend to tiles. - const int leafCount = static_cast(mManager->leafCount()); - - // Save the value masks of all leaf nodes. - std::vector savedMasks(leafCount); - this->copyMasks(savedMasks, *mManager); - LeafCache cache(7, mManager->tree()); - for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) { - const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node - cache[0] = &mManager->leaf(leafIdx); - cache.setOrigin(cache[0]->origin()); - for (int x = 0; x < LEAF_DIM; ++x ) { - for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) { - // Extract the portion of the original mask that corresponds to a row in z. - if (const Word w = oldMask.template getWord(n)) { - - // Dilate the current leaf in the +z and -z direction - cache.mask = Word(w | (w>>1) | (w<<1)); cache.scatter(0, n); - - // Dilate into neighbor leaf in the -z direction - if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) { - cache.template scatter< 0, 0,-1>(1, n); - } - // Dilate into neighbor leaf in the +z direction - if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) { - cache.template scatter< 0, 0, 1>(2, n); - } - // Dilate in the xy-face directions relative to the center leaf - cache.mask = w; cache.scatterFacesXY(x, y, 0, n, 3); - } - }// loop over y - }//loop over x - cache.clear(); - }//loop over leafs - - mManager->rebuildLeafArray(); -}//dilateVoxels6 - -template -void -Morphology::dilateVoxels18() -{ - /// @todo Currently operates only on leaf voxels; need to extend to tiles. - const int leafCount = static_cast(mManager->leafCount()); - - // Save the value masks of all leaf nodes. - std::vector savedMasks(leafCount); - this->copyMasks(savedMasks, *mManager); - LeafCache cache(19, mManager->tree()); - Coord orig_mz, orig_pz;//origins of neighbor leaf nodes in the -z and +z directions - for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) { - const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node - cache[0] = &mManager->leaf(leafIdx); - orig_mz = cache[0]->origin().offsetBy(0, 0, -LEAF_DIM); - orig_pz = cache[0]->origin().offsetBy(0, 0, LEAF_DIM); - for (int x = 0; x < LEAF_DIM; ++x ) { - for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) { - if (const Word w = oldMask.template getWord(n)) { - { - cache.mask = Word(w | (w>>1) | (w<<1)); - cache.setOrigin(cache[0]->origin()); - cache.scatter(0, n); - cache.scatterFacesXY(x, y, 0, n, 3); - cache.mask = w; - cache.scatterEdgesXY(x, y, 0, n, 3); - } - if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) { - cache.setOrigin(cache[0]->origin()); - cache.template scatter< 0, 0,-1>(1, n); - cache.setOrigin(orig_mz); - cache.scatterFacesXY(x, y, 1, n, 11); - } - if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) { - cache.setOrigin(cache[0]->origin()); - cache.template scatter< 0, 0, 1>(2, n); - cache.setOrigin(orig_pz); - cache.scatterFacesXY(x, y, 2, n, 15); - } - } - }// loop over y - }//loop over x - cache.clear(); - }//loop over leafs - - mManager->rebuildLeafArray(); -}// dilateVoxels18 - -template -void -Morphology::dilateVoxels26() -{ - /// @todo Currently operates only on leaf voxels; need to extend to tiles. - const int leafCount = static_cast(mManager->leafCount()); - - // Save the value masks of all leaf nodes. - std::vector savedMasks(leafCount); - this->copyMasks(savedMasks, *mManager); - LeafCache cache(27, mManager->tree()); - Coord orig_mz, orig_pz;//origins of neighbor leaf nodes in the -z and +z directions - for (int leafIdx = 0; leafIdx < leafCount; ++leafIdx) { - const MaskType& oldMask = savedMasks[leafIdx];//original bit-mask of current leaf node - cache[0] = &mManager->leaf(leafIdx); - orig_mz = cache[0]->origin().offsetBy(0, 0, -LEAF_DIM); - orig_pz = cache[0]->origin().offsetBy(0, 0, LEAF_DIM); - for (int x = 0; x < LEAF_DIM; ++x ) { - for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) { - if (const Word w = oldMask.template getWord(n)) { - { - cache.mask = Word(w | (w>>1) | (w<<1)); - cache.setOrigin(cache[0]->origin()); - cache.scatter(0, n); - cache.scatterFacesXY(x, y, 0, n, 3); - cache.scatterEdgesXY(x, y, 0, n, 3); - } - if ( (cache.mask = Word(w<<(LEAF_DIM-1))) ) { - cache.setOrigin(cache[0]->origin()); - cache.template scatter< 0, 0,-1>(1, n); - cache.setOrigin(orig_mz); - cache.scatterFacesXY(x, y, 1, n, 11); - cache.scatterEdgesXY(x, y, 1, n, 11); - } - if ( (cache.mask = Word(w>>(LEAF_DIM-1))) ) { - cache.setOrigin(cache[0]->origin()); - cache.template scatter< 0, 0, 1>(2, n); - cache.setOrigin(orig_pz); - cache.scatterFacesXY(x, y, 2, n, 19); - cache.scatterEdgesXY(x, y, 2, n, 19); - } - } - }// loop over y - }//loop over x - cache.clear(); - }//loop over leafs - - mManager->rebuildLeafArray(); -}// dilateVoxels26 - -template -inline void Morphology::LeafCache:: -scatterFacesXY(int x, int y, int i1, int n, int i2) -{ - // dilate current leaf or neighbor in the -x direction - if (x > 0) { - this->scatter(i1, n-LEAF_DIM); - } else { - this->template scatter<-1, 0, 0>(i2, n); - } - // dilate current leaf or neighbor in the +x direction - if (x < LEAF_DIM-1) { - this->scatter(i1, n+LEAF_DIM); - } else { - this->template scatter< 1, 0, 0>(i2+1, n); - } - // dilate current leaf or neighbor in the -y direction - if (y > 0) { - this->scatter(i1, n-1); - } else { - this->template scatter< 0,-1, 0>(i2+2, n); - } - // dilate current leaf or neighbor in the +y direction - if (y < LEAF_DIM-1) { - this->scatter(i1, n+1); - } else { - this->template scatter< 0, 1, 0>(i2+3, n); - } -} - -template -void -Morphology::LeafCache:: -scatterEdgesXY(int x, int y, int i1, int n, int i2) -{ - if (x > 0) { - if (y > 0) { - this->scatter(i1, n-LEAF_DIM-1); - } else { - this->template scatter< 0,-1, 0>(i2+2, n-LEAF_DIM); - } - if (y < LEAF_DIM-1) { - this->scatter(i1, n-LEAF_DIM+1); - } else { - this->template scatter< 0, 1, 0>(i2+3, n-LEAF_DIM); - } - } else { - if (y < LEAF_DIM-1) { - this->template scatter<-1, 0, 0>(i2 , n+1); - } else { - this->template scatter<-1, 1, 0>(i2+7, n ); - } - if (y > 0) { - this->template scatter<-1, 0, 0>(i2 , n-1); - } else { - this->template scatter<-1,-1, 0>(i2+4, n ); - } - } - if (x < LEAF_DIM-1) { - if (y > 0) { - this->scatter(i1, n+LEAF_DIM-1); - } else { - this->template scatter< 0,-1, 0>(i2+2, n+LEAF_DIM); - } - if (y < LEAF_DIM-1) { - this->scatter(i1, n+LEAF_DIM+1); - } else { - this->template scatter< 0, 1, 0>(i2+3, n+LEAF_DIM); - } - } else { - if (y > 0) { - this->template scatter< 1, 0, 0>(i2+1, n-1); - } else { - this->template scatter< 1,-1, 0>(i2+6, n ); - } - if (y < LEAF_DIM-1) { - this->template scatter< 1, 0, 0>(i2+1, n+1); - } else { - this->template scatter< 1, 1, 0>(i2+5, n ); - } - } -} - -template -inline void -Morphology::ErodeVoxelsOp:: -runParallel(NearestNeighbors nn) -{ - switch (nn) { - case NN_FACE_EDGE: - mTask = boost::bind(&ErodeVoxelsOp::erode18, _1, _2); - break; - case NN_FACE_EDGE_VERTEX: - mTask = boost::bind(&ErodeVoxelsOp::erode26, _1, _2); - break; - default: - mTask = boost::bind(&ErodeVoxelsOp::erode6, _1, _2); - } - tbb::parallel_for(mManager.getRange(), *this); -} - -template -inline typename Morphology::Word -Morphology::LeafCache:: -gatherFacesXY(int x, int y, int i1, int n, int i2) -{ - // erode current leaf or neighbor in negative x-direction - Word w = x>0 ? this->gather(i1,n-LEAF_DIM) : this->template gather<-1,0,0>(i2, n); - - // erode current leaf or neighbor in positive x-direction - w = Word(w & (xgather(i1,n+LEAF_DIM):this->template gather<1,0,0>(i2+1,n))); - - // erode current leaf or neighbor in negative y-direction - w = Word(w & (y>0 ? this->gather(i1, n-1) : this->template gather<0,-1,0>(i2+2, n))); - - // erode current leaf or neighbor in positive y-direction - w = Word(w & (ygather(i1, n+1) : this->template gather<0,1,0>(i2+3, n))); - - return w; -} - -template -inline -typename Morphology::Word -Morphology::LeafCache:: -gatherEdgesXY(int x, int y, int i1, int n, int i2) -{ - Word w = ~Word(0); - - if (x > 0) { - w &= y > 0 ? this->gather(i1, n-LEAF_DIM-1) : - this->template gather< 0,-1, 0>(i2+2, n-LEAF_DIM); - w &= y < LEAF_DIM-1 ? this->gather(i1, n-LEAF_DIM+1) : - this->template gather< 0, 1, 0>(i2+3, n-LEAF_DIM); - } else { - w &= y < LEAF_DIM-1 ? this->template gather<-1, 0, 0>(i2 , n+1): - this->template gather<-1, 1, 0>(i2+7, n ); - w &= y > 0 ? this->template gather<-1, 0, 0>(i2 , n-1): - this->template gather<-1,-1, 0>(i2+4, n ); - } - if (x < LEAF_DIM-1) { - w &= y > 0 ? this->gather(i1, n+LEAF_DIM-1) : - this->template gather< 0,-1, 0>(i2+2, n+LEAF_DIM); - w &= y < LEAF_DIM-1 ? this->gather(i1, n+LEAF_DIM+1) : - this->template gather< 0, 1, 0>(i2+3, n+LEAF_DIM); - } else { - w &= y > 0 ? this->template gather< 1, 0, 0>(i2+1, n-1): - this->template gather< 1,-1, 0>(i2+6, n ); - w &= y < LEAF_DIM-1 ? this->template gather< 1, 0, 0>(i2+1, n+1): - this->template gather< 1, 1, 0>(i2+5, n ); - } - - return w; -} - -template -void -Morphology::ErodeVoxelsOp:: -erode6(const RangeT& range) const -{ - LeafCache cache(7, mManager.tree()); - for (size_t leafIdx = range.begin(); leafIdx < range.end(); ++leafIdx) { - cache[0] = &mManager.leaf(leafIdx); - if (cache[0]->isEmpty()) continue; - cache.setOrigin(cache[0]->origin()); - MaskType& newMask = mSavedMasks[leafIdx];//original bit-mask of current leaf node - for (int x = 0; x < LEAF_DIM; ++x ) { - for (int y = 0, n = (x << LEAF_LOG2DIM); y < LEAF_DIM; ++y, ++n) { - // Extract the portion of the original mask that corresponds to a row in z. - if (Word& w = newMask.template getWord(n)) { - - // erode in two z directions (this is first since it uses the original w) - w = Word(w & - (Word(w<<1 | (cache.template gather<0,0,-1>(1, n)>>(LEAF_DIM-1))) & - Word(w>>1 | (cache.template gather<0,0, 1>(2, n)<<(LEAF_DIM-1))))); - - w = Word(w & cache.gatherFacesXY(x, y, 0, n, 3)); - } - }// loop over y - }//loop over x - cache.clear(); - }//loop over leafs -} - -template -void -Morphology::ErodeVoxelsOp:: -erode18(const RangeT&) const -{ - OPENVDB_THROW(RuntimeError, "tools::erode18 is not implemented yet!"); -} - -template -void -Morphology::ErodeVoxelsOp:: -erode26(const RangeT&) const -{ - OPENVDB_THROW(RuntimeError, "tools::erode26 is not implemented yet!"); -} - - -template -void -Morphology::doErosion(NearestNeighbors nn) -{ - /// @todo Currently operates only on leaf voxels; need to extend to tiles. - const size_t leafCount = mManager->leafCount(); - - // Save the value masks of all leaf nodes. - std::vector savedMasks(leafCount); - this->copyMasks(savedMasks, *mManager); - UpdateMasks a(savedMasks, *mManager); - ErodeVoxelsOp erode(savedMasks, *mManager); - - for (int i = 0; i < mSteps; ++i) { - erode.runParallel(nn); - a.update(); - } - - tools::pruneLevelSet(mManager->tree()); -} - - -//////////////////////////////////////// - - -template -OPENVDB_STATIC_SPECIALIZATION inline void -dilateVoxels(tree::LeafManager& manager, int iterations, NearestNeighbors nn) -{ - if (iterations > 0 ) { - Morphology m(&manager); - m.dilateVoxels(iterations, nn); - } -} - -template -OPENVDB_STATIC_SPECIALIZATION inline void -dilateVoxels(TreeType& tree, int iterations, NearestNeighbors nn) -{ - if (iterations > 0 ) { - Morphology m(tree); - m.dilateVoxels(iterations, nn); - } -} - -template -OPENVDB_STATIC_SPECIALIZATION inline void -erodeVoxels(tree::LeafManager& manager, int iterations, NearestNeighbors nn) -{ - if (iterations > 0 ) { - Morphology m(&manager); - m.erodeVoxels(iterations, nn); - } -} - -template -OPENVDB_STATIC_SPECIALIZATION inline void -erodeVoxels(TreeType& tree, int iterations, NearestNeighbors nn) -{ - if (iterations > 0 ) { - Morphology m(tree); - m.erodeVoxels(iterations, nn); - } -} - - -//////////////////////////////////////// - - -namespace activation { - -template -class ActivationOp -{ -public: - typedef typename TreeType::ValueType ValueT; - - ActivationOp(bool state, const ValueT& val, const ValueT& tol) - : mActivate(state) - , mValue(val) - , mTolerance(tol) - {} - - void operator()(const typename TreeType::ValueOnIter& it) const - { - if (math::isApproxEqual(*it, mValue, mTolerance)) { - it.setValueOff(); - } - } - - void operator()(const typename TreeType::ValueOffIter& it) const - { - if (math::isApproxEqual(*it, mValue, mTolerance)) { - it.setActiveState(/*on=*/true); - } - } - - void operator()(const typename TreeType::LeafIter& lit) const - { - typedef typename TreeType::LeafNodeType LeafT; - LeafT& leaf = *lit; - if (mActivate) { - for (typename LeafT::ValueOffIter it = leaf.beginValueOff(); it; ++it) { - if (math::isApproxEqual(*it, mValue, mTolerance)) { - leaf.setValueOn(it.pos()); - } - } - } else { - for (typename LeafT::ValueOnIter it = leaf.beginValueOn(); it; ++it) { - if (math::isApproxEqual(*it, mValue, mTolerance)) { - leaf.setValueOff(it.pos()); - } - } - } - } - -private: - bool mActivate; - const ValueT mValue, mTolerance; -}; // class ActivationOp - -} // namespace activation - - -template -inline void -activate(GridOrTree& gridOrTree, const typename GridOrTree::ValueType& value, - const typename GridOrTree::ValueType& tolerance) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeType; - - TreeType& tree = Adapter::tree(gridOrTree); - - activation::ActivationOp op(/*activate=*/true, value, tolerance); - - // Process all leaf nodes in parallel. - foreach(tree.beginLeaf(), op); - - // Process all other inactive values serially (because changing active states - // is not thread-safe unless no two threads modify the same node). - typename TreeType::ValueOffIter it = tree.beginValueOff(); - it.setMaxDepth(tree.treeDepth() - 2); - foreach(it, op, /*threaded=*/false); -} - - -template -inline void -deactivate(GridOrTree& gridOrTree, const typename GridOrTree::ValueType& value, - const typename GridOrTree::ValueType& tolerance) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType TreeType; - - TreeType& tree = Adapter::tree(gridOrTree); - - activation::ActivationOp op(/*activate=*/false, value, tolerance); - - // Process all leaf nodes in parallel. - foreach(tree.beginLeaf(), op); - - // Process all other active values serially (because changing active states - // is not thread-safe unless no two threads modify the same node). - typename TreeType::ValueOnIter it = tree.beginValueOn(); - it.setMaxDepth(tree.treeDepth() - 2); - foreach(it, op, /*threaded=*/false); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_MORPHOLOGY_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/ParticlesToLevelSet.h b/openvdb_3_0_0_library/tools/ParticlesToLevelSet.h deleted file mode 100755 index 698cdf2..0000000 --- a/openvdb_3_0_0_library/tools/ParticlesToLevelSet.h +++ /dev/null @@ -1,844 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file ParticlesToLevelSet.h -/// -/// @brief This tool converts particles (with position, radius and velocity) -/// into a signed distance field encoded as a narrow band level set. -/// Optionally, arbitrary attributes on the particles can be transferred -/// resulting in an additional attribute grid with the same topology -/// as the level set grid. -/// -/// @note This fast particle to level set converter is always intended -/// to be combined with some kind of surface postprocessing, -/// i.e. tools::Filter. Without such postprocessing the generated -/// surface is typically too noisy and blobby. However it serves as a -/// great and fast starting point for subsequent level set surface -/// processing and convolution. -/// -/// The @c ParticleListT template argument below refers to any class -/// with the following interface (see unittest/TestParticlesToLevelSet.cc -/// and SOP_DW_OpenVDBParticleVoxelizer for practical examples): -/// @code -/// -/// class ParticleList { -/// ... -/// public: -/// -/// // Return the total number of particles in list. -/// // Always required! -/// size_t size() const; -/// -/// // Get the world space position of the nth particle. -/// // Required by ParticledToLevelSet::rasterizeSphere(*this,radius). -/// void getPos(size_t n, Vec3R& xyz) const; -/// -/// // Get the world space position and radius of the nth particle. -/// // Required by ParticledToLevelSet::rasterizeSphere(*this). -/// void getPosRad(size_t n, Vec3R& xyz, Real& rad) const; -/// -/// // Get the world space position, radius and velocity of the nth particle. -/// // Required by ParticledToLevelSet::rasterizeSphere(*this,radius). -/// void getPosRadVel(size_t n, Vec3R& xyz, Real& rad, Vec3R& vel) const; -/// -/// // Get the attribute of the nth particle. AttributeType is user-defined! -/// // Only required if attribute transfer is enabled in ParticlesToLevelSet. -/// void getAtt(size_t n, AttributeType& att) const; -/// }; -/// @endcode -/// -/// @note See unittest/TestParticlesToLevelSet.cc for an example. -/// -/// The @c InterruptT template argument below refers to any class -/// with the following interface: -/// @code -/// class Interrupter { -/// ... -/// public: -/// void start(const char* name = NULL)// called when computations begin -/// void end() // called when computations end -/// bool wasInterrupted(int percent=-1)// return true to break computation -/// }; -/// @endcode -/// -/// @note If no template argument is provided for this InterruptT -/// the util::NullInterrupter is used which implies that all -/// interrupter calls are no-ops (i.e. incurs no computational overhead). - -#ifndef OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Composite.h" // for csgUnion() -#include "PointPartitioner.h" -#include "Prune.h" -#include "SignedFloodFill.h" - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -namespace p2ls_internal { -// This is a simple type that combines a distance value and a particle -// attribute. It's required for attribute transfer which is performed -// in the ParticlesToLevelSet::Raster memberclass defined below. -template class BlindData; -}// namespace p2ls_internal - - -template -class ParticlesToLevelSet -{ -public: - typedef typename boost::is_void::type DisableT; - typedef InterrupterT InterrupterType; - - typedef SdfGridT SdfGridType; - typedef typename SdfGridT::ValueType SdfType; - - typedef typename boost::mpl::if_::type AttType; - typedef typename SdfGridT::template ValueConverter::Type AttGridType; - - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Constructor using an exiting signed distance, - /// i.e. narrow band level set, grid. - /// - /// @param grid Level set grid in which particles are rasterized - /// @param interrupt Callback to interrupt a long-running process - /// - /// @note The input grid is assumed to be a valid level set and if - /// it already contains voxels (with SDF values) partices are unioned - /// onto the exisinting level set surface. However, if attribute tranfer - /// is enabled, i.e. AttributeT != void, attributes are only - /// generated for voxels that overlap with particles, not the existing - /// voxels in the input grid (for which no attributes exist!). - /// - /// @details The width in voxel units of the generated narrow band level set is - /// given by 2*background/dx, where background is the background value - /// stored in the grid, and dx is the voxel size derived from the - /// transform also stored in the grid. Also note that -background - /// corresponds to the constant value inside the generated narrow - /// band level sets. Finally the default NullInterrupter should - /// compile out interruption checks during optimization, thus - /// incurring no run-time overhead. - explicit ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupt = NULL); - - /// Destructor - ~ParticlesToLevelSet() { delete mBlindGrid; } - - /// @brief This methods syncs up the level set and attribute grids - /// and therefore needs to be called before any of these grids are - /// used and after the last call to any of the rasterizer methods. - /// - /// @note Avoid calling this method more then once and only after - /// all the particles have been rasterized. It has no effect or - /// overhead if attribute transfer is disabled, i.e. AttributeT = - /// void and prune is false. - void finalize(bool prune = false); - - /// @brief Return a shared pointer to the grid containing the - /// (optional) attribute. - /// - /// @warning If attribute transfer was disabled, i.e. AttributeT = - /// void, or finalize() was not called the pointer is NULL! - typename AttGridType::Ptr attributeGrid() { return mAttGrid; } - - /// @brief Return the size of a voxel in world units - Real getVoxelSize() const { return mDx; } - - /// @brief Return the half-width of the narrow band in voxel units - Real getHalfWidth() const { return mHalfWidth; } - - /// @brief Return the smallest radius allowed in voxel units - Real getRmin() const { return mRmin; } - /// @brief Return the largest radius allowed in voxel units - Real getRmax() const { return mRmax; } - - /// @brief Return true if any particles were ignored due to their size - bool ignoredParticles() const { return mMinCount>0 || mMaxCount>0; } - /// @brief Return number of small particles that were ignore due to Rmin - size_t getMinCount() const { return mMinCount; } - /// @brief Return number of large particles that were ignore due to Rmax - size_t getMaxCount() const { return mMaxCount; } - - /// @brief set the smallest radius allowed in voxel units - void setRmin(Real Rmin) { mRmin = math::Max(Real(0),Rmin); } - /// @brief set the largest radius allowed in voxel units - void setRmax(Real Rmax) { mRmax = math::Max(mRmin,Rmax); } - - /// @brief Rreturn the grain-size used for multi-threading - int getGrainSize() const { return mGrainSize; } - /// @brief Set the grain-size used for multi-threading. - /// @note A grainsize of 0 or less disables multi-threading! - void setGrainSize(int grainSize) { mGrainSize = grainSize; } - - /// @brief Rasterize a sphere per particle derived from their - /// position and radius. All spheres are CSG unioned. - /// - /// @param pa Particles with position and radius. - template - void rasterizeSpheres(const ParticleListT& pa); - - /// @brief Rasterize a sphere per particle derived from their - /// position and constant radius. All spheres are CSG unioned. - /// - /// @param pa Particles with position. - /// @param radius Constant particle radius in world units. - template - void rasterizeSpheres(const ParticleListT& pa, Real radius); - - /// @brief Rasterize a trail per particle derived from their - /// position, radius and velocity. Each trail is generated - /// as CSG unions of sphere instances with decreasing radius. - /// - /// @param pa particles with position, radius and velocity. - /// @param delta controls distance between sphere instances - /// (default=1). Be careful not to use too small values since this - /// can lead to excessive computation per trail (which the - /// interrupter can't stop). - /// - /// @note The direction of a trail is inverse to the direction of - /// the velocity vector, and the length is given by |V|. The radius - /// at the head of the trail is given by the radius of the particle - /// and the radius at the tail of the trail is Rmin voxel units which - /// has a default value of 1.5 corresponding to the Nyquist - /// frequency! - template - void rasterizeTrails(const ParticleListT& pa, Real delta=1.0); - -private: - typedef p2ls_internal::BlindData BlindType; - typedef typename SdfGridT::template ValueConverter::Type BlindGridType; - - /// Class with multi-threaded implementation of particle rasterization - template struct Raster; - - SdfGridType* mSdfGrid; - typename AttGridType::Ptr mAttGrid; - BlindGridType* mBlindGrid; - InterrupterT* mInterrupter; - Real mDx, mHalfWidth; - Real mRmin, mRmax;//ignore particles outside this range of radii in voxel - size_t mMinCount, mMaxCount;//counters for ignored particles! - int mGrainSize; - -};//end of ParticlesToLevelSet class - -template -inline ParticlesToLevelSet:: -ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupter) : - mSdfGrid(&grid), - mBlindGrid(NULL), - mInterrupter(interrupter), - mDx(grid.voxelSize()[0]), - mHalfWidth(grid.background()/mDx), - mRmin(1.5),// corresponds to the Nyquist grid sampling frequency - mRmax(100.0),// corresponds to a huge particle (probably too large!) - mMinCount(0), - mMaxCount(0), - mGrainSize(1) -{ - if (!mSdfGrid->hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "ParticlesToLevelSet only supports uniform voxels!"); - } - if (mSdfGrid->getGridClass() != GRID_LEVEL_SET) { - OPENVDB_THROW(RuntimeError, - "ParticlesToLevelSet only supports level sets!" - "\nUse Grid::setGridClass(openvdb::GRID_LEVEL_SET)"); - } - - if (!DisableT::value) { - mBlindGrid = new BlindGridType(BlindType(grid.background())); - mBlindGrid->setTransform(mSdfGrid->transform().copy()); - } -} - -template -template -inline void ParticlesToLevelSet:: -rasterizeSpheres(const ParticleListT& pa) -{ - if (DisableT::value) { - Raster r(*this, mSdfGrid, pa); - r.rasterizeSpheres(); - } else { - Raster r(*this, mBlindGrid, pa); - r.rasterizeSpheres(); - } -} - -template -template -inline void ParticlesToLevelSet:: -rasterizeSpheres(const ParticleListT& pa, Real radius) -{ - if (DisableT::value) { - Raster r(*this, mSdfGrid, pa); - r.rasterizeSpheres(radius/mDx); - } else { - Raster r(*this, mBlindGrid, pa); - r.rasterizeSpheres(radius/mDx); - } -} - -template -template -inline void ParticlesToLevelSet:: -rasterizeTrails(const ParticleListT& pa, Real delta) -{ - if (DisableT::value) { - Raster r(*this, mSdfGrid, pa); - r.rasterizeTrails(delta); - } else { - Raster r(*this, mBlindGrid, pa); - r.rasterizeTrails(delta); - } -} - -template -inline void -ParticlesToLevelSet::finalize(bool prune) -{ - if (mBlindGrid==NULL) { - if (prune) tools::pruneLevelSet(mSdfGrid->tree()); - return; - } else { - if (prune) tools::prune(mBlindGrid->tree()); - } - - typedef typename SdfGridType::TreeType SdfTreeT; - typedef typename AttGridType::TreeType AttTreeT; - typedef typename BlindGridType::TreeType BlindTreeT; - // Use topology copy constructors since output grids have the same topology as mBlindDataGrid - const BlindTreeT& tree = mBlindGrid->tree(); - - // New level set tree - typename SdfTreeT::Ptr sdfTree(new SdfTreeT( - tree, tree.background().visible(), openvdb::TopologyCopy())); - - // Note this overwrites any existing attribute grids! - typename AttTreeT::Ptr attTree(new AttTreeT( - tree, tree.background().blind(), openvdb::TopologyCopy())); - mAttGrid = typename AttGridType::Ptr(new AttGridType(attTree)); - mAttGrid->setTransform(mBlindGrid->transform().copy()); - - // Extract the level set and IDs from mBlindDataGrid. We will - // explore the fact that by design active values always live - // at the leaf node level, i.e. level sets have no active tiles! - typedef typename BlindTreeT::LeafCIter LeafIterT; - typedef typename BlindTreeT::LeafNodeType LeafT; - typedef typename SdfTreeT::LeafNodeType SdfLeafT; - typedef typename AttTreeT::LeafNodeType AttLeafT; - for (LeafIterT n = tree.cbeginLeaf(); n; ++n) { - const LeafT& leaf = *n; - const openvdb::Coord xyz = leaf.origin(); - // Get leafnodes that were allocated during topology contruction! - SdfLeafT* sdfLeaf = sdfTree->probeLeaf(xyz); - AttLeafT* attLeaf = attTree->probeLeaf(xyz); - // Use linear offset (vs coordinate) access for better performance! - typename LeafT::ValueOnCIter m=leaf.cbeginValueOn(); - if (!m) {//no active values in leaf node so copy everything - for (openvdb::Index k = 0; k!=LeafT::SIZE; ++k) { - const BlindType& v = leaf.getValue(k); - sdfLeaf->setValueOnly(k, v.visible()); - attLeaf->setValueOnly(k, v.blind()); - } - } else {//only copy active values (using flood fill for the inactive values) - for(; m; ++m) { - const openvdb::Index k = m.pos(); - const BlindType& v = *m; - sdfLeaf->setValueOnly(k, v.visible()); - attLeaf->setValueOnly(k, v.blind()); - } - } - } - - tools::signedFloodFill(*sdfTree);//required since we only transferred active voxels! - - if (mSdfGrid->empty()) { - mSdfGrid->setTree(sdfTree); - } else { - tools::csgUnion(mSdfGrid->tree(), *sdfTree, /*prune=*/true); - } -} - -/////////////////////////////////////////////////////////// - -template -template -struct ParticlesToLevelSet::Raster -{ - typedef typename boost::is_void::type DisableT; - typedef ParticlesToLevelSet ParticlesToLevelSetT; - typedef typename ParticlesToLevelSetT::SdfType SdfT;//type of signed distance values - typedef typename ParticlesToLevelSetT::AttType AttT;//type of particle attribute - typedef typename GridT::ValueType ValueT; - typedef typename GridT::Accessor AccessorT; - typedef typename GridT::TreeType TreeT; - typedef typename TreeT::LeafNodeType LeafNodeT; - typedef PointPartitioner PointPartitionerT; - - - /// @brief Main constructor - Raster(ParticlesToLevelSetT& parent, GridT* grid, const ParticleListT& particles) - : mParent(parent) - , mParticles(particles) - , mGrid(grid) - , mMap(*(mGrid->transform().baseMap())) - , mMinCount(0) - , mMaxCount(0) - , mIsCopy(false) - { - mPointPartitioner = new PointPartitionerT(); - mPointPartitioner->construct(particles, mGrid->transform()); - } - - /// @brief Copy constructor called by tbb threads - Raster(Raster& other, tbb::split) - : mParent(other.mParent) - , mParticles(other.mParticles) - , mGrid(new GridT(*other.mGrid, openvdb::ShallowCopy())) - , mMap(other.mMap) - , mMinCount(0) - , mMaxCount(0) - , mTask(other.mTask) - , mIsCopy(true) - , mPointPartitioner(other.mPointPartitioner) - { - mGrid->newTree(); - } - - virtual ~Raster() { - - // Copies construct temporary grids that have to be deleted - // but the original has ownership of the bucket array - if (mIsCopy) { - delete mGrid; - } else { - delete mPointPartitioner; - } - } - - /// @brief Rasterize a sphere per particle derived from their - /// position and radius. All spheres are CSG unioned. - void rasterizeSpheres() - { - mMinCount = mMaxCount = 0; - if (mParent.mInterrupter) { - mParent.mInterrupter->start("Rasterizing particles to level set using spheres"); - } - mTask = boost::bind(&Raster::rasterSpheres, _1, _2); - this->cook(); - if (mParent.mInterrupter) mParent.mInterrupter->end(); - } - /// @brief Rasterize a sphere per particle derived from their - /// position and constant radius. All spheres are CSG unioned. - /// @param radius constant radius of all particles in voxel units. - void rasterizeSpheres(Real radius) - { - mMinCount = radius < mParent.mRmin ? mParticles.size() : 0; - mMaxCount = radius > mParent.mRmax ? mParticles.size() : 0; - if (mMinCount>0 || mMaxCount>0) {//skipping all particles! - mParent.mMinCount = mMinCount; - mParent.mMaxCount = mMaxCount; - } else { - if (mParent.mInterrupter) { - mParent.mInterrupter->start( - "Rasterizing particles to level set using const spheres"); - } - mTask = boost::bind(&Raster::rasterFixedSpheres, _1, _2, SdfT(radius)); - this->cook(); - if (mParent.mInterrupter) mParent.mInterrupter->end(); - } - } - /// @brief Rasterize a trail per particle derived from their - /// position, radius and velocity. Each trail is generated - /// as CSG unions of sphere instances with decreasing radius. - /// - /// @param delta controls distance between sphere instances - /// (default=1). Be careful not to use too small values since this - /// can lead to excessive computation per trail (which the - /// interrupter can't stop). - /// - /// @note The direction of a trail is inverse to the direction of - /// the velocity vector, and the length is given by |V|. The radius - /// at the head of the trail is given by the radius of the particle - /// and the radius at the tail of the trail is Rmin voxel units which - /// has a default value of 1.5 corresponding to the Nyquist frequency! - void rasterizeTrails(Real delta=1.0) - { - mMinCount = mMaxCount = 0; - if (mParent.mInterrupter) { - mParent.mInterrupter->start("Rasterizing particles to level set using trails"); - } - mTask = boost::bind(&Raster::rasterTrails, _1, _2, SdfT(delta)); - this->cook(); - if (mParent.mInterrupter) mParent.mInterrupter->end(); - } - - /// @brief Kicks off the optionally multithreaded computation - void operator()(const tbb::blocked_range& r) - { - assert(mTask); - mTask(this, r); - mParent.mMinCount = mMinCount; - mParent.mMaxCount = mMaxCount; - } - - /// @brief Reguired by tbb::parallel_reduce - void join(Raster& other) - { - tools::csgUnion(*mGrid, *other.mGrid, /*prune=*/true); - mMinCount += other.mMinCount; - mMaxCount += other.mMaxCount; - } -private: - /// Disallow assignment since some of the members are references - Raster& operator=(const Raster& other) { return *this; } - - /// @return true if the particle is too small or too large - bool ignoreParticle(SdfT R) - { - if (R < mParent.mRmin) {// below the cutoff radius - ++mMinCount; - return true; - } - if (R > mParent.mRmax) {// above the cutoff radius - ++mMaxCount; - return true; - } - return false; - } - /// @brief Reguired by tbb::parallel_reduce to multithreaded - /// rasterization of particles as spheres with variable radius - /// - /// @param r tbb's default range referring to the list of particles - void rasterSpheres(const tbb::blocked_range& r) - { - AccessorT acc = mGrid->getAccessor(); // local accessor - bool run = true; - const SdfT invDx = SdfT(1/mParent.mDx); - AttT att; - Vec3R pos; - Real rad; - - // Loop over buckets - for (size_t n = r.begin(), N = r.end(); n < N; ++n) { - // Loop over particles in bucket n. - typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n); - for ( ; run && iter; ++iter) { - const Index32& id = *iter; - mParticles.getPosRad(id, pos, rad); - const SdfT R = SdfT(invDx * rad);// in voxel units - if (this->ignoreParticle(R)) continue; - const Vec3R P = mMap.applyInverseMap(pos); - this->getAtt(id, att); - run = this->makeSphere(P, R, att, acc); - }//end loop over particles - }//end loop over buckets - } - - /// @brief Reguired by tbb::parallel_reduce to multithreaded - /// rasterization of particles as spheres with a fixed radius - /// - /// @param r tbb's default range referring to the list of particles - void rasterFixedSpheres(const tbb::blocked_range& r, SdfT R) - { - const SdfT - dx = static_cast(mParent.mDx), - w = static_cast(mParent.mHalfWidth); // in voxel units - AccessorT acc = mGrid->getAccessor(); // local accessor - const ValueT inside = -mGrid->background(); - const SdfT max = R + w;// maximum distance in voxel units - const SdfT max2 = math::Pow2(max);//square of maximum distance in voxel units - const SdfT min2 = math::Pow2(math::Max(SdfT(0), R - w));//square of minimum distance - ValueT v; - size_t count = 0; - AttT att; - Vec3R pos; - - // Loop over buckets - for (size_t n = r.begin(), N = r.end(); n < N; ++n) { - // Loop over particles in bucket n. - typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n); - for ( ; iter; ++iter) { - const Index32& id = *iter; - this->getAtt(id, att); - mParticles.getPos(id, pos); - const Vec3R P = mMap.applyInverseMap(pos); - const Coord a(math::Floor(P[0]-max),math::Floor(P[1]-max),math::Floor(P[2]-max)); - const Coord b(math::Ceil( P[0]+max),math::Ceil( P[1]+max),math::Ceil( P[2]+max)); - for (Coord c = a; c.x() <= b.x(); ++c.x()) { - //only check interrupter every 32'th scan in x - if (!(count++ & ((1<<5)-1)) && util::wasInterrupted(mParent.mInterrupter)) { - tbb::task::self().cancel_group_execution(); - return; - } - SdfT x2 = static_cast(math::Pow2(c.x() - P[0])); - for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) { - SdfT x2y2 = static_cast(x2 + math::Pow2(c.y() - P[1])); - for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) { - SdfT x2y2z2 = static_cast( - x2y2 + math::Pow2(c.z()- P[2])); // square distance from c to P - if (x2y2z2 >= max2 || (!acc.probeValue(c,v) && v& r, SdfT delta) - { - AccessorT acc = mGrid->getAccessor(); // local accessor - bool run = true; - AttT att; - Vec3R pos, vel; - Real rad; - const Vec3R origin = mMap.applyInverseMap(Vec3R(0,0,0)); - const SdfT Rmin = SdfT(mParent.mRmin), invDx = SdfT(1/mParent.mDx); - - // Loop over buckets - for (size_t n = r.begin(), N = r.end(); n < N; ++n) { - // Loop over particles in bucket n. - typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n); - for ( ; run && iter; ++iter) { - const Index32& id = *iter; - mParticles.getPosRadVel(id, pos, rad, vel); - const SdfT R0 = SdfT(invDx*rad); - if (this->ignoreParticle(R0)) continue; - this->getAtt(id, att); - const Vec3R P0 = mMap.applyInverseMap(pos); - const Vec3R V = mMap.applyInverseMap(vel) - origin;//exclude translation - const SdfT speed = SdfT(V.length()), inv_speed = SdfT(1.0/speed); - const Vec3R Nrml = -V*inv_speed;// inverse normalized direction - Vec3R P = P0;// local position of instance - SdfT R = R0, d=0;// local radius and length of trail - for (size_t m=0; run && d <= speed ; ++m) { - run = this->makeSphere(P, R, att, acc); - P += 0.5*delta*R*Nrml;// adaptive offset along inverse velocity direction - d = SdfT((P-P0).length());// current length of trail - R = R0-(R0-Rmin)*d*inv_speed;// R = R0 -> mRmin(e.g. 1.5) - }//end loop over sphere instances - }//end loop over particles - }//end loop over buckets - } - - void cook() - { - // parallelize over the point buckets - const Index32 bucketCount = Index32(mPointPartitioner->size()); - - if (mParent.mGrainSize>0) { - tbb::parallel_reduce( - tbb::blocked_range(0, bucketCount, mParent.mGrainSize), *this); - } else { - (*this)(tbb::blocked_range(0, bucketCount)); - } - } - - /// @brief Rasterize sphere at position P and radius R into a - /// narrow-band level set with half-width, mHalfWidth. - /// @return false if it was interrupted - /// - /// @param P coordinates of the particle position in voxel units - /// @param R radius of particle in voxel units - /// @param id - /// @param accessor grid accessor with a private copy of the grid - /// - /// @note For best performance all computations are performed in - /// voxel-space with the important exception of the final level set - /// value that is converted to world units (e.g. the grid stores - /// the closest Euclidian signed distances measured in world - /// units). Also note we use the convention of positive distances - /// outside the surface an negative distances inside the surface. - bool makeSphere(const Vec3R &P, SdfT R, const AttT& att, AccessorT& acc) - { - const ValueT inside = -mGrid->background(); - const SdfT dx = SdfT(mParent.mDx), w = SdfT(mParent.mHalfWidth); - const SdfT max = R + w;// maximum distance in voxel units - const Coord a(math::Floor(P[0]-max),math::Floor(P[1]-max),math::Floor(P[2]-max)); - const Coord b(math::Ceil( P[0]+max),math::Ceil( P[1]+max),math::Ceil( P[2]+max)); - const SdfT max2 = math::Pow2(max);//square of maximum distance in voxel units - const SdfT min2 = math::Pow2(math::Max(SdfT(0), R - w));//square of minimum distance - ValueT v; - size_t count = 0; - for ( Coord c = a; c.x() <= b.x(); ++c.x() ) { - //only check interrupter every 32'th scan in x - if (!(count++ & ((1<<5)-1)) && util::wasInterrupted(mParent.mInterrupter)) { - tbb::task::self().cancel_group_execution(); - return false; - } - SdfT x2 = SdfT(math::Pow2(c.x() - P[0])); - for (c.y() = a.y(); c.y() <= b.y(); ++c.y()) { - SdfT x2y2 = SdfT(x2 + math::Pow2(c.y() - P[1])); - for (c.z() = a.z(); c.z() <= b.z(); ++c.z()) { - SdfT x2y2z2 = SdfT(x2y2 + math::Pow2(c.z()-P[2]));//square distance from c to P - if (x2y2z2 >= max2 || (!acc.probeValue(c,v) && v&)> FuncType; - - template - typename boost::enable_if::type - getAtt(size_t, AttT&) const {;} - - template - typename boost::disable_if::type - getAtt(size_t n, AttT& a) const { mParticles.getAtt(n, a); } - - template - typename boost::enable_if, ValueT>::type - Merge(T s, const AttT&) const { return s; } - - template - typename boost::disable_if, ValueT>::type - Merge(T s, const AttT& a) const { return ValueT(s,a); } - - ParticlesToLevelSetT& mParent; - const ParticleListT& mParticles;//list of particles - GridT* mGrid; - const math::MapBase& mMap; - size_t mMinCount, mMaxCount;//counters for ignored particles! - FuncType mTask; - const bool mIsCopy; - PointPartitionerT* mPointPartitioner; -};//end of Raster struct - - -///////////////////// YOU CAN SAFELY IGNORE THIS SECTION ///////////////////// - -namespace p2ls_internal { - -// This is a simple type that combines a distance value and a particle -// attribute. It's required for attribute transfer which is defined in the -// Raster class above. -template -class BlindData -{ -public: - typedef VisibleT type; - typedef VisibleT VisibleType; - typedef BlindT BlindType; - - BlindData() {} - explicit BlindData(VisibleT v) : mVisible(v), mBlind(zeroVal()) {} - BlindData(VisibleT v, BlindT b) : mVisible(v), mBlind(b) {} - BlindData& operator=(const BlindData& rhs) - { - mVisible = rhs.mVisible; - mBlind = rhs.mBlind; - return *this; - } - const VisibleT& visible() const { return mVisible; } - const BlindT& blind() const { return mBlind; } - bool operator==(const BlindData& rhs) const { return mVisible == rhs.mVisible; } - bool operator< (const BlindData& rhs) const { return mVisible < rhs.mVisible; }; - bool operator> (const BlindData& rhs) const { return mVisible > rhs.mVisible; }; - BlindData operator+(const BlindData& rhs) const { return BlindData(mVisible + rhs.mVisible); }; - BlindData operator+(const VisibleT& rhs) const { return BlindData(mVisible + rhs); }; - BlindData operator-(const BlindData& rhs) const { return BlindData(mVisible - rhs.mVisible); }; - BlindData operator-() const { return BlindData(-mVisible, mBlind); } - -protected: - VisibleT mVisible; - BlindT mBlind; -}; - -// Required by several of the tree nodes -template -inline std::ostream& operator<<(std::ostream& ostr, const BlindData& rhs) -{ - ostr << rhs.visible(); - return ostr; -} - -// Required by math::Abs -template -inline BlindData Abs(const BlindData& x) -{ - return BlindData(math::Abs(x.visible()), x.blind()); -} - -} // namespace p2ls_internal - -////////////////////////////////////////////////////////////////////////////// - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/PointAdvect.h b/openvdb_3_0_0_library/tools/PointAdvect.h deleted file mode 100755 index 23cbc29..0000000 --- a/openvdb_3_0_0_library/tools/PointAdvect.h +++ /dev/null @@ -1,524 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth, D.J. Hill (openvdb port, added staggered grid support) -/// @file PointAdvect.h -/// -/// @brief Class PointAdvect advects points (with position) in a static velocity field - -#ifndef OPENVDB_TOOLS_POINT_ADVECT_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_POINT_ADVECT_HAS_BEEN_INCLUDED - -#include -#include // min -#include // Vec3 types and version number -#include // grid -#include -#include "Interpolation.h" // sampling - -#include -#include // threading -#include // threading -#include // for cancel - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// Class that holds a Vec3 grid, to be interpreted as the closest point to a constraint -/// surface. Supports a method to allow a point to be projected onto the closest point -/// on the constraint surface. Uses Caching. -template -class ClosestPointProjector -{ -public: - typedef CptGridT CptGridType; - typedef typename CptGridType::ConstAccessor CptAccessor; - typedef typename CptGridType::ValueType CptValueType; - - ClosestPointProjector(): - mCptIterations(0) - { - } - ClosestPointProjector(const CptGridType& cptGrid, int n): - mCptGrid(&cptGrid), - mCptAccessor(cptGrid.getAccessor()), - mCptIterations(n) - { - } - ClosestPointProjector(const ClosestPointProjector &other): - mCptGrid(other.mCptGrid), - mCptAccessor(mCptGrid->getAccessor()), - mCptIterations(other.mCptIterations) - { - } - void setConstraintIterations(unsigned int cptIterations) { mCptIterations = cptIterations; } - unsigned int numIterations() { return mCptIterations;}; - - // point constraint - template - inline void projectToConstraintSurface(LocationType& W) const - { - /// Entries in the CPT tree are the closest point to the constraint surface. - /// The interpolation step in sample introduces error so that the result - /// of a single sample may not lie exactly on the surface. The iterations - /// in the loop exist to minimize this error. - CptValueType result(W[0], W[1],W[2]); - for (unsigned int i = 0; i < mCptIterations; ++i) { - const Vec3R location = mCptGrid->worldToIndex(Vec3R(result[0], result[1], result[2])); - BoxSampler::sample(mCptAccessor, location, result); - } - W[0] = result[0]; - W[1] = result[1]; - W[2] = result[2]; - } - -private: - const CptGridType* mCptGrid; // Closest-Point-Transform vector field - CptAccessor mCptAccessor; - unsigned int mCptIterations; -};// end of ClosestPointProjector class - - -/// Class to hold a Vec3 field interperated as a velocity field. -/// Primarily exists to provide a method(s) that integrate a passive -/// point forward in the velocity field for a single time-step (dt) -template -class VelocitySampler -{ -public: - typedef typename GridT::ConstAccessor VelAccessor; - typedef typename GridT::ValueType VelValueType; - - VelocitySampler(const GridT& velGrid): - mVelGrid(&velGrid), - mVelAccessor(mVelGrid->getAccessor()) - { - } - VelocitySampler(const VelocitySampler& other): - mVelGrid(other.mVelGrid), - mVelAccessor(mVelGrid->getAccessor()) - { - } - ~VelocitySampler() - { - } - /// Samples the velocity at position W onto result. Supports both - /// staggered (i.e. MAC) and collocated velocity grids. - template - inline void sample(const LocationType& W, VelValueType& result) const - { - const Vec3R location = mVelGrid->worldToIndex(Vec3R(W[0], W[1], W[2])); - /// Note this if-branch is optimized away at compile time - if (StaggeredVelocity) { - // the velocity Grid stores data in MAC-style staggered layout - StaggeredBoxSampler::sample(mVelAccessor, location, result); - } else { - // the velocity Grid uses collocated data - BoxSampler::sample(mVelAccessor, location, result); - } - } - -private: - // holding the Grids for the transforms - const GridT* mVelGrid; // Velocity vector field - VelAccessor mVelAccessor; -};// end of VelocitySampler class - - -/// @brief Performs runge-kutta time integration of variable order in -/// a static velocity field -template -class VelocityIntegrator -{ -public: - typedef typename GridT::ValueType VecType; - typedef typename VecType::ValueType ElementType; - - VelocityIntegrator(const GridT& velGrid): - mVelField(velGrid) - { - } - // variable order Runge-Kutta time integration for a single time step - template - void rungeKutta(const float dt, LocationType& loc) { - VecType P(loc[0],loc[1],loc[2]), V0, V1, V2, V3; - - BOOST_STATIC_ASSERT((Order < 5) && (Order > -1)); - /// Note the if-braching below is optimized away at compile time - if (Order == 0) { - // do nothing - return ; - } else if (Order == 1) { - mVelField.sample(P, V0); - P = dt*V0; - - } else if (Order == 2) { - mVelField.sample(P, V0); - mVelField.sample(P + ElementType(0.5) * ElementType(dt) * V0, V1); - P = dt*V1; - - } else if (Order == 3) { - mVelField.sample(P, V0); - mVelField.sample(P+ElementType(0.5)*ElementType(dt)*V0, V1); - mVelField.sample(P+dt*(ElementType(2.0)*V1-V0), V2); - P = dt*(V0 + ElementType(4.0)*V1 + V2)*ElementType(1.0/6.0); - - } else if (Order == 4) { - mVelField.sample(P, V0); - mVelField.sample(P+ElementType(0.5)*ElementType(dt)*V0, V1); - mVelField.sample(P+ElementType(0.5)*ElementType(dt)*V1, V2); - mVelField.sample(P+ dt*V2, V3); - P = dt*(V0 + ElementType(2.0)*(V1 + V2) + V3)*ElementType(1.0/6.0); - - } - loc += LocationType(P[0], P[1], P[2]); - - } -private: - VelocitySampler mVelField; -};// end of VelocityIntegrator class - - -//////////////////////////////////////// - - -/// Performs passive or constrained advection of points in a velocity field -/// represented by an OpenVDB grid and an optional closest-point-transform (CPT) -/// represented in another OpenVDB grid. Note the CPT is assumed to be -/// in world coordinates and NOT index coordinates! -/// Supports both collocated velocity grids and staggered velocity grids -/// -/// The @c PointListT template argument refers to any class with the following -/// interface (e.g., std::vector): -/// @code -/// class PointList { -/// ... -/// public: -/// typedef internal_vector3_type value_type; // must support [] component access -/// openvdb::Index size() const; // number of points in list -/// value_type& operator[](int n); // world space position of nth point -/// }; -/// @endcode -/// -/// @note All methods (except size) are assumed to be thread-safe and -/// the positions are returned as non-const references since the -/// advection method needs to modify them! -template, - bool StaggeredVelocity = false, - typename InterrupterType = util::NullInterrupter> -class PointAdvect -{ -public: - typedef GridT GridType; - typedef PointListT PointListType; - typedef typename PointListT::value_type LocationType; - typedef VelocityIntegrator VelocityFieldIntegrator; - - PointAdvect(const GridT& velGrid, InterrupterType* interrupter=NULL) : - mVelGrid(&velGrid), - mPoints(NULL), - mIntegrationOrder(1), - mThreaded(true), - mInterrupter(interrupter) - { - } - PointAdvect(const PointAdvect &other) : - mVelGrid(other.mVelGrid), - mPoints(other.mPoints), - mDt(other.mDt), - mAdvIterations(other.mAdvIterations), - mIntegrationOrder(other.mIntegrationOrder), - mThreaded(other.mThreaded), - mInterrupter(other.mInterrupter) - { - } - virtual ~PointAdvect() - { - } - /// If the order of the integration is set to zero no advection is performed - bool earlyOut() const { return (mIntegrationOrder==0);} - /// get & set - void setThreaded(bool threaded) { mThreaded = threaded; } - bool getThreaded() { return mThreaded; } - void setIntegrationOrder(unsigned int order) {mIntegrationOrder = order;} - - /// Constrained advection of a list of points over a time = dt * advIterations - void advect(PointListT& points, float dt, unsigned int advIterations = 1) - { - if (this->earlyOut()) return; // nothing to do! - mPoints = &points; - mDt = dt; - mAdvIterations = advIterations; - - if (mInterrupter) mInterrupter->start("Advecting points by OpenVDB velocity field: "); - if (mThreaded) { - tbb::parallel_for(tbb::blocked_range(0, mPoints->size()), *this); - } else { - (*this)(tbb::blocked_range(0, mPoints->size())); - } - if (mInterrupter) mInterrupter->end(); - } - - /// Never call this method directly - it is use by TBB and has to be public! - void operator() (const tbb::blocked_range &range) const - { - if (mInterrupter && mInterrupter->wasInterrupted()) { - tbb::task::self().cancel_group_execution(); - } - - VelocityFieldIntegrator velField(*mVelGrid); - switch (mIntegrationOrder) { - case 1: - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - // loop over number of time steps - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<1>(mDt, X0); - } - } - } - break; - case 2: - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - // loop over number of time steps - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<2>(mDt, X0); - } - } - } - break; - case 3: - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - // loop over number of time steps - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<3>(mDt, X0); - } - } - } - break; - case 4: - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - // loop over number of time steps - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<4>(mDt, X0); - } - } - } - break; - } - } - -private: - // the velocity field - const GridType* mVelGrid; - - // vertex list of all the points - PointListT* mPoints; - - // time integration parameters - float mDt; // time step - unsigned int mAdvIterations; // number of time steps - unsigned int mIntegrationOrder; - - // operational parameters - bool mThreaded; - InterrupterType* mInterrupter; - -};//end of PointAdvect class - - -template, - bool StaggeredVelocity = false, - typename CptGridType = GridT, - typename InterrupterType = util::NullInterrupter> -class ConstrainedPointAdvect -{ -public: - typedef GridT GridType; - typedef typename PointListT::value_type LocationType; - typedef VelocityIntegrator VelocityIntegratorType; - typedef ClosestPointProjector ClosestPointProjectorType; - typedef PointListT PointListType; - - ConstrainedPointAdvect(const GridType& velGrid, - const GridType& cptGrid, int cptn, InterrupterType* interrupter = NULL): - mVelGrid(&velGrid), - mCptGrid(&cptGrid), - mCptIter(cptn), - mInterrupter(interrupter) - { - } - ConstrainedPointAdvect(const ConstrainedPointAdvect& other): - mVelGrid(other.mVelGrid), - mCptGrid(other.mCptGrid), - mCptIter(other.mCptIter), - mPoints(other.mPoints), - mDt(other.mDt), - mAdvIterations(other.mAdvIterations), - mIntegrationOrder(other.mIntegrationOrder), - mThreaded(other.mThreaded), - mInterrupter(other.mInterrupter) - { - } - virtual ~ConstrainedPointAdvect(){} - - void setConstraintIterations(unsigned int cptIter) {mCptIter = cptIter;} - void setIntegrationOrder(unsigned int order) {mIntegrationOrder = order;} - - void setThreaded(bool threaded) { mThreaded = threaded; } - bool getThreaded() { return mThreaded; } - - /// Constrained Advection a list of points over a time = dt * advIterations - void advect(PointListT& points, float dt, unsigned int advIterations = 1) - { - mPoints = &points; - mDt = dt; - - if (mIntegrationOrder==0 && mCptIter == 0) { - return; // nothing to do! - } - (mIntegrationOrder>0) ? mAdvIterations = advIterations : mAdvIterations = 1; - - if (mInterrupter) mInterrupter->start("Advecting points by OpenVDB velocity field: "); - const size_t N = mPoints->size(); - - if (mThreaded) { - tbb::parallel_for(tbb::blocked_range(0, N), *this); - } else { - (*this)(tbb::blocked_range(0, N)); - } - if (mInterrupter) mInterrupter->end(); - } - - - /// Never call this method directly - it is use by TBB and has to be public! - void operator() (const tbb::blocked_range &range) const - { - if (mInterrupter && mInterrupter->wasInterrupted()) { - tbb::task::self().cancel_group_execution(); - } - - VelocityIntegratorType velField(*mVelGrid); - ClosestPointProjectorType cptField(*mCptGrid, mCptIter); - switch (mIntegrationOrder) { - case 0://pure CPT projection - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - for (unsigned int i = 0; i < mAdvIterations; ++i) { - cptField.projectToConstraintSurface(X0); - } - } - } - break; - case 1://1'th order advection and CPT projection - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<1>(mDt, X0); - cptField.projectToConstraintSurface(X0); - } - } - } - break; - case 2://2'nd order advection and CPT projection - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<2>(mDt, X0); - cptField.projectToConstraintSurface(X0); - } - } - } - break; - - case 3://3'rd order advection and CPT projection - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<3>(mDt, X0); - cptField.projectToConstraintSurface(X0); - } - } - } - break; - case 4://4'th order advection and CPT projection - { - for (size_t n = range.begin(); n != range.end(); ++n) { - LocationType& X0 = (*mPoints)[n]; - for (unsigned int i = 0; i < mAdvIterations; ++i) { - velField.template rungeKutta<4>(mDt, X0); - cptField.projectToConstraintSurface(X0); - } - } - } - break; - } - } - -private: - const GridType* mVelGrid; // the velocity field - const GridType* mCptGrid; - int mCptIter; - PointListT* mPoints; // vertex list of all the points - - // time integration parameters - float mDt; // time step - unsigned int mAdvIterations; // number of time steps - unsigned int mIntegrationOrder; // order of Runge-Kutta integration - // operational parameters - bool mThreaded; - InterrupterType* mInterrupter; -};// end of ConstrainedPointAdvect class - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_POINT_ADVECT_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/PointIndexGrid.h b/openvdb_3_0_0_library/tools/PointIndexGrid.h deleted file mode 100755 index ee5056b..0000000 --- a/openvdb_3_0_0_library/tools/PointIndexGrid.h +++ /dev/null @@ -1,1809 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file PointIndexGrid.h -/// -/// @brief Space-partitioning acceleration structure for points. Partitions -/// the points into voxels to accelerate range and nearest neighbor -/// searches. -/// -/// @note Leaf nodes store a single point-index array and the voxels are only -/// integer offsets into that array. The actual points are never stored -/// in the acceleration structure, only offsets into an external array. -/// -/// @author Mihai Alden - -#ifndef OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED - - -#include -#include -#include -#include -#include -#include -#include "PointPartitioner.h" - -#include -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -namespace tree { -template struct SameLeafConfig; // forward declaration -} - -namespace tools { - -template struct PointIndexLeafNode; // forward declaration - -/// Point index tree configured to match the default OpenVDB tree configuration -typedef tree::Tree, 4>, 5> > > PointIndexTree; - -/// Point index grid -typedef Grid PointIndexGrid; - - -//////////////////////////////////////// - - -/// @interface PointArray -/// Expected interface for the PointArray container: -/// @code -/// template -/// struct PointArray -/// { -/// // The type used to represent world-space point positions -/// typedef VectorType value_type; -/// -/// // Return the number of points in the array -/// size_t size() const; -/// -/// // Return the world-space position of the nth point in the array. -/// void getPos(size_t n, VectorType& xyz) const; -/// }; -/// @endcode - - -//////////////////////////////////////// - - -/// @brief Partition points into a point index grid to accelerate range and -/// nearest-neighbor searches. -/// -/// @param points world-space point array conforming to the PointArray interface -/// @param xform world-to-index-space transform -template -inline typename GridT::Ptr -createPointIndexGrid(const PointArrayT& points, const math::Transform& xform); - - -/// @brief Return @c true if the given point index grid represents a valid partitioning -/// of the given point array. -/// -/// @param points world-space point array conforming to the PointArray interface -/// @param grid point index grid to validate -template -inline bool -isValidPartition(const PointArrayT& points, const GridT& grid); - - -/// Repartition the @a points if needed, otherwise return the input @a grid. -template -inline typename GridT::ConstPtr -getValidPointIndexGrid(const PointArrayT& points, const typename GridT::ConstPtr& grid); - -/// Repartition the @a points if needed, otherwise return the input @a grid. -template -inline typename GridT::Ptr -getValidPointIndexGrid(const PointArrayT& points, const typename GridT::Ptr& grid); - - -//////////////////////////////////////// - - -/// Accelerated range and nearest-neighbor searches for point index grids -template -struct PointIndexIterator -{ - typedef tree::ValueAccessor ConstAccessor; - typedef typename TreeType::LeafNodeType LeafNodeType; - typedef typename TreeType::ValueType ValueType; - - - PointIndexIterator(); - PointIndexIterator(const PointIndexIterator& rhs); - PointIndexIterator& operator=(const PointIndexIterator& rhs); - - - /// @brief Construct an iterator over the indices of the points contained in voxel (i, j, k). - /// @param ijk the voxel containing the points over which to iterate - /// @param acc an accessor for the grid or tree that holds the point indices - PointIndexIterator(const Coord& ijk, ConstAccessor& acc); - - - /// @brief Construct an iterator over the indices of the points contained in - /// the given bounding box. - /// @param bbox the bounding box of the voxels containing the points over which to iterate - /// @param acc an accessor for the grid or tree that holds the point indices - /// @note The range of the @a bbox is inclusive. Thus, a bounding box with - /// min = max is not empty but rather encloses a single voxel. - PointIndexIterator(const CoordBBox& bbox, ConstAccessor& acc); - - - /// @brief Clear the iterator and update it with the result of the given voxel query. - /// @param ijk the voxel containing the points over which to iterate - /// @param acc an accessor for the grid or tree that holds the point indices - void searchAndUpdate(const Coord& ijk, ConstAccessor& acc); - - - /// @brief Clear the iterator and update it with the result of the given voxel region query. - /// @param bbox the bounding box of the voxels containing the points over which to iterate - /// @param acc an accessor for the grid or tree that holds the point indices - /// @note The range of the @a bbox is inclusive. Thus, a bounding box with - /// min = max is not empty but rather encloses a single voxel. - void searchAndUpdate(const CoordBBox& bbox, ConstAccessor& acc); - - - /// @brief Clear the iterator and update it with the result of the given - /// index-space bounding box query. - /// @param bbox index-space bounding box - /// @param acc an accessor for the grid or tree that holds the point indices - /// @param points world-space point array conforming to the PointArray interface - /// @param xform linear, uniform-scale transform (i.e., cubical voxels) - template - void searchAndUpdate(const BBoxd& bbox, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform); - - - /// @brief Clear the iterator and update it with the result of the given - /// index-space radial query. - /// @param center index-space center - /// @param radius index-space radius - /// @param acc an accessor for the grid or tree that holds the point indices - /// @param points world-space point array conforming to the PointArray interface - /// @param xform linear, uniform-scale transform (i.e., cubical voxels) - /// @param subvoxelAccuracy if true, check individual points against the search region, - /// otherwise return all points that reside in voxels that are inside - /// or intersect the search region - template - void searchAndUpdate(const Vec3d& center, double radius, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform, bool subvoxelAccuracy = true); - - - /// @brief Clear the iterator and update it with the result of the given - /// world-space bounding box query. - /// @param bbox world-space bounding box - /// @param acc an accessor for the grid or tree that holds the point indices - /// @param points world-space point array conforming to the PointArray interface - /// @param xform linear, uniform-scale transform (i.e., cubical voxels) - template - void worldSpaceSearchAndUpdate(const BBoxd& bbox, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform); - - - /// @brief Clear the iterator and update it with the result of the given - /// world-space radial query. - /// @param center world-space center - /// @param radius world-space radius - /// @param acc an accessor for the grid or tree that holds the point indices - /// @param points world-space point array conforming to the PointArray interface - /// @param xform linear, uniform-scale transform (i.e., cubical voxels) - /// @param subvoxelAccuracy if true, check individual points against the search region, - /// otherwise return all points that reside in voxels that are inside - /// or intersect the search region - template - void worldSpaceSearchAndUpdate(const Vec3d& center, double radius, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform, bool subvoxelAccuracy = true); - - - /// Reset the iterator to point to the first item. - void reset(); - - /// Return a const reference to the item to which this iterator is pointing. - const ValueType& operator*() const { return *mRange.first; } - - /// @{ - /// @brief Return @c true if this iterator is not yet exhausted. - bool test() const { return mRange.first < mRange.second || mIter != mRangeList.end(); } - operator bool() const { return this->test(); } - /// @} - - /// Advance iterator to next item. - void increment(); - - /// Advance iterator to next item. - void operator++() { this->increment(); } - - - /// @brief Advance iterator to next item. - /// @return @c true if this iterator is not yet exhausted. - bool next(); - - /// Return the number of point indices in the iterator range. - size_t size() const; - - /// Return @c true if both iterators point to the same element. - bool operator==(const PointIndexIterator& p) const { return mRange.first == p.mRange.first; } - bool operator!=(const PointIndexIterator& p) const { return !this->operator==(p); } - - -private: - typedef std::pair Range; - typedef std::deque RangeDeque; - typedef typename RangeDeque::const_iterator RangeDequeCIter; - typedef boost::scoped_array IndexArray; - - void clear(); - - // Primary index collection - Range mRange; - RangeDeque mRangeList; - RangeDequeCIter mIter; - // Secondary index collection - IndexArray mIndexArray; - size_t mIndexArraySize; -}; // struct PointIndexIterator - - -/// @brief Selectively extract and filter point data using a custom filter operator. -/// -/// @par FilterType example: -/// @interface FilterType -/// @code -/// template -/// struct WeightedAverageAccumulator { -/// typedef T ValueType; -/// -/// WeightedAverageAccumulator(T const * const array, const T radius) -/// : mValues(array), mInvRadius(1.0/radius), mWeightSum(0.0), mValueSum(0.0) {} -/// -/// void reset() { mWeightSum = mValueSum = T(0.0); } -/// -/// // the following method is invoked by the PointIndexFilter -/// void operator()(const T distSqr, const size_t pointIndex) { -/// const T weight = T(1.0) - openvdb::math::Sqrt(distSqr) * mInvRadius; -/// mWeightSum += weight; -/// mValueSum += weight * mValues[pointIndex]; -/// } -/// -/// T result() const { return mWeightSum > T(0.0) ? mValueSum / mWeightSum : T(0.0); } -/// -/// private: -/// T const * const mValues; -/// const T mInvRadius; -/// T mWeightSum, mValueSum; -/// }; // struct WeightedAverageAccumulator -/// @endcode -template -struct PointIndexFilter -{ - typedef typename PointArray::value_type PointType; - typedef typename PointType::ValueType PointElementType; - typedef tree::ValueAccessor ConstAccessor; - - /// @brief Constructor - /// @param points world-space point array conforming to the PointArray interface - /// @param tree a point index tree - /// @param xform linear, uniform-scale transform (i.e., cubical voxels) - PointIndexFilter(const PointArray& points, const TreeType& tree, const math::Transform& xform); - - /// Thread safe copy constructor - PointIndexFilter(const PointIndexFilter& rhs); - - /// @brief Perform a radial search query and apply the given filter - /// operator to the selected points. - /// @param center world-space center - /// @param radius world-space radius - /// @param op custom filter operator (see the FilterType example for interface details) - template - void searchAndApply(const PointType& center, PointElementType radius, FilterType& op); - -private: - PointArray const * const mPoints; - ConstAccessor mAcc; - const math::Transform mXform; - const PointElementType mInvVoxelSize; - PointIndexIterator mIter; -}; // struct PointIndexFilter - - -//////////////////////////////////////// - -// Internal operators and implementation details - - -namespace point_index_grid_internal { - -template -struct ValidPartitioningOp -{ - ValidPartitioningOp(tbb::atomic& hasChanged, - const PointArrayT& points, const math::Transform& xform) - : mPoints(&points) - , mTransform(&xform) - , mHasChanged(&hasChanged) - { - } - - template - void operator()(LeafT &leaf, size_t /*leafIndex*/) const - { - if ((*mHasChanged)) { - tbb::task::self().cancel_group_execution(); - return; - } - - typedef typename LeafT::IndexArray IndexArrayT; - typedef typename IndexArrayT::value_type IndexT; - typedef typename PointArrayT::value_type PointT; - - typename LeafT::ValueOnCIter iter; - Coord voxelCoord; - PointT point; - - const IndexT *begin = static_cast(NULL), *end = static_cast(NULL); - - for (iter = leaf.cbeginValueOn(); iter; ++iter) { - - if ((*mHasChanged)) break; - - voxelCoord = iter.getCoord(); - leaf.getIndices(iter.pos(), begin, end); - - while (begin < end) { - - mPoints->getPos(*begin, point); - if (voxelCoord != mTransform->worldToIndexCellCentered(point)) { - mHasChanged->fetch_and_store(true); - break; - } - - ++begin; - } - } - } - -private: - PointArrayT const * const mPoints; - math::Transform const * const mTransform; - tbb::atomic * const mHasChanged; -}; - - -template -struct PopulateLeafNodesOp -{ - typedef uint32_t IndexT; - typedef PointPartitioner Partitioner; - - PopulateLeafNodesOp(boost::scoped_array& leafNodes, - const Partitioner& partitioner) - : mLeafNodes(leafNodes.get()) - , mPartitioner(&partitioner) - { - } - - void operator()(const tbb::blocked_range& range) const { - - typedef typename Partitioner::VoxelOffsetType VoxelOffsetT; - - size_t maxPointCount = 0; - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - maxPointCount = std::max(maxPointCount, mPartitioner->indices(n).size()); - } - - const IndexT voxelCount = LeafNodeT::SIZE; - - // allocate histogram buffers - boost::scoped_array offsets(new VoxelOffsetT[maxPointCount]); - boost::scoped_array histogram(new IndexT[voxelCount]); - - VoxelOffsetT const * const voxelOffsets = mPartitioner->voxelOffsets().get(); - - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - - LeafNodeT* node = new LeafNodeT(); - node->setOrigin(mPartitioner->origin(n)); - - typename Partitioner::IndexIterator it = mPartitioner->indices(n); - - const size_t pointCount = it.size(); - IndexT const * const indices = &*it; - - // local copy of voxel offsets. - for (IndexT i = 0; i < pointCount; ++i) { - offsets[i] = voxelOffsets[ indices[i] ]; - } - - // compute voxel-offset histogram - memset(&histogram[0], 0, voxelCount * sizeof(IndexT)); - for (IndexT i = 0; i < pointCount; ++i) { - ++histogram[ offsets[i] ]; - } - - typename LeafNodeT::NodeMaskType& mask = node->getValueMask(); - typename LeafNodeT::Buffer& buffer = node->buffer(); - - // scan histogram (all-prefix-sums) - IndexT count = 0, startOffset; - for (int i = 0; i < int(voxelCount); ++i) { - if (histogram[i] > 0) { - startOffset = count; - count += histogram[i]; - histogram[i] = startOffset; - mask.setOn(i); - } - buffer.setValue(i, count); - } - - // allocate point-index array - node->indices().resize(pointCount); - typename LeafNodeT::ValueType * const orderedIndices = node->indices().data(); - - // rank and permute - for (IndexT i = 0; i < pointCount; ++i) { - orderedIndices[ histogram[ offsets[i] ]++ ] = indices[i]; - } - - mLeafNodes[n] = node; - } - } - - ////////// - - LeafNodeT* * const mLeafNodes; - Partitioner const * const mPartitioner; -}; - - -/// Construct a @c PointIndexTree -template -inline void -constructPointTree(TreeType& tree, const math::Transform& xform, const PointArray& points) -{ - typedef typename TreeType::LeafNodeType LeafType; - - boost::scoped_array leafNodes; - size_t leafNodeCount = 0; - - { - PointPartitioner partitioner; - partitioner.construct(points, xform, /*voxelOrder=*/false, /*recordVoxelOffsets=*/true); - - leafNodeCount = partitioner.size(); - leafNodes.reset(new LeafType*[leafNodeCount]); - - const tbb::blocked_range range(0, leafNodeCount); - tbb::parallel_for(range, PopulateLeafNodesOp(leafNodes, partitioner)); - } - - tree::ValueAccessor acc(tree); - for (size_t n = 0; n < leafNodeCount; ++n) { - acc.addLeaf(leafNodes[n]); - } -} - - -//////////////////////////////////////// - - -template -inline void -dequeToArray(const std::deque& d, boost::scoped_array& a, size_t& size) -{ - size = d.size(); - a.reset(new T[size]); - typename std::deque::const_iterator it = d.begin(), itEnd = d.end(); - T* item = a.get(); - for ( ; it != itEnd; ++it, ++item) *item = *it; -} - - -inline void -constructExclusiveRegions(std::vector& regions, - const CoordBBox& bbox, const CoordBBox& ibox) -{ - regions.clear(); - regions.reserve(6); - Coord cmin = ibox.min(); - Coord cmax = ibox.max(); - - // left-face bbox - regions.push_back(bbox); - regions.back().max().z() = cmin.z(); - - // right-face bbox - regions.push_back(bbox); - regions.back().min().z() = cmax.z(); - - --cmax.z(); // accounting for cell centered bucketing. - ++cmin.z(); - - // front-face bbox - regions.push_back(bbox); - CoordBBox* lastRegion = ®ions.back(); - lastRegion->min().z() = cmin.z(); - lastRegion->max().z() = cmax.z(); - lastRegion->max().x() = cmin.x(); - - // back-face bbox - regions.push_back(*lastRegion); - lastRegion = ®ions.back(); - lastRegion->min().x() = cmax.x(); - lastRegion->max().x() = bbox.max().x(); - - --cmax.x(); - ++cmin.x(); - - // bottom-face bbox - regions.push_back(*lastRegion); - lastRegion = ®ions.back(); - lastRegion->min().x() = cmin.x(); - lastRegion->max().x() = cmax.x(); - lastRegion->max().y() = cmin.y(); - - // top-face bbox - regions.push_back(*lastRegion); - lastRegion = ®ions.back(); - lastRegion->min().y() = cmax.y(); - lastRegion->max().y() = bbox.max().y(); -} - - -template -struct BBoxFilter -{ - typedef typename PointArray::value_type PointType; - typedef typename PointType::ValueType PointElementType; - typedef std::pair Range; - typedef std::deque RangeDeque; - typedef std::deque IndexDeque; - - BBoxFilter(RangeDeque& ranges, IndexDeque& indices, const BBoxd& bbox, - const PointArray& points, const math::Transform& xform) - : mRanges(ranges) - , mIndices(indices) - , mRegion(bbox) - , mPoints(points) - , mMap(*xform.baseMap()) - { - } - - template - void filterLeafNode(const LeafNodeType& leaf) - { - typename LeafNodeType::ValueOnCIter iter; - const IndexT *begin = static_cast(NULL), *end = static_cast(NULL); - for (iter = leaf.cbeginValueOn(); iter; ++iter) { - leaf.getIndices(iter.pos(), begin, end); - filterVoxel(iter.getCoord(), begin, end); - } - } - - void filterVoxel(const Coord&, const IndexT* begin, const IndexT* end) - { - Vec3d xyz; - PointType vec; - - for (; begin < end; ++begin) { - mPoints.getPos(*begin, vec); - - // world to index cell centered, similar the PointPartitioner tool. - xyz = mMap.applyInverseMap(vec); - xyz[0] = math::Round(xyz[0]); - xyz[1] = math::Round(xyz[1]); - xyz[2] = math::Round(xyz[2]); - - if (mRegion.isInside(xyz)) { - mIndices.push_back(*begin); - } - } - } - -private: - RangeDeque& mRanges; - IndexDeque& mIndices; - const BBoxd mRegion; - const PointArray& mPoints; - const math::MapBase& mMap; -}; - - -template -struct RadialRangeFilter -{ - typedef typename PointArray::value_type PointType; - typedef typename PointType::ValueType PointElementType; - typedef std::pair Range; - typedef std::deque RangeDeque; - typedef std::deque IndexDeque; - - RadialRangeFilter(RangeDeque& ranges, IndexDeque& indices, const Vec3d& xyz, double radius, - const PointArray& points, const math::Transform& xform, - const double leafNodeDim, const bool subvoxelAccuracy) - : mRanges(ranges) - , mIndices(indices) - , mCenter(xyz) - , mWSCenter(xform.indexToWorld(xyz)) - , mVoxelDist1(0.0) - , mVoxelDist2(0.0) - , mLeafNodeDist1(0.0) - , mLeafNodeDist2(0.0) - , mWSRadiusSqr(radius * xform.voxelSize()[0]) - , mPoints(points) - , mSubvoxelAccuracy(subvoxelAccuracy) - { - const PointElementType voxelRadius = std::sqrt(3.0) * 0.5; - mVoxelDist1 = voxelRadius + radius; - mVoxelDist1 *= mVoxelDist1; - - if (radius > voxelRadius) { - mVoxelDist2 = radius - voxelRadius; - mVoxelDist2 *= mVoxelDist2; - } - - const PointElementType leafNodeRadius = leafNodeDim * std::sqrt(3.0) * 0.5; - mLeafNodeDist1 = leafNodeRadius + radius; - mLeafNodeDist1 *= mLeafNodeDist1; - - if (radius > leafNodeRadius) { - mLeafNodeDist2 = radius - leafNodeRadius; - mLeafNodeDist2 *= mLeafNodeDist2; - } - - mWSRadiusSqr *= mWSRadiusSqr; - } - - template - void filterLeafNode(const LeafNodeType& leaf) - { - { - const Coord& ijk = leaf.origin(); - PointType vec; - vec[0] = PointElementType(ijk[0]); - vec[1] = PointElementType(ijk[1]); - vec[2] = PointElementType(ijk[2]); - vec += PointElementType(LeafNodeType::DIM - 1) * 0.5; - vec -= mCenter; - - const PointElementType dist = vec.lengthSqr(); - if (dist > mLeafNodeDist1) return; - - if (mLeafNodeDist2 > 0.0 && dist < mLeafNodeDist2) { - const IndexT* begin = &leaf.indices().front(); - mRanges.push_back(Range(begin, begin + leaf.indices().size())); - return; - } - } - - typename LeafNodeType::ValueOnCIter iter; - const IndexT *begin = static_cast(NULL), *end = static_cast(NULL); - for (iter = leaf.cbeginValueOn(); iter; ++iter) { - leaf.getIndices(iter.pos(), begin, end); - filterVoxel(iter.getCoord(), begin, end); - } - } - - void filterVoxel(const Coord& ijk, const IndexT* begin, const IndexT* end) - { - PointType vec; - - { - vec[0] = mCenter[0] - PointElementType(ijk[0]); - vec[1] = mCenter[1] - PointElementType(ijk[1]); - vec[2] = mCenter[2] - PointElementType(ijk[2]); - - const PointElementType dist = vec.lengthSqr(); - if (dist > mVoxelDist1) return; - - if (!mSubvoxelAccuracy || (mVoxelDist2 > 0.0 && dist < mVoxelDist2)) { - if (!mRanges.empty() && mRanges.back().second == begin) { - mRanges.back().second = end; - } else { - mRanges.push_back(Range(begin, end)); - } - return; - } - } - - - while (begin < end) { - mPoints.getPos(*begin, vec); - vec = mWSCenter - vec; - - if (vec.lengthSqr() < mWSRadiusSqr) { - mIndices.push_back(*begin); - } - ++begin; - } - } - -private: - RangeDeque& mRanges; - IndexDeque& mIndices; - const PointType mCenter, mWSCenter; - PointElementType mVoxelDist1, mVoxelDist2, mLeafNodeDist1, mLeafNodeDist2, mWSRadiusSqr; - const PointArray& mPoints; - const bool mSubvoxelAccuracy; -}; // struct RadialRangeFilter - - -//////////////////////////////////////// - - -template -inline void -filteredPointIndexSearchVoxels(RangeFilterType& filter, - const LeafNodeType& leaf, const Coord& min, const Coord& max) -{ - typedef typename LeafNodeType::ValueType PointIndexT; - Index xPos(0), yPos(0), pos(0); - Coord ijk(0); - - const PointIndexT* dataPtr = &leaf.indices().front(); - PointIndexT beginOffset, endOffset; - - for (ijk[0] = min[0]; ijk[0] <= max[0]; ++ijk[0]) { - xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM); - for (ijk[1] = min[1]; ijk[1] <= max[1]; ++ijk[1]) { - yPos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM); - for (ijk[2] = min[2]; ijk[2] <= max[2]; ++ijk[2]) { - pos = yPos + (ijk[2] & (LeafNodeType::DIM - 1u)); - - beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1)); - endOffset = leaf.getValue(pos); - - if (endOffset > beginOffset) { - filter.filterVoxel(ijk, dataPtr + beginOffset, dataPtr + endOffset); - } - } - } - } -} - - -template -inline void -filteredPointIndexSearch(RangeFilterType& filter, ConstAccessor& acc, const CoordBBox& bbox) -{ - typedef typename ConstAccessor::TreeType::LeafNodeType LeafNodeType; - Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0); - const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1); - const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1); - - for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) { - for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) { - for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) { - - if (const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) { - ijkMax = ijk; - ijkMax.offset(LeafNodeType::DIM - 1); - - // intersect leaf bbox with search region. - ijkA = Coord::maxComponent(bbox.min(), ijk); - ijkB = Coord::minComponent(bbox.max(), ijkMax); - - if (ijkA != ijk || ijkB != ijkMax) { - filteredPointIndexSearchVoxels(filter, *leaf, ijkA, ijkB); - } else { // leaf bbox is inside the search region - filter.filterLeafNode(*leaf); - } - } - } - } - } -} - - -//////////////////////////////////////// - - -template -inline void -pointIndexSearchVoxels(RangeDeque& rangeList, - const LeafNodeType& leaf, const Coord& min, const Coord& max) -{ - typedef typename LeafNodeType::ValueType PointIndexT; - typedef typename RangeDeque::value_type Range; - - Index xPos(0), pos(0), zStride = Index(max[2] - min[2]); - const PointIndexT* dataPtr = &leaf.indices().front(); - PointIndexT beginOffset(0), endOffset(0), - previousOffset = PointIndexT(leaf.indices().size() + size_t(1)); - Coord ijk(0); - - for (ijk[0] = min[0]; ijk[0] <= max[0]; ++ijk[0]) { - xPos = (ijk[0] & (LeafNodeType::DIM - 1u)) << (2 * LeafNodeType::LOG2DIM); - - for (ijk[1] = min[1]; ijk[1] <= max[1]; ++ijk[1]) { - pos = xPos + ((ijk[1] & (LeafNodeType::DIM - 1u)) << LeafNodeType::LOG2DIM); - pos += (min[2] & (LeafNodeType::DIM - 1u)); - - beginOffset = (pos == 0 ? PointIndexT(0) : leaf.getValue(pos - 1)); - endOffset = leaf.getValue(pos+zStride); - - if (endOffset > beginOffset) { - - if (beginOffset == previousOffset) { - rangeList.back().second = dataPtr + endOffset; - } else { - rangeList.push_back(Range(dataPtr + beginOffset, dataPtr + endOffset)); - } - - previousOffset = endOffset; - } - } - } -} - - -template -inline void -pointIndexSearch(RangeDeque& rangeList, ConstAccessor& acc, const CoordBBox& bbox) -{ - typedef typename ConstAccessor::TreeType::LeafNodeType LeafNodeType; - typedef typename LeafNodeType::ValueType PointIndexT; - typedef typename RangeDeque::value_type Range; - - Coord ijk(0), ijkMax(0), ijkA(0), ijkB(0); - const Coord leafMin = bbox.min() & ~(LeafNodeType::DIM - 1); - const Coord leafMax = bbox.max() & ~(LeafNodeType::DIM - 1); - - for (ijk[0] = leafMin[0]; ijk[0] <= leafMax[0]; ijk[0] += LeafNodeType::DIM) { - for (ijk[1] = leafMin[1]; ijk[1] <= leafMax[1]; ijk[1] += LeafNodeType::DIM) { - for (ijk[2] = leafMin[2]; ijk[2] <= leafMax[2]; ijk[2] += LeafNodeType::DIM) { - - if (const LeafNodeType* leaf = acc.probeConstLeaf(ijk)) { - ijkMax = ijk; - ijkMax.offset(LeafNodeType::DIM - 1); - - // intersect leaf bbox with search region. - ijkA = Coord::maxComponent(bbox.min(), ijk); - ijkB = Coord::minComponent(bbox.max(), ijkMax); - - if (ijkA != ijk || ijkB != ijkMax) { - pointIndexSearchVoxels(rangeList, *leaf, ijkA, ijkB); - } else { - // leaf bbox is inside the search region, add all indices. - const PointIndexT* begin = &leaf->indices().front(); - rangeList.push_back(Range(begin, (begin + leaf->indices().size()))); - } - } - } - } - } -} - - -} // namespace point_index_grid_internal - - -// PointIndexIterator implementation - -template -inline -PointIndexIterator::PointIndexIterator() - : mRange(static_cast(NULL), static_cast(NULL)) - , mRangeList() - , mIter(mRangeList.begin()) - , mIndexArray() - , mIndexArraySize(0) -{ -} - - -template -inline -PointIndexIterator::PointIndexIterator(const PointIndexIterator& rhs) - : mRange(rhs.mRange) - , mRangeList(rhs.mRangeList) - , mIter(mRangeList.begin()) - , mIndexArray() - , mIndexArraySize(rhs.mIndexArraySize) -{ - if (rhs.mIndexArray) { - mIndexArray.reset(new ValueType[mIndexArraySize]); - memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize * sizeof(ValueType)); - } -} - - -template -inline PointIndexIterator& -PointIndexIterator::operator=(const PointIndexIterator& rhs) -{ - if (&rhs != this) { - mRange = rhs.mRange; - mRangeList = rhs.mRangeList; - mIter = mRangeList.begin(); - mIndexArray.reset(); - mIndexArraySize = rhs.mIndexArraySize; - - if (rhs.mIndexArray) { - mIndexArray.reset(new ValueType[mIndexArraySize]); - memcpy(mIndexArray.get(), rhs.mIndexArray.get(), mIndexArraySize * sizeof(ValueType)); - } - } - return *this; -} - - -template -inline -PointIndexIterator::PointIndexIterator(const Coord& ijk, ConstAccessor& acc) - : mRange(static_cast(NULL), static_cast(NULL)) - , mRangeList() - , mIter(mRangeList.begin()) - , mIndexArray() - , mIndexArraySize(0) -{ - const LeafNodeType* leaf = acc.probeConstLeaf(ijk); - if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) { - mRangeList.push_back(mRange); - mIter = mRangeList.begin(); - } -} - - -template -inline -PointIndexIterator::PointIndexIterator(const CoordBBox& bbox, ConstAccessor& acc) - : mRange(static_cast(NULL), static_cast(NULL)) - , mRangeList() - , mIter(mRangeList.begin()) - , mIndexArray() - , mIndexArraySize(0) -{ - point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox); - - if (!mRangeList.empty()) { - mIter = mRangeList.begin(); - mRange = mRangeList.front(); - } -} - - -template -inline void -PointIndexIterator::reset() -{ - mIter = mRangeList.begin(); - if (!mRangeList.empty()) { - mRange = mRangeList.front(); - } else if (mIndexArray) { - mRange.first = mIndexArray.get(); - mRange.second = mRange.first + mIndexArraySize; - } else { - mRange.first = static_cast(NULL); - mRange.second = static_cast(NULL); - } -} - - -template -inline void -PointIndexIterator::increment() -{ - ++mRange.first; - if (mRange.first >= mRange.second && mIter != mRangeList.end()) { - ++mIter; - if (mIter != mRangeList.end()) { - mRange = *mIter; - } else if (mIndexArray) { - mRange.first = mIndexArray.get(); - mRange.second = mRange.first + mIndexArraySize; - } - } -} - - -template -inline bool -PointIndexIterator::next() -{ - if (!this->test()) return false; - this->increment(); - return this->test(); -} - - -template -inline size_t -PointIndexIterator::size() const -{ - size_t count = 0; - typename RangeDeque::const_iterator it = mRangeList.begin(); - - for ( ; it != mRangeList.end(); ++it) { - count += it->second - it->first; - } - - return count + mIndexArraySize; -} - - -template -inline void -PointIndexIterator::clear() -{ - mRange.first = static_cast(NULL); - mRange.second = static_cast(NULL); - mRangeList.clear(); - mIter = mRangeList.end(); - mIndexArray.reset(); - mIndexArraySize = 0; -} - - -template -inline void -PointIndexIterator::searchAndUpdate(const Coord& ijk, ConstAccessor& acc) -{ - this->clear(); - const LeafNodeType* leaf = acc.probeConstLeaf(ijk); - if (leaf && leaf->getIndices(ijk, mRange.first, mRange.second)) { - mRangeList.push_back(mRange); - mIter = mRangeList.begin(); - } -} - - -template -inline void -PointIndexIterator::searchAndUpdate(const CoordBBox& bbox, ConstAccessor& acc) -{ - this->clear(); - point_index_grid_internal::pointIndexSearch(mRangeList, acc, bbox); - - if (!mRangeList.empty()) { - mIter = mRangeList.begin(); - mRange = mRangeList.front(); - } -} - - -template -template -inline void -PointIndexIterator::searchAndUpdate(const BBoxd& bbox, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform) -{ - this->clear(); - - std::vector searchRegions; - CoordBBox region(Coord::round(bbox.min()), Coord::round(bbox.max())); - - const Coord dim = region.dim(); - const int minExtent = std::min(dim[0], std::min(dim[1], dim[2])); - - if (minExtent > 2) { - // collect indices that don't need to be tested - CoordBBox ibox = region; - ibox.expand(-1); - - point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox); - - // define regions for the filtered search - ibox.expand(1); - point_index_grid_internal::constructExclusiveRegions(searchRegions, region, ibox); - } else { - searchRegions.push_back(region); - } - - // filtered search - std::deque filteredIndices; - point_index_grid_internal::BBoxFilter - filter(mRangeList, filteredIndices, bbox, points, xform); - - for (size_t n = 0, N = searchRegions.size(); n < N; ++n) { - point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]); - } - - point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize); - - this->reset(); -} - - -template -template -inline void -PointIndexIterator::searchAndUpdate(const Vec3d& center, double radius, - ConstAccessor& acc, const PointArray& points, const math::Transform& xform, - bool subvoxelAccuracy) -{ - this->clear(); - std::vector searchRegions; - - // bounding box - CoordBBox bbox( - Coord::round(Vec3d(center[0] - radius, center[1] - radius, center[2] - radius)), - Coord::round(Vec3d(center[0] + radius, center[1] + radius, center[2] + radius))); - bbox.expand(1); - - const double iRadius = radius * double(1.0 / std::sqrt(3.0)); - if (iRadius > 2.0) { - // inscribed box - CoordBBox ibox( - Coord::round(Vec3d(center[0] - iRadius, center[1] - iRadius, center[2] - iRadius)), - Coord::round(Vec3d(center[0] + iRadius, center[1] + iRadius, center[2] + iRadius))); - ibox.expand(-1); - - // collect indices that don't need to be tested - point_index_grid_internal::pointIndexSearch(mRangeList, acc, ibox); - - ibox.expand(1); - point_index_grid_internal::constructExclusiveRegions(searchRegions, bbox, ibox); - } else { - searchRegions.push_back(bbox); - } - - // filtered search - std::deque filteredIndices; - const double leafNodeDim = double(TreeType::LeafNodeType::DIM); - - typedef point_index_grid_internal::RadialRangeFilter FilterT; - - FilterT filter(mRangeList, filteredIndices, - center, radius, points, xform, leafNodeDim, subvoxelAccuracy); - - for (size_t n = 0, N = searchRegions.size(); n < N; ++n) { - point_index_grid_internal::filteredPointIndexSearch(filter, acc, searchRegions[n]); - } - - point_index_grid_internal::dequeToArray(filteredIndices, mIndexArray, mIndexArraySize); - - this->reset(); -} - - -template -template -inline void -PointIndexIterator::worldSpaceSearchAndUpdate(const BBoxd& bbox, ConstAccessor& acc, - const PointArray& points, const math::Transform& xform) -{ - this->searchAndUpdate( - BBoxd(xform.worldToIndex(bbox.min()), xform.worldToIndex(bbox.max())), acc, points, xform); -} - - -template -template -inline void -PointIndexIterator::worldSpaceSearchAndUpdate(const Vec3d& center, double radius, - ConstAccessor& acc, const PointArray& points, const math::Transform& xform, - bool subvoxelAccuracy) -{ - this->searchAndUpdate(xform.worldToIndex(center), - (radius / xform.voxelSize()[0]), acc, points, xform, subvoxelAccuracy); -} - - -//////////////////////////////////////// - -// PointIndexFilter implementation - -template -inline -PointIndexFilter::PointIndexFilter( - const PointArray& points, const TreeType& tree, const math::Transform& xform) - : mPoints(&points), mAcc(tree), mXform(xform), mInvVoxelSize(1.0/xform.voxelSize()[0]) -{ -} - - -template -inline -PointIndexFilter::PointIndexFilter(const PointIndexFilter& rhs) - : mPoints(rhs.mPoints) - , mAcc(rhs.mAcc.tree()) - , mXform(rhs.mXform) - , mInvVoxelSize(rhs.mInvVoxelSize) -{ -} - - -template -template -inline void -PointIndexFilter::searchAndApply( - const PointType& center, PointElementType radius, FilterType& op) -{ - if (radius * mInvVoxelSize < PointElementType(8.0)) { - mIter.searchAndUpdate(openvdb::CoordBBox( - mXform.worldToIndexCellCentered(center - radius), - mXform.worldToIndexCellCentered(center + radius)), mAcc); - } else { - mIter.worldSpaceSearchAndUpdate( - center, radius, mAcc, *mPoints, mXform, /*subvoxelAccuracy=*/false); - } - - const PointElementType radiusSqr = radius * radius; - PointElementType distSqr = 0.0; - PointType pos; - for (; mIter; ++mIter) { - mPoints->getPos(*mIter, pos); - pos -= center; - distSqr = pos.lengthSqr(); - - if (distSqr < radiusSqr) { - op(distSqr, *mIter); - } - } -} - - -//////////////////////////////////////// - - -template -inline typename GridT::Ptr -createPointIndexGrid(const PointArrayT& points, const math::Transform& xform) -{ - typename GridT::Ptr grid = GridT::create(typename GridT::ValueType(0)); - grid->setTransform(xform.copy()); - - if (points.size() > 0) { - point_index_grid_internal::constructPointTree( - grid->tree(), grid->transform(), points); - } - - return grid; -} - - -template -inline bool -isValidPartition(const PointArrayT& points, const GridT& grid) -{ - tree::LeafManager leafs(grid.tree()); - - size_t pointCount = 0; - for (size_t n = 0, N = leafs.leafCount(); n < N; ++n) { - pointCount += leafs.leaf(n).indices().size(); - } - - if (points.size() != pointCount) { - return false; - } - - tbb::atomic changed; - changed = false; - - point_index_grid_internal::ValidPartitioningOp - op(changed, points, grid.transform()); - - leafs.foreach(op); - - return !bool(changed); -} - - -template -inline typename GridT::ConstPtr -getValidPointIndexGrid(const PointArrayT& points, const typename GridT::ConstPtr& grid) -{ - if (isValidPartition(points, *grid)) { - return grid; - } - - return createPointIndexGrid(points, grid->transform()); -} - - -template -inline typename GridT::Ptr -getValidPointIndexGrid(const PointArrayT& points, const typename GridT::Ptr& grid) -{ - if (isValidPartition(points, *grid)) { - return grid; - } - - return createPointIndexGrid(points, grid->transform()); -} - - -//////////////////////////////////////// - - -template -struct PointIndexLeafNode : public tree::LeafNode -{ - typedef PointIndexLeafNode LeafNodeType; - typedef boost::shared_ptr Ptr; - - typedef T ValueType; - typedef std::vector IndexArray; - - - IndexArray& indices() { return mIndices; } - const IndexArray& indices() const { return mIndices; } - - bool getIndices(const Coord& ijk, const ValueType*& begin, const ValueType*& end) const; - bool getIndices(Index offset, const ValueType*& begin, const ValueType*& end) const; - - void setOffsetOn(Index offset, const ValueType& val); - void setOffsetOnly(Index offset, const ValueType& val); - - bool isEmpty(const CoordBBox& bbox) const; - -private: - IndexArray mIndices; - - //////////////////////////////////////// - - // The following methods had to be copied from the LeafNode class - // to make the derived PointIndexLeafNode class compatible with the tree structure. - -public: - typedef tree::LeafNode BaseLeaf; - typedef util::NodeMask NodeMaskType; - - using BaseLeaf::LOG2DIM; - using BaseLeaf::TOTAL; - using BaseLeaf::DIM; - using BaseLeaf::NUM_VALUES; - using BaseLeaf::NUM_VOXELS; - using BaseLeaf::SIZE; - using BaseLeaf::LEVEL; - - /// Default constructor - PointIndexLeafNode() : BaseLeaf(), mIndices() {} - - explicit - PointIndexLeafNode(const Coord& coords, const T& value = zeroVal(), bool active = false) - : BaseLeaf(coords, value, active) - , mIndices() - { - } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - PointIndexLeafNode(PartialCreate, const Coord& coords, - const T& value = zeroVal(), bool active = false) - : BaseLeaf(PartialCreate(), coords, value, active) - , mIndices() - { - } -#endif - - /// Deep copy constructor - PointIndexLeafNode(const PointIndexLeafNode& rhs) : BaseLeaf(rhs), mIndices(rhs.mIndices) {} - - /// @brief Return @c true if the given node (which may have a different @c ValueType - /// than this node) has the same active value topology as this node. - template - bool hasSameTopology(const PointIndexLeafNode* other) const { - return BaseLeaf::hasSameTopology(other); - } - - /// Check for buffer, state and origin equivalence. - bool operator==(const PointIndexLeafNode& other) const { return BaseLeaf::operator==(other); } - - bool operator!=(const PointIndexLeafNode& other) const { return !(other == *this); } - - template void merge(const PointIndexLeafNode& rhs) { - BaseLeaf::merge(rhs); - } - template void merge(const ValueType& tileValue, bool tileActive) { - BaseLeaf::template merge(tileValue, tileActive); - } - - template - void merge(const PointIndexLeafNode& other, - const ValueType& /*bg*/, const ValueType& /*otherBG*/) - { - BaseLeaf::template merge(other); - } - - void addLeaf(PointIndexLeafNode*) {} - template - void addLeafAndCache(PointIndexLeafNode*, AccessorT&) {} - - //@{ - /// @brief Return a pointer to this node. - PointIndexLeafNode* touchLeaf(const Coord&) { return this; } - template - PointIndexLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; } - - template - NodeT* probeNodeAndCache(const Coord&, AccessorT&) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - PointIndexLeafNode* probeLeaf(const Coord&) { return this; } - template - PointIndexLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; } - //@} - - //@{ - /// @brief Return a @const pointer to this node. - const PointIndexLeafNode* probeConstLeaf(const Coord&) const { return this; } - template - const PointIndexLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const {return this;} - template - const PointIndexLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; } - const PointIndexLeafNode* probeLeaf(const Coord&) const { return this; } - template - const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - //@} - - - // I/O methods - - void readBuffers(std::istream& is, bool fromHalf = false); - void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false); - void writeBuffers(std::ostream& os, bool toHalf = false) const; - - - Index64 memUsage() const; - - - //////////////////////////////////////// - - // Disable all write methods to avoid unintentional changes - // to the point-array offsets. - - void assertNonmodifiable() { - assert(false && "Cannot modify voxel values in a PointIndexTree."); - } - - void setActiveState(const Coord&, bool) { assertNonmodifiable(); } - void setActiveState(Index, bool) { assertNonmodifiable(); } - - void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); } - void setValueOnly(Index, const ValueType&) { assertNonmodifiable(); } - - void setValueOff(const Coord&) { assertNonmodifiable(); } - void setValueOff(Index) { assertNonmodifiable(); } - - void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); } - void setValueOff(Index, const ValueType&) { assertNonmodifiable(); } - - void setValueOn(const Coord&) { assertNonmodifiable(); } - void setValueOn(Index) { assertNonmodifiable(); } - - void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); } - void setValueOn(Index, const ValueType&) { assertNonmodifiable(); } - - void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); } - - void setValuesOn() { assertNonmodifiable(); } - void setValuesOff() { assertNonmodifiable(); } - - template - void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); } - - template - void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); } - - template - void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); } - - void clip(const CoordBBox&, const ValueType&) { assertNonmodifiable(); } - - void fill(const CoordBBox&, const ValueType&, bool) { assertNonmodifiable(); } - void fill(const ValueType&) {} - void fill(const ValueType&, bool) { assertNonmodifiable(); } - - template - void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();} - - template - void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) { - assertNonmodifiable(); - } - - template - void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); } - - template - void setActiveStateAndCache(const Coord&, bool, AccessorT&) { assertNonmodifiable(); } - - void resetBackground(const ValueType&, const ValueType&) { assertNonmodifiable(); } - - void signedFloodFill(const ValueType&) { assertNonmodifiable(); } - void signedFloodFill(const ValueType&, const ValueType&) { assertNonmodifiable(); } - - void negate() { assertNonmodifiable(); } - -protected: - typedef typename BaseLeaf::ValueOn ValueOn; - typedef typename BaseLeaf::ValueOff ValueOff; - typedef typename BaseLeaf::ValueAll ValueAll; - typedef typename BaseLeaf::ChildOn ChildOn; - typedef typename BaseLeaf::ChildOff ChildOff; - typedef typename BaseLeaf::ChildAll ChildAll; - - typedef typename NodeMaskType::OnIterator MaskOnIterator; - typedef typename NodeMaskType::OffIterator MaskOffIterator; - typedef typename NodeMaskType::DenseIterator MaskDenseIterator; - - // During topology-only construction, access is needed - // to protected/private members of other template instances. - template friend struct PointIndexLeafNode; - - friend class tree::IteratorBase; - friend class tree::IteratorBase; - friend class tree::IteratorBase; - -public: - - - typedef typename BaseLeaf::template ValueIter< - MaskOnIterator, PointIndexLeafNode, const ValueType, ValueOn> ValueOnIter; - typedef typename BaseLeaf::template ValueIter< - MaskOnIterator, const PointIndexLeafNode, const ValueType, ValueOn> ValueOnCIter; - typedef typename BaseLeaf::template ValueIter< - MaskOffIterator, PointIndexLeafNode, const ValueType, ValueOff> ValueOffIter; - typedef typename BaseLeaf::template ValueIter< - MaskOffIterator,const PointIndexLeafNode,const ValueType,ValueOff> ValueOffCIter; - typedef typename BaseLeaf::template ValueIter< - MaskDenseIterator, PointIndexLeafNode, const ValueType, ValueAll> ValueAllIter; - typedef typename BaseLeaf::template ValueIter< - MaskDenseIterator,const PointIndexLeafNode,const ValueType,ValueAll> ValueAllCIter; - typedef typename BaseLeaf::template ChildIter< - MaskOnIterator, PointIndexLeafNode, ChildOn> ChildOnIter; - typedef typename BaseLeaf::template ChildIter< - MaskOnIterator, const PointIndexLeafNode, ChildOn> ChildOnCIter; - typedef typename BaseLeaf::template ChildIter< - MaskOffIterator, PointIndexLeafNode, ChildOff> ChildOffIter; - typedef typename BaseLeaf::template ChildIter< - MaskOffIterator, const PointIndexLeafNode, ChildOff> ChildOffCIter; - typedef typename BaseLeaf::template DenseIter< - PointIndexLeafNode, ValueType, ChildAll> ChildAllIter; - typedef typename BaseLeaf::template DenseIter< - const PointIndexLeafNode, const ValueType, ChildAll> ChildAllCIter; - -#define VMASK_ this->getValueMask() - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); } - ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); } - ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); } - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); } - ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); } - ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); } - ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); } - ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); } - - ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); } - ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); } - ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); } - ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); } - ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); } - ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); } - ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); } - ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); } - ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); } - - ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); } - ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); } - ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); } - ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); } - ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); } - ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); } - ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); } - ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); } - ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); } - - ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); } - ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); } - ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); } - ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); } - ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); } - ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); } - ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); } - ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); } - ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); } -#undef VMASK_ -}; // struct PointIndexLeafNode - - -template -inline bool -PointIndexLeafNode::getIndices(const Coord& ijk, - const ValueType*& begin, const ValueType*& end) const -{ - return getIndices(LeafNodeType::coordToOffset(ijk), begin, end); -} - - -template -inline bool -PointIndexLeafNode::getIndices(Index offset, - const ValueType*& begin, const ValueType*& end) const -{ - if (this->isValueMaskOn(offset)) { - const ValueType* dataPtr = &mIndices.front(); - begin = dataPtr + (offset == 0 ? ValueType(0) : this->buffer()[offset - 1]); - end = dataPtr + this->buffer()[offset]; - return true; - } - return false; -} - - -template -inline void -PointIndexLeafNode::setOffsetOn(Index offset, const ValueType& val) -{ - this->buffer().setValue(offset, val); - this->setValueMaskOn(offset); -} - - -template -inline void -PointIndexLeafNode::setOffsetOnly(Index offset, const ValueType& val) -{ - this->buffer().setValue(offset, val); -} - - -template -inline bool -PointIndexLeafNode::isEmpty(const CoordBBox& bbox) const -{ - Index xPos, pos, zStride = Index(bbox.max()[2] - bbox.min()[2]); - Coord ijk; - - for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) { - xPos = (ijk[0] & (DIM - 1u)) << (2 * LOG2DIM); - - for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) { - pos = xPos + ((ijk[1] & (DIM - 1u)) << LOG2DIM); - pos += (bbox.min()[2] & (DIM - 1u)); - - if (this->buffer()[pos+zStride] > (pos == 0 ? T(0) : this->buffer()[pos - 1])) { - return false; - } - } - } - - return true; -} - - -template -inline void -PointIndexLeafNode::readBuffers(std::istream& is, bool fromHalf) -{ - BaseLeaf::readBuffers(is, fromHalf); - - Index64 numIndices = Index64(0); - is.read(reinterpret_cast(&numIndices), sizeof(Index64)); - - mIndices.resize(size_t(numIndices)); - is.read(reinterpret_cast(mIndices.data()), numIndices * sizeof(T)); -} - - -template -inline void -PointIndexLeafNode::readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf) -{ - // Read and clip voxel values. - BaseLeaf::readBuffers(is, bbox, fromHalf); - - Index64 numIndices = Index64(0); - is.read(reinterpret_cast(&numIndices), sizeof(Index64)); - - const Index64 numBytes = numIndices * sizeof(T); - - if (bbox.hasOverlap(this->getNodeBoundingBox())) { - mIndices.resize(size_t(numIndices)); - is.read(reinterpret_cast(mIndices.data()), numBytes); - - /// @todo If any voxels were deactivated as a result of clipping in the call to - /// BaseLeaf::readBuffers(), the point index list will need to be regenerated. - } else { - // Read and discard voxel values. - boost::scoped_array buf(new char[numBytes]); - is.read(buf.get(), numBytes); - } - - // Reserved for future use - Index64 auxDataBytes = Index64(0); - is.read(reinterpret_cast(&auxDataBytes), sizeof(Index64)); - if (auxDataBytes > 0) { - // For now, read and discard any auxiliary data. - boost::scoped_array auxData(new char[auxDataBytes]); - is.read(auxData.get(), auxDataBytes); - } -} - - -template -inline void -PointIndexLeafNode::writeBuffers(std::ostream& os, bool toHalf) const -{ - BaseLeaf::writeBuffers(os, toHalf); - - Index64 numIndices = Index64(mIndices.size()); - os.write(reinterpret_cast(&numIndices), sizeof(Index64)); - os.write(reinterpret_cast(mIndices.data()), numIndices * sizeof(T)); - - // Reserved for future use - const Index64 auxDataBytes = Index64(0); - os.write(reinterpret_cast(&auxDataBytes), sizeof(Index64)); -} - - -template -inline Index64 -PointIndexLeafNode::memUsage() const -{ - return BaseLeaf::memUsage() + Index64((sizeof(T)*mIndices.capacity()) + sizeof(mIndices)); -} - -} // namespace tools - - -//////////////////////////////////////// - - -namespace tree { - -/// Helper metafunction used to implement LeafNode::SameConfiguration -/// (which, as an inner class, can't be independently specialized) -template -struct SameLeafConfig > -{ - static const bool value = true; -}; - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_POINT_INDEX_GRID_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/PointPartitioner.h b/openvdb_3_0_0_library/tools/PointPartitioner.h deleted file mode 100755 index 2b74983..0000000 --- a/openvdb_3_0_0_library/tools/PointPartitioner.h +++ /dev/null @@ -1,1153 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file PointPartitioner.h -/// -/// @brief Multi-threaded space-partitioning scheme for points. -/// -/// @note This tool is deterministic; partitioning the same point -/// sequence will produce the same result each time. -/// The actual points are never stored in the tool, only -/// offsets into an external array. -/// -/// @author Mihai Alden - -#ifndef OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED - - -#include -#include - -#include -#include -#include // std::swap - -#include -#include // boost::int_t::least -#include //for boost::math::isfinite - -#include -#include -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -//////////////////////////////////////// - - -// Expected interface for the PointArray container: -// -// template -// struct PointList { -// typedef VectorType position_type; -// size_t size() const; -// void getPos(size_t n, VectorType& xyz) const; -// }; - - -/// @brief Partitions points into @c Log2Dim aligned buckets. -/// -/// @note This tool is deterministic; partitioning the same point -/// sequence will produce the same result each time. -/// @c Log2Dim defines the bucket coordinate dimensions, -/// i.e. Log2Dim = 3 corresponds to a bucket that spans -/// a (2^3)^3 = 8^3 voxel region. -template -class PointPartitioner -{ -public: - enum { LOG2DIM = Log2Dim }; - - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - typedef PointIndexT IndexType; - typedef typename boost::int_t<1 + (3 * Log2Dim)>::least VoxelOffsetType; - typedef boost::scoped_array VoxelOffsetArray; - - class IndexIterator; - - ////////// - - PointPartitioner(); - - /// @brief Partitions point indices into @c Log2Dim aligned buckets. - /// - /// @param points list of world space points. - /// @param xform world to index space transform. - /// @param voxelOrder sort point indices by local voxel offsets. - /// @param recordVoxelOffsets construct local voxel offsets - template - void construct(const PointArray& points, const math::Transform& xform, - bool voxelOrder = false, bool recordVoxelOffsets = false); - - - /// @brief Partitions point indices into @c Log2Dim aligned buckets. - /// - /// @param points list of world space points. - /// @param xform world to index space transform. - /// @param voxelOrder sort point indices by local voxel offsets. - /// @param recordVoxelOffsets construct local voxel offsets - template - static Ptr create(const PointArray& points, const math::Transform& xform, - bool voxelOrder = false, bool recordVoxelOffsets = false); - - - /// @brief Returns the number of buckets. - size_t size() const { return mPageCount; } - - /// @brief true if the container size is 0, false otherwise. - bool empty() const { return mPageCount == 0; } - - /// @brief Removes all data and frees up memory. - void clear(); - - /// @brief Exchanges the content of the container by another. - void swap(PointPartitioner&); - - /// @brief Returns the point indices for bucket @a n - IndexIterator indices(size_t n) const; - - /// @brief Returns the coordinate-aligned bounding box for bucket @a n - CoordBBox getBBox(size_t n) const { - return CoordBBox::createCube(mPageCoordinates[n], (1u << Log2Dim)); - } - - /// @brief Returns the origin coordinate for bucket @a n - const Coord& origin(size_t n) const { return mPageCoordinates[n]; } - - /// @brief Returns a list of @c LeafNode voxel offsets for the points. - /// @note The list is optionally constructed. - const VoxelOffsetArray& voxelOffsets() const { return mVoxelOffsets; } - -private: - // Disallow copying - PointPartitioner(const PointPartitioner&); - PointPartitioner& operator=(const PointPartitioner&); - - boost::scoped_array mPointIndices; - VoxelOffsetArray mVoxelOffsets; - - boost::scoped_array mPageOffsets; - boost::scoped_array mPageCoordinates; - IndexType mPageCount; -}; // class PointPartitioner - - -typedef PointPartitioner UInt32PointPartitioner; - - -template -class PointPartitioner::IndexIterator -{ -public: - typedef PointIndexT IndexType; - - IndexIterator(IndexType* begin = NULL, IndexType* end = NULL) - : mBegin(begin), mEnd(end), mItem(begin) {} - - /// @brief Rewind to first item. - void reset() { mItem = mBegin; } - - /// @brief Number of point indices in the iterator range. - size_t size() const { return mEnd - mBegin; } - - /// @brief Returns the item to which this iterator is currently pointing. - IndexType& operator*() { assert(mItem != NULL); return *mItem; } - const IndexType& operator*() const { assert(mItem != NULL); return *mItem; } - - /// @brief Return @c true if this iterator is not yet exhausted. - operator bool() const { return mItem < mEnd; } - bool test() const { return mItem < mEnd; } - - /// @brief Advance to the next item. - IndexIterator& operator++() { assert(this->test()); ++mItem; return *this; } - - /// @brief Advance to the next item. - bool next() { this->operator++(); return this->test(); } - bool increment() { this->next(); return this->test(); } - - /// @brief Equality operators - bool operator==(const IndexIterator& other) const { return mItem == other.mItem; } - bool operator!=(const IndexIterator& other) const { return !this->operator==(other); } - -private: - IndexType * const mBegin, * const mEnd; - IndexType * mItem; -}; // class PointPartitioner::IndexIterator - - -//////////////////////////////////////// - -// Implementation details - - -namespace point_partitioner_internal { - -enum { LEAF_NODE_LIMIT = 1000000000 }; - -//////////////////////////////////////// - - -template -struct ComputeBBoxOp { - typedef typename PointArray::value_type PointType; - typedef typename PointType::value_type ElementType; - - ComputeBBoxOp(const PointArray& points) - : mPoints(&points) - , mMin(std::numeric_limits::max()) - , mMax(-std::numeric_limits::max()) - { - } - - ComputeBBoxOp(const ComputeBBoxOp& other, tbb::split) - : mPoints(other.mPoints) - , mMin(std::numeric_limits::max()) - , mMax(-std::numeric_limits::max()) - { - } - - void operator()(const tbb::blocked_range& range) { - - PointType pos, tmpMin(mMin), tmpMax(mMax); - - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - mPoints->getPos(n, pos); - - if (boost::math::isfinite(pos[0]) && - boost::math::isfinite(pos[1]) && - boost::math::isfinite(pos[2])) { - tmpMin[0] = std::min(tmpMin[0], pos[0]); - tmpMin[1] = std::min(tmpMin[1], pos[1]); - tmpMin[2] = std::min(tmpMin[2], pos[2]); - tmpMax[0] = std::max(tmpMax[0], pos[0]); - tmpMax[1] = std::max(tmpMax[1], pos[1]); - tmpMax[2] = std::max(tmpMax[2], pos[2]); - } - } - - mMin[0] = std::min(tmpMin[0], mMin[0]); - mMin[1] = std::min(tmpMin[1], mMin[1]); - mMin[2] = std::min(tmpMin[2], mMin[2]); - mMax[0] = std::max(tmpMax[0], mMax[0]); - mMax[1] = std::max(tmpMax[1], mMax[1]); - mMax[2] = std::max(tmpMax[2], mMax[2]); - } - - void join(ComputeBBoxOp& other) { - mMin[0] = std::min(mMin[0], other.mMin[0]); - mMin[1] = std::min(mMin[1], other.mMin[1]); - mMin[2] = std::min(mMin[2], other.mMin[2]); - mMax[0] = std::max(mMax[0], other.mMax[0]); - mMax[1] = std::max(mMax[1], other.mMax[1]); - mMax[2] = std::max(mMax[2], other.mMax[2]); - } - - ////////// - - PointArray const * const mPoints; - PointType mMin, mMax; -}; - - -//////////////////////////////////////// - - -template -struct IndexPair { - IndexT first, second; - - bool operator<(const IndexPair& rhs) const { - return first < rhs.first; - } -}; - - -template -struct BucketAndVoxelOffsetOp -{ - typedef typename PointArray::value_type PointType; - typedef boost::scoped_array IndexArray; - typedef boost::scoped_array VoxelOffsetArray; - - BucketAndVoxelOffsetOp( - VoxelOffsetArray& voxelOffsets, IndexArray& bucketOffsets, - const PointArray& points, const math::Transform& m, - const CoordBBox& bbox, int log2dim) - : mVoxelOffsets(voxelOffsets.get()) - , mBucketOffsets(bucketOffsets.get()) - , mPoints(&points) - , mXForm(m) - , mBBox(bbox) - , mDim(bbox.dim()) - , mBlockLog2Dim(log2dim) - { - } - - - void operator()(const tbb::blocked_range& range) const { - PointType pos; - Coord ijk(0, 0, 0), loc(0, 0, 0); - - const int xMin = mBBox.min()[0], yMin = mBBox.min()[1], zMin = mBBox.min()[2]; - const int yzDim = mDim[1] * mDim[2], zDim = mDim[2]; - - const int log2dim = mBlockLog2Dim, log2dim2 = 2 * mBlockLog2Dim, - mask = unsigned(1u << mBlockLog2Dim) - 1u; - - IndexT bucketOffset = 0; - VoxelOffsetT voxelOffset = 0; - - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - - mPoints->getPos(n, pos); - - if (boost::math::isfinite(pos[0]) && - boost::math::isfinite(pos[1]) && - boost::math::isfinite(pos[2])) { - - ijk = mXForm.worldToIndexCellCentered(pos); - - // coord to offset - if (mVoxelOffsets) { - loc[0] = ijk[0] & mask; - loc[1] = ijk[1] & mask; - loc[2] = ijk[2] & mask; - - voxelOffset = VoxelOffsetT((loc[0] << log2dim2) + (loc[1] << log2dim) + loc[2]); - } - - ijk[0] >>= log2dim; - ijk[1] >>= log2dim; - ijk[2] >>= log2dim; - - ijk[0] -= xMin; - ijk[1] -= yMin; - ijk[2] -= zMin; - - bucketOffset = IndexT(ijk[0] * yzDim + ijk[1] * zDim + ijk[2]); - mBucketOffsets[n] = bucketOffset; - - if (mVoxelOffsets) mVoxelOffsets[n] = voxelOffset; - } - } - } - - ////////// - - VoxelOffsetT * const mVoxelOffsets; - IndexT * const mBucketOffsets; - PointArray const * const mPoints; - - const math::Transform mXForm; - const CoordBBox mBBox; - const Coord mDim; - const int mBlockLog2Dim; -}; - - -template -struct ComputeOffsetOp -{ - typedef typename PointArray::value_type PointType; - typedef IndexPair IndexPairT; - typedef boost::scoped_array IndexPairArray; - typedef boost::scoped_array VoxelOffsetArray; - - ComputeOffsetOp( - VoxelOffsetArray& voxelOffsets, IndexPairArray& bucketOffsets, - const PointArray& points, const math::Transform& m, - const CoordBBox& bbox, int log2dim) - : mVoxelOffsets(voxelOffsets.get()) - , mBucketOffsets(bucketOffsets.get()) - , mPoints(&points) - , mXForm(m) - , mBBox(bbox) - , mDim(bbox.dim()) - , mBlockLog2Dim(log2dim) - { - } - - - void operator()(const tbb::blocked_range& range) const { - PointType pos; - Coord ijk(0, 0, 0), loc(0, 0, 0); - - const int xMin = mBBox.min()[0], yMin = mBBox.min()[1], zMin = mBBox.min()[2]; - const int yzDim = mDim[1] * mDim[2], zDim = mDim[2]; - - const int log2dim = mBlockLog2Dim, log2dim2 = 2 * mBlockLog2Dim, - mask = unsigned(1u << mBlockLog2Dim) - 1u; - - IndexT bucketOffset = 0; - VoxelOffsetT voxelOffset = 0; - - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - - mPoints->getPos(n, pos); - - if (boost::math::isfinite(pos[0]) && - boost::math::isfinite(pos[1]) && - boost::math::isfinite(pos[2])) { - ijk = mXForm.worldToIndexCellCentered(pos); - - // coord to offset - if (mVoxelOffsets) { - loc[0] = ijk[0] & mask; - loc[1] = ijk[1] & mask; - loc[2] = ijk[2] & mask; - - voxelOffset = VoxelOffsetT((loc[0] << log2dim2) + (loc[1] << log2dim) + loc[2]); - } - - ijk[0] >>= log2dim; - ijk[1] >>= log2dim; - ijk[2] >>= log2dim; - - ijk[0] -= xMin; - ijk[1] -= yMin; - ijk[2] -= zMin; - - bucketOffset = IndexT(ijk[0] * yzDim + ijk[1] * zDim + ijk[2]); - - IndexPairT& item = mBucketOffsets[n]; - - item.first = bucketOffset; - item.second = IndexT(n); - - if (mVoxelOffsets) mVoxelOffsets[n] = voxelOffset; - } - } - } - - ////////// - - VoxelOffsetT * const mVoxelOffsets; - IndexPairT * const mBucketOffsets; - PointArray const * const mPoints; - - const math::Transform mXForm; - const CoordBBox mBBox; - const Coord mDim; - const int mBlockLog2Dim; -}; - - - -template -struct BucketMapOp -{ - typedef tbb::atomic AtomicIndex; - typedef boost::scoped_array AtomicIndexArray; - typedef boost::scoped_array IndexArray; - - BucketMapOp(IndexArray& bucketIndices, - AtomicIndexArray& bucketMap, const IndexArray& bucketOffsets) - : mBucketIndices(bucketIndices.get()) - , mBucketMap(bucketMap.get()) - , mBucketOffsets(bucketOffsets.get()) - { - } - - void operator()(const tbb::blocked_range& range) const { - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - mBucketIndices[n] = mBucketMap[mBucketOffsets[n]].fetch_and_increment(); - } - } - - IndexT * const mBucketIndices; - AtomicIndex * const mBucketMap; - IndexT const * const mBucketOffsets; -}; - - -template -struct MergeOffsetsOp -{ - typedef tbb::atomic AtomicIndex; - typedef boost::scoped_array AtomicIndexArray; - typedef boost::scoped_array IndexArray; - - MergeOffsetsOp(IndexArray& pointIndices, - const AtomicIndexArray& bucketMap, const IndexArray& bucketOffsets) - : mPointIndices(pointIndices.get()) - , mBucketMap(bucketMap.get()) - , mBucketOffsets(bucketOffsets.get()) - { - } - - void operator()(const tbb::blocked_range& range) const { - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - mPointIndices[n] += mBucketMap[mBucketOffsets[n]]; - } - } - - IndexT * const mPointIndices; - AtomicIndex const * const mBucketMap; - IndexT const * const mBucketOffsets; -}; - - -template -struct BucketOrderOp -{ - typedef boost::scoped_array IndexArray; - - BucketOrderOp(IndexArray& pointIndices, IndexArray& bucketOffsets) - : mPointIndices(pointIndices.get()) - , mBucketOffsets(bucketOffsets.get()) - { - } - - void operator()(const tbb::blocked_range& range) const { - for (IndexT n = static_cast(range.begin()), N = static_cast(range.end()); - n != N; ++n) - { - mBucketOffsets[mPointIndices[n]] = n; - } - } - - IndexT const * const mPointIndices; - IndexT * const mBucketOffsets; -}; - -template -struct PageOrderOp -{ - typedef boost::scoped_array IndexArray; - typedef boost::scoped_array > IndexPairArray; - - PageOrderOp(IndexArray& pointIndices, const IndexPairArray& pairs) - : mPointIndices(pointIndices.get()) - , mPairs(pairs.get()) - { - } - - void operator()(const tbb::blocked_range& range) const { - for (size_t n(range.begin()), N(range.end()); n != N; ++n) { - mPointIndices[n] = mPairs[n].second; - } - } - - IndexT * const mPointIndices; - IndexPair const * const mPairs; -}; - -template -struct PageBreakOp -{ - typedef std::pair Range; - typedef boost::scoped_array IndexArray; - typedef boost::scoped_array > IndexPairArray; - - PageBreakOp(const Range& range, const IndexPairArray& pairs, - IndexArray& segment, IndexT& size) - : mRange(range) - , mPairs(pairs.get()) - , mSegment(&segment) - , mSize(&size) - { - } - - void operator()() const { - - const IndexT start = mRange.first; - const IndexT end = mRange.second; - - std::deque pageBreaks; - - IndexT last = mPairs[start].first; - for (IndexT n = start + 1; n != end; ++n) { - const IndexPair& pair = mPairs[n]; - if (last != pair.first) { - last = pair.first; - pageBreaks.push_back(n); - } - } - - if (!pageBreaks.empty()) { - - IndexArray segment(new IndexT[pageBreaks.size()]); - IndexT* item = segment.get(); - - typename std::deque::iterator it = pageBreaks.begin(); - while (it != pageBreaks.end()) { - *item++ = *it++; - } - - mSegment->swap(segment); - *mSize = static_cast(pageBreaks.size()); - } - } - - Range mRange; - IndexPair const * const mPairs; - IndexArray * const mSegment; - IndexT * const mSize; -}; - - - -template -struct VoxelOrderOp -{ - typedef typename boost::int_t<1 + (3 * Log2Dim)>::least VoxelOffsetT; - typedef boost::scoped_array VoxelOffsetArray; - typedef boost::scoped_array IndexArray; - - VoxelOrderOp(IndexArray& indices, const IndexArray& pages,const VoxelOffsetArray& offsets) - : mIndices(indices.get()) - , mPages(pages.get()) - , mVoxelOffsets(offsets.get()) - { - } - - - void operator()(const tbb::blocked_range& range) const { - - IndexT pointCount = 0; - for (size_t n(range.begin()), N(range.end()); n != N; ++n) { - pointCount = std::max(pointCount, (mPages[n + 1] - mPages[n])); - } - - const IndexT voxelCount = 1 << (3 * Log2Dim); - - // allocate histogram buffers - boost::scoped_array offsets(new VoxelOffsetT[pointCount]); - boost::scoped_array sortedIndices(new IndexT[pointCount]); - boost::scoped_array histogram(new IndexT[voxelCount]); - - for (size_t n(range.begin()), N(range.end()); n != N; ++n) { - - IndexT * const indices = mIndices + mPages[n]; - pointCount = mPages[n + 1] - mPages[n]; - - // local copy of voxel offsets. - for (IndexT i = 0; i < pointCount; ++i) { - offsets[i] = mVoxelOffsets[ indices[i] ]; - } - - // reset histogram - memset(&histogram[0], 0, voxelCount * sizeof(IndexT)); - - // compute histogram - for (IndexT i = 0; i < pointCount; ++i) { - ++histogram[ offsets[i] ]; - } - - IndexT count = 0, startOffset; - for (int i = 0; i < int(voxelCount); ++i) { - if (histogram[i] > 0) { - startOffset = count; - count += histogram[i]; - histogram[i] = startOffset; - } - } - - // sort indices based on voxel offset - for (IndexT i = 0; i < pointCount; ++i) { - sortedIndices[ histogram[ offsets[i] ]++ ] = indices[i]; - } - - memcpy(&indices[0], &sortedIndices[0], sizeof(IndexT) * pointCount); - } - } - - - IndexT * const mIndices; - IndexT const * const mPages; - VoxelOffsetT const * const mVoxelOffsets; -}; - - -template -struct IndexOrderOp -{ - typedef boost::scoped_array IndexArray; - - IndexOrderOp(IndexArray& indices, const IndexArray& pages) - : mIndices(indices.get()) , mPages(pages.get()) { } - - void operator()(const tbb::blocked_range& range) const { - for (size_t n(range.begin()), N(range.end()); n != N; ++n) - std::sort(mIndices + mPages[n], mIndices + mPages[n+1]); - } - - IndexT * const mIndices; - IndexT const * const mPages; -}; - - -template -struct LeafNodeOriginOp -{ - typedef boost::scoped_array IndexArray; - typedef boost::scoped_array CoordArray; - - LeafNodeOriginOp(CoordArray& coordinates, - const IndexArray& indices, const IndexArray& pages, - const PointArray& points, const math::Transform& m, int log2dim) - : mCoordinates(coordinates.get()) - , mIndices(indices.get()) - , mPages(pages.get()) - , mPoints(&points) - , mXForm(m) - , mLog2Dim(log2dim) - { - } - - void operator()(const tbb::blocked_range& range) const { - - const int mask = ~((1 << mLog2Dim) - 1); - Coord ijk; - typename PointArray::value_type pos; - for (size_t n = range.begin(), N = range.end(); n != N; ++n) { - - mPoints->getPos(mIndices[mPages[n]], pos); - - if (boost::math::isfinite(pos[0]) && - boost::math::isfinite(pos[1]) && - boost::math::isfinite(pos[2])) { - - ijk = mXForm.worldToIndexCellCentered(pos); - - ijk[0] &= mask; - ijk[1] &= mask; - ijk[2] &= mask; - - mCoordinates[n] = ijk; - } - } - } - - ////////// - - Coord * const mCoordinates; - IndexT const * const mIndices; - IndexT const * const mPages; - PointArray const * const mPoints; - - const math::Transform mXForm; - const int mLog2Dim; -}; - - -//////////////////////////////////////// - - -// Tests whether the given bbox volume can be computed without -// overflowing the given IntType -template -inline bool -isVolumeCalculationOverflowSafe(const CoordBBox& bbox) -{ - const uint64_t xdim = uint64_t(bbox.max()[0] - bbox.min()[0]); - const uint64_t ydim = uint64_t(bbox.max()[1] - bbox.min()[1]); - const uint64_t zdim = uint64_t(bbox.max()[2] - bbox.min()[2]); - - uint64_t product = xdim * ydim; - if (product > std::numeric_limits::max()) return false; - - product *= zdim; - if (product > std::numeric_limits::max()) return false; - return true; -} - - -//////////////////////////////////////// - -template -inline CoordBBox -computeLeafBounds(const PointArray& points, const math::Transform& m, unsigned log2dim) -{ - ComputeBBoxOp bboxOp(points); - tbb::parallel_reduce(tbb::blocked_range(0, points.size()), bboxOp); - - CoordBBox box; - - if (m.isLinear()) { - box.min() = m.worldToIndexCellCentered(bboxOp.mMin); - box.max() = m.worldToIndexCellCentered(bboxOp.mMax); - } else { - Vec3d minIS, maxIS; - math::calculateBounds(m, bboxOp.mMin, bboxOp.mMax, minIS, maxIS); - box.min() = math::Coord::round(minIS); - box.max() = math::Coord::round(maxIS); - } - - box.min() >>= log2dim; - box.max() >>= log2dim; - return box; -} - - -template -inline void partition( - const PointArray& points, - const math::Transform& xform, - const CoordBBox& bbox, - boost::scoped_array& pointIndices, - boost::scoped_array& pageOffsets, - IndexT& pageCount, - boost::scoped_array& voxelOffsets, - bool recordVoxelOffsets) -{ - typedef tbb::atomic AtomicIndexT; - typedef boost::scoped_array AtomicIndexArray; - typedef boost::scoped_array IndexArray; - - ////////// - - // Compute voxel and bucket offsets - - const size_t pointCount = points.size(); - const tbb::blocked_range pointRange(0, pointCount); - - if (recordVoxelOffsets) { - voxelOffsets.reset(new VoxelOffsetT[pointCount]); - } else { - voxelOffsets.reset(); - } - - IndexArray bucketOffsets(new IndexT[pointCount]); - - tbb::parallel_for(pointRange, BucketAndVoxelOffsetOp< - PointArray, IndexT, VoxelOffsetT>( - voxelOffsets, bucketOffsets, points, xform, bbox, int(Log2Dim))); - - // Compute bucket indices and bucket point counts - - const Index64 volume = bbox.volume(); - - pointIndices.reset(new IndexT[pointCount]); - AtomicIndexArray bucketMap(new AtomicIndexT[volume]); - memset(&bucketMap[0], 0, sizeof(AtomicIndexT) * volume); - - tbb::parallel_for(pointRange, - BucketMapOp(pointIndices, bucketMap, bucketOffsets)); - - // Initialize page offsets and update bucket map with global start index. - { - pageCount = 0; - for (size_t n(0), N(volume); n < N; ++n) { - pageCount += static_cast(bucketMap[n] != 0); - } - - pageOffsets.reset(new IndexT[pageCount + 1]); - IndexT count = 0; - for (size_t n = 0, idx = 0; n < volume; ++n) { - if (bucketMap[n] != 0) { - pageOffsets[idx] = count; - count += bucketMap[n]; - bucketMap[n] = pageOffsets[idx]; - ++idx; - } - } - - pageOffsets[pageCount] = count; - } - - - // Merge bucket offsets with bucket indices - tbb::parallel_for(pointRange, - MergeOffsetsOp(pointIndices, bucketMap, bucketOffsets)); - - bucketMap.reset(); - - // Bucket order indices - tbb::parallel_for(pointRange, BucketOrderOp(pointIndices, bucketOffsets)); - - pointIndices.swap(bucketOffsets); - bucketOffsets.reset(); -} - - -template -inline void sortPartition( - const PointArray& points, - const math::Transform& xform, - const CoordBBox& bbox, - boost::scoped_array& pointIndices, - boost::scoped_array& pageOffsets, - IndexT& pageCount, - boost::scoped_array& voxelOffsets, - bool recordVoxelOffsets) -{ - typedef boost::scoped_array IndexArray; - typedef IndexPair IndexPairT; - typedef boost::scoped_array IndexPairArray; - - ////////// - - const size_t pointCount = points.size(); - const tbb::blocked_range pointRange(0, pointCount); - - if (recordVoxelOffsets) { - voxelOffsets.reset(new VoxelOffsetT[pointCount]); - } else { - voxelOffsets.reset(); - } - - IndexPairArray bucketOffsets(new IndexPairT[pointCount]); - tbb::parallel_for(pointRange, ComputeOffsetOp< - PointArray, IndexT, VoxelOffsetT>( - voxelOffsets, bucketOffsets, points, xform, bbox, int(Log2Dim))); - - tbb::parallel_sort(bucketOffsets.get(), bucketOffsets.get() + pointCount); - - { // Compute page offsets - const size_t nthreads = tbb::task_scheduler_init::default_num_threads(); - const size_t ntasks = nthreads > 1 ? 2 * nthreads : 1; - - if (ntasks > 1) { - - IndexArray segmentSizes(new IndexT[ntasks]); - memset(segmentSizes.get(), 0, ntasks * sizeof(IndexT)); - boost::scoped_array segments(new IndexArray[ntasks]); - - const IndexT grainSize = static_cast(pointCount / ntasks); - const IndexT end = static_cast(grainSize * (ntasks - 1)); - - tbb::task_group tasks; - - IndexT idx = 0; - std::pair range; - - // create tasks - range.first = 0; - range.second = grainSize; - tasks.run(PageBreakOp(range, bucketOffsets, segments[idx], segmentSizes[idx])); - ++idx; - - for (IndexT n = grainSize; n < end; n += grainSize) { - range.first = n-1; - range.second = n+grainSize; - tasks.run(PageBreakOp(range, bucketOffsets, segments[idx], segmentSizes[idx])); - ++idx; - } - - range.first = end-1; - range.second = static_cast(pointCount); - tasks.run(PageBreakOp(range, bucketOffsets, segments[idx], segmentSizes[idx])); - - tasks.wait(); - - // collect data - size_t pcount = 1; - for (size_t n = 0; n < ntasks; ++n) { - pcount += segmentSizes[n]; - } - - pageCount = static_cast(pcount); - pageOffsets.reset(new IndexT[pageCount + 1]); - - pcount = 1; - for (size_t n = 0; n < ntasks; ++n) { - const IndexT size = segmentSizes[n]; - if(size != 0) { - memcpy(pageOffsets.get() + pcount, segments[n].get(), size * sizeof(IndexT)); - pcount += size; - } - } - - pageOffsets[0] = 0; - pageOffsets[pageCount] = static_cast(pointCount); - - } else { - - std::deque pageBreaks; - IndexT last = bucketOffsets[0].first; - - for (IndexT n = 1; n != pointCount; ++n) { - if (last != bucketOffsets[n].first) { - last = bucketOffsets[n].first; - pageBreaks.push_back(n); - } - } - - pageCount = static_cast(pageBreaks.size() + 1); - pageOffsets.reset(new IndexT[pageCount + 1]); - - if (!pageBreaks.empty()) { - - IndexT* item = pageOffsets.get() + 1; - - typename std::deque::iterator it = pageBreaks.begin(); - while (it != pageBreaks.end()) { - *item++ = *it++; - } - } - - pageOffsets[0] = 0; - pageOffsets[pageCount] = static_cast(pointCount); - } - } - - pointIndices.reset(new IndexT[pointCount]); - tbb::parallel_for(pointRange, PageOrderOp(pointIndices, bucketOffsets)); -} - -} // namespace point_partitioner_internal - - -//////////////////////////////////////// - - -template -inline PointPartitioner::PointPartitioner() - : mPointIndices(NULL) - , mVoxelOffsets(NULL) - , mPageOffsets(NULL) - , mPageCoordinates(NULL) - , mPageCount(0) -{ -} - - -template -inline void -PointPartitioner::clear() -{ - mPageCount = 0; - mPointIndices.reset(); - mVoxelOffsets.reset(); - mPageOffsets.reset(); - mPageCoordinates.reset(); -} - - -template -inline void -PointPartitioner::swap(PointPartitioner& rhs) -{ - std::swap(mPageCount, rhs.mPageCount); - mPointIndices.swap(rhs.mPointIndices); - mVoxelOffsets.swap(rhs.mVoxelOffsets); - mPageOffsets.swap(rhs.mPageOffsets); - mPageCoordinates.swap(rhs.mPageCoordinates); -} - - -template -inline typename PointPartitioner::IndexIterator -PointPartitioner::indices(size_t n) const -{ - assert(bool(mPointIndices) && bool(mPageCount)); - return IndexIterator( - mPointIndices.get() + mPageOffsets[n], - mPointIndices.get() + mPageOffsets[n + 1]); -} - - -template -template -inline void -PointPartitioner::construct(const PointArray& points, - const math::Transform& xform, bool voxelOrder, bool recordVoxelOffsets) -{ - const CoordBBox bbox = - point_partitioner_internal::computeLeafBounds(points, xform, int(Log2Dim)); - - if(!point_partitioner_internal::isVolumeCalculationOverflowSafe(bbox)) { - // the bbox is computed in leafnode space (the lattice composing of only - // leafnode origins) and should rarely overflow the volume calc. in practice. - OPENVDB_THROW(ArithmeticError, "Detected overflow in bbox volume computation, " - "use uint64 for the PointIndexT type in the PointPartitioner."); - - /// @todo This can be avoided using boost::int_t::least to determine the - /// bucket offset type instead of PointIndexT in the @c sortPartition - /// and @c partition algorithms. - } - - if (bbox.volume() > Index64(point_partitioner_internal::LEAF_NODE_LIMIT)) { - point_partitioner_internal::sortPartition(points, xform, bbox, - mPointIndices, mPageOffsets, mPageCount, mVoxelOffsets, (voxelOrder || recordVoxelOffsets)); - } else { - point_partitioner_internal::partition(points, xform, bbox, - mPointIndices, mPageOffsets, mPageCount, mVoxelOffsets, (voxelOrder || recordVoxelOffsets)); - } - - const tbb::blocked_range pageRange(0, mPageCount); - - tbb::parallel_for(pageRange, - point_partitioner_internal::IndexOrderOp(mPointIndices, mPageOffsets)); - - mPageCoordinates.reset(new Coord[mPageCount]); - - tbb::parallel_for(pageRange, - point_partitioner_internal::LeafNodeOriginOp - (mPageCoordinates, mPointIndices, mPageOffsets, points, xform, Log2Dim)); - - if (mVoxelOffsets && voxelOrder) { - tbb::parallel_for(pageRange, point_partitioner_internal::VoxelOrderOp< - IndexType, Log2Dim>(mPointIndices, mPageOffsets, mVoxelOffsets)); - } - - if (mVoxelOffsets && !recordVoxelOffsets) { - mVoxelOffsets.reset(); - } -} - - -template -template -inline typename PointPartitioner::Ptr -PointPartitioner::create(const PointArray& points, const math::Transform& xform, - bool voxelOrder, bool recordVoxelOffsets) -{ - Ptr ret(new PointPartitioner()); - ret->construct(points, xform, voxelOrder, recordVoxelOffsets); - return ret; -} - - -//////////////////////////////////////// - - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -#endif // OPENVDB_TOOLS_POINT_PARTITIONER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/PointScatter.h b/openvdb_3_0_0_library/tools/PointScatter.h deleted file mode 100755 index d467035..0000000 --- a/openvdb_3_0_0_library/tools/PointScatter.h +++ /dev/null @@ -1,437 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file PointScatter.h -/// -/// @brief We offer three differet algorithms (each in its own class) -/// for scattering of point in active voxels: -/// -/// 1) UniformPointScatter. Has two modes: Either randomly distributes -/// a fixed number of points in the active voxels, or the user can -/// specify a fixed probability of having a points per unit of volume. -/// -/// 2) DenseUniformPointScatter. Randomly distributes points in active -/// voxels using a fixed number of points per voxel. -/// -/// 3) NonIniformPointScatter. Define the local probability of having -/// a point in a voxel as the product of a global density and the -/// value of the voxel itself. - -#ifndef OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// Forward declaration of base class -template -class BasePointScatter; - -/// @brief The two point scatters UniformPointScatter and -/// NonUniformPointScatter depend on the following two classes: -/// -/// The @c PointAccessorType template argument below refers to any class -/// with the following interface: -/// @code -/// class PointAccessor { -/// ... -/// public: -/// void add(const openvdb::Vec3R &pos);// appends point with world positions pos -/// }; -/// @endcode -/// -/// -/// The @c InterruptType template argument below refers to any class -/// with the following interface: -/// @code -/// class Interrupter { -/// ... -/// public: -/// void start(const char* name = NULL)// called when computations begin -/// void end() // called when computations end -/// bool wasInterrupted(int percent=-1)// return true to break computation -///}; -/// @endcode -/// -/// @note If no template argument is provided for this InterruptType -/// the util::NullInterrupter is used which implies that all -/// interrupter calls are no-ops (i.e. incurs no computational overhead). - - -/// @brief Uniform scatters of point in the active voxels. -/// The point count is either explicitly defined or implicitly -/// through the specification of a global density (=points-per-volume) -/// -/// @note This uniform scattering technique assumes that the number of -/// points is generally smaller than the number of active voxels -/// (including virtual active voxels in active tiles). -template -class UniformPointScatter : public BasePointScatter -{ -public: - typedef BasePointScatter BaseT; - - UniformPointScatter(PointAccessorType& points, - Index64 pointCount, - RandomGenerator& randGen, - InterruptType* interrupt = NULL) - : BaseT(points, randGen, interrupt) - , mTargetPointCount(pointCount) - , mPointsPerVolume(0.0f) - { - } - UniformPointScatter(PointAccessorType& points, - float pointsPerVolume, - RandomGenerator& randGen, - InterruptType* interrupt = NULL) - : BaseT(points, randGen, interrupt) - , mTargetPointCount(0) - , mPointsPerVolume(pointsPerVolume) - { - } - - /// @brief This is the main functor method implementing the actual - /// scattering of points. - template - bool operator()(const GridT& grid) - { - mVoxelCount = grid.activeVoxelCount(); - if (mVoxelCount == 0) return false; - const Vec3d dim = grid.voxelSize(); - if (mPointsPerVolume>0) { - BaseT::start("Uniform scattering with fixed point density"); - mTargetPointCount = Index64(mPointsPerVolume*dim[0]*dim[1]*dim[2])*mVoxelCount; - } else if (mTargetPointCount>0) { - BaseT::start("Uniform scattering with fixed point count"); - mPointsPerVolume = mTargetPointCount/float(dim[0]*dim[1]*dim[2] * mVoxelCount); - } else { - return false; - } - - boost::scoped_array list(new Index64[mTargetPointCount]); - math::RandInt rand(BaseT::mRand01.engine(), 0, mVoxelCount-1); - for (Index64 i=0; i -class DenseUniformPointScatter : public BasePointScatter -{ -public: - typedef BasePointScatter BaseT; - - DenseUniformPointScatter(PointAccessorType& points, - float pointsPerVoxel, - RandomGenerator& randGen, - InterruptType* interrupt = NULL) - : BaseT(points, randGen, interrupt) - , mPointsPerVoxel(pointsPerVoxel) - { - } - - /// This is the main functor method implementing the actual scattering of points. - template - bool operator()(const GridT& grid) - { - typedef typename GridT::ValueOnCIter ValueIter; - if (mPointsPerVoxel < 1.0e-6) return false; - mVoxelCount = grid.activeVoxelCount(); - if (mVoxelCount == 0) return false; - BaseT::start("Dense uniform scattering with fixed point count"); - CoordBBox bbox; - const Vec3R offset(0.5, 0.5, 0.5); - - const int ppv = math::Floor(mPointsPerVoxel); - const double delta = mPointsPerVoxel - ppv; - const bool fractional = !math::isApproxZero(delta, 1.0e-6); - - for (ValueIter iter = grid.cbeginValueOn(); iter; ++iter) { - if (BaseT::interrupt()) return false; - if (iter.isVoxelValue()) {// a majorty is expected to be voxels - const Vec3R dmin = iter.getCoord() - offset; - for (int n = 0; n != ppv; ++n) BaseT::addPoint(grid, dmin); - if (fractional && BaseT::getRand() < delta) BaseT::addPoint(grid, dmin); - } else {// tiles contain multiple (virtual) voxels - iter.getBoundingBox(bbox); - const Coord size(bbox.extents()); - const Vec3R dmin = bbox.min() - offset; - const double d = mPointsPerVoxel * iter.getVoxelCount(); - const int m = math::Floor(d); - for (int n = 0; n != m; ++n) BaseT::addPoint(grid, dmin, size); - if (BaseT::getRand() < d - m) BaseT::addPoint(grid, dmin, size); - } - }//loop over all the active voxels and tiles - - BaseT::end(); - return true; - } - - // The following methods should only be called after the - // the operator() method was called - void print(const std::string &name, std::ostream& os = std::cout) const - { - os << "Dense uniformely scattered " << mPointCount << " points into " << mVoxelCount - << " active voxels in \"" << name << "\" corresponding to " - << mPointsPerVoxel << " points per voxel." << std::endl; - } - - float getPointsPerVoxel() const { return mPointsPerVoxel; } - -private: - using BaseT::mPointCount; - using BaseT::mVoxelCount; - float mPointsPerVoxel; -}; // class DenseUniformPointScatter - -/// @brief Non-uniform scatters of point in the active voxels. -/// The local point count is implicitly defined as a product of -/// of a global density (called pointsPerVolume) and the local voxel -/// (or tile) value. -/// -/// @note This scattering technique can be significantly slower -/// than a uniform scattering since its computational complexity -/// is proportional to the active voxel (and tile) count. -template -class NonUniformPointScatter : public BasePointScatter -{ -public: - typedef BasePointScatter BaseT; - - NonUniformPointScatter(PointAccessorType& points, - float pointsPerVolume, - RandomGenerator& randGen, - InterruptType* interrupt = NULL) - : BaseT(points, randGen, interrupt) - , mPointsPerVolume(pointsPerVolume)//note this is merely a - //multiplyer for the local point density - { - } - - /// This is the main functor method implementing the actual scattering of points. - template - bool operator()(const GridT& grid) - { - if (mPointsPerVolume <= 0.0f) return false; - mVoxelCount = grid.activeVoxelCount(); - if (mVoxelCount == 0) return false; - BaseT::start("Non-uniform scattering with local point density"); - const Vec3d dim = grid.voxelSize(); - const double volumePerVoxel = dim[0]*dim[1]*dim[2], - pointsPerVoxel = mPointsPerVolume * volumePerVoxel; - CoordBBox bbox; - const Vec3R offset(0.5, 0.5, 0.5); - for (typename GridT::ValueOnCIter iter = grid.cbeginValueOn(); iter; ++iter) { - if (BaseT::interrupt()) return false; - const double d = (*iter) * pointsPerVoxel * iter.getVoxelCount(); - const int n = int(d); - if (iter.isVoxelValue()) { // a majorty is expected to be voxels - const Vec3R dmin =iter.getCoord() - offset; - for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin); - if (BaseT::getRand() < (d - n)) BaseT::addPoint(grid, dmin); - } else { // tiles contain multiple (virtual) voxels - iter.getBoundingBox(bbox); - const Coord size(bbox.extents()); - const Vec3R dmin = bbox.min() - offset; - for (int i = 0; i < n; ++i) BaseT::addPoint(grid, dmin, size); - if (BaseT::getRand() < (d - n)) BaseT::addPoint(grid, dmin, size); - } - }//loop over all the active voxels and tiles - BaseT::end(); - return true; - } - - // The following methods should only be called after the - // the operator() method was called - void print(const std::string &name, std::ostream& os = std::cout) const - { - os << "Non-uniformely scattered " << mPointCount << " points into " << mVoxelCount - << " active voxels in \"" << name << "\"." << std::endl; - } - - float getPointPerVolume() const { return mPointsPerVolume; } - -private: - using BaseT::mPointCount; - using BaseT::mVoxelCount; - float mPointsPerVolume; - -}; // class NonUniformPointScatter - -/// Base class of all the point scattering classes defined above -template -class BasePointScatter -{ -public: - - Index64 getPointCount() const { return mPointCount; } - Index64 getVoxelCount() const { return mVoxelCount; } - -protected: - - /// This is a base class so the constructor is protected - BasePointScatter(PointAccessorType& points, - RandomGenerator& randGen, - InterruptType* interrupt = NULL) - : mPoints(points) - , mInterrupter(interrupt) - , mPointCount(0) - , mVoxelCount(0) - , mInterruptCount(0) - , mRand01(randGen) - { - } - - PointAccessorType& mPoints; - InterruptType* mInterrupter; - Index64 mPointCount; - Index64 mVoxelCount; - Index64 mInterruptCount; - math::Rand01 mRand01; - - inline void start(const char* name) - { - if (mInterrupter) mInterrupter->start(name); - } - - inline void end() - { - if (mInterrupter) mInterrupter->end(); - } - - inline bool interrupt() - { - //only check interrupter for every 32'th call - return !(mInterruptCount++ & ((1<<5)-1)) && util::wasInterrupted(mInterrupter); - } - - inline double getRand() { return mRand01(); } - - template - inline void addPoint(const GridT &grid, const Vec3R &dmin) - { - const Vec3R pos(dmin[0] + this->getRand(), - dmin[1] + this->getRand(), - dmin[2] + this->getRand()); - mPoints.add(grid.indexToWorld(pos)); - ++mPointCount; - } - - template - inline void addPoint(const GridT &grid, const Vec3R &dmin, const Coord &size) - { - const Vec3R pos(dmin[0] + size[0]*this->getRand(), - dmin[1] + size[1]*this->getRand(), - dmin[2] + size[2]*this->getRand()); - mPoints.add(grid.indexToWorld(pos)); - ++mPointCount; - } -};// class BasePointScatter - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_POINT_SCATTER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Prune.h b/openvdb_3_0_0_library/tools/Prune.h deleted file mode 100755 index 6937f74..0000000 --- a/openvdb_3_0_0_library/tools/Prune.h +++ /dev/null @@ -1,384 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Prune.h -/// -/// @brief Defined various multi-threaded utility functions for trees -/// -/// @author Ken Museth - -#ifndef OPENVDB_TOOLS_PRUNE_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_PRUNE_HAS_BEEN_INCLUDED - -#include -#include // for isNegative and negative -#include // for Index typedef -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Reduce the memory footprint of a @a tree by replacing with tiles -/// any nodes whose values are all the same (optionally to within a tolerance) -/// and have the same active state. -/// -/// @param tree the tree to be pruned -/// @param tolerance tolerance within which values are considered to be equal -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -template -inline void -prune(TreeT& tree, - typename TreeT::ValueType tolerance = zeroVal(), - bool threaded = true, - size_t grainSize = 1); - - -/// @brief Reduce the memory footprint of a @a tree by replacing with tiles -/// any non-leaf nodes whose values are all the same (optionally to within a tolerance) -/// and have the same active state. -/// -/// @param tree the tree to be pruned -/// @param tolerance tolerance within which values are considered to be equal -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -template -inline void -pruneTiles(TreeT& tree, - typename TreeT::ValueType tolerance = zeroVal(), - bool threaded = true, - size_t grainSize = 1); - - -/// @brief Reduce the memory footprint of a @a tree by replacing with -/// background tiles any nodes whose values are all inactive. -/// -/// @param tree the tree to be pruned -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -template -inline void -pruneInactive(TreeT& tree, bool threaded = true, size_t grainSize = 1); - - -/// @brief Reduce the memory footprint of a @a tree by replacing any nodes -/// whose values are all inactive with tiles of the given @a value. -/// -/// @param tree the tree to be pruned -/// @param value value assigned to inactive tiles created during pruning -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -template -inline void -pruneInactiveWithValue( - TreeT& tree, - const typename TreeT::ValueType& value, - bool threaded = true, - size_t grainSize = 1); - - -/// @brief Reduce the memory footprint of a @a tree by replacing nodes -/// whose values are all inactive with inactive tiles having a value equal to -/// the first value encountered in the (inactive) child. -/// @details This method is faster than tolerance-based prune and -/// useful for narrow-band level set applications where inactive -/// values are limited to either an inside or an outside value. -/// -/// @param tree the tree to be pruned -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -/// -/// @throw ValueError if the background of the @a tree is negative (as defined by math::isNegative) -template -inline void -pruneLevelSet(TreeT& tree, - bool threaded = true, - size_t grainSize = 1); - - -/// @brief Reduce the memory footprint of a @a tree by replacing nodes whose voxel values -/// are all inactive with inactive tiles having the value -| @a insideWidth | -/// if the voxel values are negative and | @a outsideWidth | otherwise. -/// -/// @details This method is faster than tolerance-based prune and -/// useful for narrow-band level set applications where inactive -/// values are limited to either an inside or an outside value. -/// -/// @param tree the tree to be pruned -/// @param outsideWidth the width of the outside of the narrow band -/// @param insideWidth the width of the inside of the narrow band -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -/// -/// @throw ValueError if @a outsideWidth is negative or @a insideWidth is -/// not negative (as defined by math::isNegative). -template -inline void -pruneLevelSet(TreeT& tree, - const typename TreeT::ValueType& outsideWidth, - const typename TreeT::ValueType& insideWidth, - bool threaded = true, - size_t grainSize = 1); - - -//////////////////////////////////////////////// - - -template -class InactivePruneOp -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::RootNodeType RootT; - typedef typename TreeT::LeafNodeType LeafT; - BOOST_STATIC_ASSERT(RootT::LEVEL > TerminationLevel); - - InactivePruneOp(TreeT& tree) : mValue(tree.background()) - { - tree.clearAllAccessors();//clear cache of nodes that could be pruned - } - - InactivePruneOp(TreeT& tree, const ValueT& v) : mValue(v) - { - tree.clearAllAccessors();//clear cache of nodes that could be pruned - } - - // Nothing to do at the leaf node level - void operator()(LeafT& node) const {;} - // Prune the child nodes of the internal nodes - template - void operator()(NodeT& node) const - { - if (NodeT::LEVEL > TerminationLevel) { - for (typename NodeT::ChildOnIter it=node.beginChildOn(); it; ++it) { - if (it->isInactive()) node.addTile(it.pos(), mValue, false); - } - } - } - // Prune the child nodes of the root node - void operator()(RootT& root) const - { - for (typename RootT::ChildOnIter it = root.beginChildOn(); it; ++it) { - if (it->isInactive()) root.addTile(it.getCoord(), mValue, false); - } - root.eraseBackgroundTiles(); - } -private: - - const ValueT mValue; -};// InactivePruneOp - - -template -class TolerancePruneOp -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::RootNodeType RootT; - typedef typename TreeT::LeafNodeType LeafT; - BOOST_STATIC_ASSERT(RootT::LEVEL > TerminationLevel); - - TolerancePruneOp(TreeT& tree, const ValueT& t) : mTolerance(t) - { - tree.clearAllAccessors();//clear cache of nodes that could be pruned - } - - // Nothing to do at the leaf node level - void operator()(LeafT& node) const {;} - // Prune the child nodes of the internal nodes - template - void operator()(NodeT& node) const - { - if (NodeT::LEVEL > TerminationLevel) { - ValueT value; - bool state; - for (typename NodeT::ChildOnIter it=node.beginChildOn(); it; ++it) { - if (it->isConstant(value, state, mTolerance)) node.addTile(it.pos(), value, state); - } - } - } - // Prune the child nodes of the root node - void operator()(RootT& root) const - { - ValueT value; - bool state; - for (typename RootT::ChildOnIter it = root.beginChildOn(); it; ++it) { - if (it->isConstant(value, state, mTolerance)) root.addTile(it.getCoord(), value, state); - } - root.eraseBackgroundTiles(); - } -private: - - const ValueT mTolerance; -};// TolerancePruneOp - - -template -class LevelSetPruneOp -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef typename TreeT::RootNodeType RootT; - typedef typename TreeT::LeafNodeType LeafT; - BOOST_STATIC_ASSERT(RootT::LEVEL > TerminationLevel); - - LevelSetPruneOp(TreeT& tree) - : mOutside(tree.background()) - , mInside(math::negative(mOutside)) - { - if (math::isNegative(mOutside)) { - OPENVDB_THROW(ValueError, - "LevelSetPruneOp: the background value cannot be negative!"); - } - tree.clearAllAccessors();//clear cache of nodes that could be pruned - } - LevelSetPruneOp(TreeT& tree, const ValueT& outside, const ValueT& inside) - : mOutside(outside) - , mInside(inside) - { - if (math::isNegative(mOutside)) { - OPENVDB_THROW(ValueError, - "LevelSetPruneOp: the outside value cannot be negative!"); - } - if (!math::isNegative(mInside)) { - OPENVDB_THROW(ValueError, - "LevelSetPruneOp: the inside value must be negative!"); - } - tree.clearAllAccessors();//clear cache of nodes that could be pruned - } - // Nothing to do at the leaf node level - void operator()(LeafT& node) const {;} - // Prune the child nodes of the internal nodes - template - void operator()(NodeT& node) const - { - if (NodeT::LEVEL > TerminationLevel) { - for (typename NodeT::ChildOnIter it=node.beginChildOn(); it; ++it) { - if (it->isInactive()) node.addTile(it.pos(), this->getTileValue(it), false); - } - } - } - // Prune the child nodes of the root node - void operator()(RootT& root) const - { - for (typename RootT::ChildOnIter it = root.beginChildOn(); it; ++it) { - if (it->isInactive()) root.addTile(it.getCoord(), this->getTileValue(it), false); - } - root.eraseBackgroundTiles(); - } - -private: - template - inline ValueT getTileValue(const IterT& iter) const - { - return math::isNegative(iter->getFirstValue()) ? mInside : mOutside; - } - - const ValueT mOutside, mInside; -};// LevelSetPruneOp - - -template -inline void -prune(TreeT& tree, typename TreeT::ValueType tol, bool threaded, size_t grainSize) -{ - tree::NodeManager nodes(tree); - TolerancePruneOp op(tree, tol); - nodes.processBottomUp(op, threaded, grainSize); -} - - -template -inline void -pruneTiles(TreeT& tree, typename TreeT::ValueType tol, bool threaded, size_t grainSize) -{ - tree::NodeManager nodes(tree); - TolerancePruneOp op(tree, tol); - nodes.processBottomUp(op, threaded, grainSize); -} - - -template -inline void -pruneInactive(TreeT& tree, bool threaded, size_t grainSize) -{ - tree::NodeManager nodes(tree); - InactivePruneOp op(tree); - nodes.processBottomUp(op, threaded, grainSize); -} - - -template -inline void -pruneInactiveWithValue(TreeT& tree, const typename TreeT::ValueType& v, - bool threaded, size_t grainSize) -{ - tree::NodeManager nodes(tree); - InactivePruneOp op(tree, v); - nodes.processBottomUp(op, threaded, grainSize); -} - - -template -inline void -pruneLevelSet(TreeT& tree, - const typename TreeT::ValueType& outside, - const typename TreeT::ValueType& inside, - bool threaded, - size_t grainSize) -{ - tree::NodeManager nodes(tree); - LevelSetPruneOp op(tree, outside, inside); - nodes.processBottomUp(op, threaded, grainSize); -} - - -template -inline void -pruneLevelSet(TreeT& tree, bool threaded, size_t grainSize) -{ - tree::NodeManager nodes(tree); - LevelSetPruneOp op(tree); - nodes.processBottomUp(op, threaded, grainSize); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_PRUNE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/RayIntersector.h b/openvdb_3_0_0_library/tools/RayIntersector.h deleted file mode 100755 index 3b45c68..0000000 --- a/openvdb_3_0_0_library/tools/RayIntersector.h +++ /dev/null @@ -1,702 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file RayIntersector.h -/// -/// @author Ken Museth -/// -/// @brief Accelerated intersection of a ray with a narrow-band level -/// set or a generic (e.g. density) volume. This will of course be -/// useful for respectively surface and volume rendering. -/// -/// @details This file defines two main classes, -/// LevelSetRayIntersector and VolumeRayIntersector, as well as the -/// three support classes LevelSetHDDA, VolumeHDDA and LinearSearchImpl. -/// The LevelSetRayIntersector is templated on the LinearSearchImpl class -/// and calls instances of the LevelSetHDDA class. The reason to split -/// level set ray intersection into three classes is twofold. First -/// LevelSetRayIntersector defines the public API for client code and -/// LinearSearchImpl defines the actual algorithm used for the -/// ray level-set intersection. In other words this design will allow -/// for the public API to be fixed while the intersection algorithm -/// can change without resolving to (slow) virtual methods. Second, -/// LevelSetHDDA, which implements a hierarchical Differential Digital -/// Analyzer, relies on partial template specialization, so it has to -/// be a standalone class (as opposed to a member class of -/// LevelSetRayIntersector). The VolumeRayIntersector is conceptually -/// much simpler then the LevelSetRayIntersector, and hence it only -/// depends on VolumeHDDA that implements the hierarchical -/// Differential Digital Analyzer. - - -#ifndef OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "Morphology.h" -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -// Helper class that implements the actual search of the zero-crossing -// of the level set along the direction of a ray. This particular -// implementation uses iterative linear search. -template -class LinearSearchImpl; - - -///////////////////////////////////// LevelSetRayIntersector ///////////////////////////////////// - - -/// @brief This class provides the public API for intersecting a ray -/// with a narrow-band level set. -/// -/// @details It wraps an SearchImplT with a simple public API and -/// performs the actual hierarchical tree node and voxel traversal. -/// -/// @warning Use the (default) copy-constructor to make sure each -/// computational thread has their own instance of this class. This is -/// important since the SearchImplT contains a ValueAccessor that is -/// not thread-safe. However copying is very efficient. -/// -/// @see tools/RayTracer.h for examples of intended usage. -/// -/// @todo Add TrilinearSearchImpl, as an alternative to LinearSearchImpl, -/// that performs analytical 3D trilinear intersection tests, i.e., solves -/// cubic equations. This is slower but also more accurate than the 1D -/// linear interpolation in LinearSearchImpl. -template, - int NodeLevel = GridT::TreeType::RootNodeType::ChildNodeType::LEVEL, - typename RayT = math::Ray > -class LevelSetRayIntersector -{ -public: - typedef GridT GridType; - typedef RayT RayType; - typedef typename RayT::RealType RealType; - typedef typename RayT::Vec3T Vec3Type; - typedef typename GridT::ValueType ValueT; - typedef typename GridT::TreeType TreeT; - - BOOST_STATIC_ASSERT( NodeLevel >= -1 && NodeLevel < int(TreeT::DEPTH)-1); - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Constructor - /// @param grid level set grid to intersect rays against. - /// @param isoValue optional iso-value for the ray-intersection. - LevelSetRayIntersector(const GridT& grid, const ValueT& isoValue = zeroVal()) - : mTester(grid, isoValue) - { - if (!grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "LevelSetRayIntersector only supports uniform voxels!"); - } - if (grid.getGridClass() != GRID_LEVEL_SET) { - OPENVDB_THROW(RuntimeError, - "LevelSetRayIntersector only supports level sets!" - "\nUse Grid::setGridClass(openvdb::GRID_LEVEL_SET)"); - } - } - - /// @brief Return the iso-value used for ray-intersections - const ValueT& getIsoValue() const { return mTester.getIsoValue(); } - - /// @brief Return @c true if the index-space ray intersects the level set. - /// @param iRay ray represented in index space. - bool intersectsIS(const RayType& iRay) const - { - if (!mTester.setIndexRay(iRay)) return false;//missed bbox - return math::LevelSetHDDA::test(mTester); - } - - /// @brief Return @c true if the index-space ray intersects the level set - /// @param iRay ray represented in index space. - /// @param iTime if an intersection was found it is assigned the time of the - /// intersection along the index ray. - bool intersectsIS(const RayType& iRay, Real &iTime) const - { - if (!mTester.setIndexRay(iRay)) return false;//missed bbox - iTime = mTester.getIndexTime(); - return math::LevelSetHDDA::test(mTester); - } - - /// @brief Return @c true if the index-space ray intersects the level set. - /// @param iRay ray represented in index space. - /// @param xyz if an intersection was found it is assigned the - /// intersection point in index space, otherwise it is unchanged. - bool intersectsIS(const RayType& iRay, Vec3Type& xyz) const - { - if (!mTester.setIndexRay(iRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getIndexPos(xyz); - return true; - } - - /// @brief Return @c true if the index-space ray intersects the level set. - /// @param iRay ray represented in index space. - /// @param xyz if an intersection was found it is assigned the - /// intersection point in index space, otherwise it is unchanged. - /// @param iTime if an intersection was found it is assigned the time of the - /// intersection along the index ray. - bool intersectsIS(const RayType& iRay, Vec3Type& xyz, Real &iTime) const - { - if (!mTester.setIndexRay(iRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getIndexPos(xyz); - iTime = mTester.getIndexTime(); - return true; - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - bool intersectsWS(const RayType& wRay) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - return math::LevelSetHDDA::test(mTester); - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - /// @param wTime if an intersection was found it is assigned the time of the - /// intersection along the world ray. - bool intersectsWS(const RayType& wRay, Real &wTime) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - wTime = mTester.getWorldTime(); - return math::LevelSetHDDA::test(mTester); - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - /// @param world if an intersection was found it is assigned the - /// intersection point in world space, otherwise it is unchanged - bool intersectsWS(const RayType& wRay, Vec3Type& world) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getWorldPos(world); - return true; - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - /// @param world if an intersection was found it is assigned the - /// intersection point in world space, otherwise it is unchanged. - /// @param wTime if an intersection was found it is assigned the time of the - /// intersection along the world ray. - bool intersectsWS(const RayType& wRay, Vec3Type& world, Real &wTime) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getWorldPos(world); - wTime = mTester.getWorldTime(); - return true; - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - /// @param world if an intersection was found it is assigned the - /// intersection point in world space, otherwise it is unchanged. - /// @param normal if an intersection was found it is assigned the normal - /// of the level set surface in world space, otherwise it is unchanged. - bool intersectsWS(const RayType& wRay, Vec3Type& world, Vec3Type& normal) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getWorldPosAndNml(world, normal); - return true; - } - - /// @brief Return @c true if the world-space ray intersects the level set. - /// @param wRay ray represented in world space. - /// @param world if an intersection was found it is assigned the - /// intersection point in world space, otherwise it is unchanged. - /// @param normal if an intersection was found it is assigned the normal - /// of the level set surface in world space, otherwise it is unchanged. - /// @param wTime if an intersection was found it is assigned the time of the - /// intersection along the world ray. - bool intersectsWS(const RayType& wRay, Vec3Type& world, Vec3Type& normal, Real &wTime) const - { - if (!mTester.setWorldRay(wRay)) return false;//missed bbox - if (!math::LevelSetHDDA::test(mTester)) return false;//missed level set - mTester.getWorldPosAndNml(world, normal); - wTime = mTester.getWorldTime(); - return true; - } - -private: - - mutable SearchImplT mTester; - -};// LevelSetRayIntersector - - -////////////////////////////////////// VolumeRayIntersector ////////////////////////////////////// - - -/// @brief This class provides the public API for intersecting a ray -/// with a generic (e.g. density) volume. -/// @details Internally it performs the actual hierarchical tree node traversal. -/// @warning Use the (default) copy-constructor to make sure each -/// computational thread has their own instance of this class. This is -/// important since it contains a ValueAccessor that is -/// not thread-safe and a CoordBBox of the active voxels that should -/// not be re-computed for each thread. However copying is very efficient. -/// @par Example: -/// @code -/// // Create an instance for the master thread -/// VolumeRayIntersector inter(grid); -/// // For each additional thread use the copy contructor. This -/// // amortizes the overhead of computing the bbox of the active voxels! -/// VolumeRayIntersector inter2(inter); -/// // Before each ray-traversal set the index ray. -/// iter.setIndexRay(ray); -/// // or world ray -/// iter.setWorldRay(ray); -/// // Now you can begin the ray-marching using consecutive calls to VolumeRayIntersector::march -/// double t0=0, t1=0;// note the entry and exit times are with respect to the INDEX ray -/// while ( inter.march(t0, t1) ) { -/// // perform line-integration between t0 and t1 -/// }} -/// @endcode -template > -class VolumeRayIntersector -{ -public: - typedef GridT GridType; - typedef RayT RayType; - typedef typename RayT::RealType RealType; - typedef typename GridT::TreeType::RootNodeType RootType; - typedef tree::Tree::Type> TreeT; - - BOOST_STATIC_ASSERT( NodeLevel >= 0 && NodeLevel < int(TreeT::DEPTH)-1); - - /// @brief Grid constructor - /// @param grid Generic grid to intersect rays against. - /// @param dilationCount The number of voxel dilations performed - /// on (a boolean copy of) the input grid. This allows the - /// intersector to account for the size of interpolation kernels - /// in client code. - /// @throw RuntimeError if the voxels of the grid are not uniform - /// or the grid is empty. - VolumeRayIntersector(const GridT& grid, int dilationCount = 0) - : mIsMaster(true) - , mTree(new TreeT(grid.tree(), false, TopologyCopy())) - , mGrid(&grid) - , mAccessor(*mTree) - { - if (!grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "VolumeRayIntersector only supports uniform voxels!"); - } - if ( grid.empty() ) { - OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids"); - } - - // Dilate active voxels to better account for the size of interpolation kernels - tools::dilateVoxels(*mTree, dilationCount); - - mTree->root().evalActiveBoundingBox(mBBox, /*visit individual voxels*/false); - - mBBox.max().offset(1);//padding so the bbox of a node becomes (origin,origin + node_dim) - } - - /// @brief Grid and BBox constructor - /// @param grid Generic grid to intersect rays against. - /// @param bbox The axis-aligned bounding-box in the index space of the grid. - /// @warning It is assumed that bbox = (min, min + dim) where min denotes - /// to the smallest grid coordinates and dim are the integer length of the bbox. - /// @throw RuntimeError if the voxels of the grid are not uniform - /// or the grid is empty. - VolumeRayIntersector(const GridT& grid, const math::CoordBBox& bbox) - : mIsMaster(true) - , mTree(new TreeT(grid.tree(), false, TopologyCopy())) - , mGrid(&grid) - , mAccessor(*mTree) - , mBBox(bbox) - { - if (!grid.hasUniformVoxels() ) { - OPENVDB_THROW(RuntimeError, - "VolumeRayIntersector only supports uniform voxels!"); - } - if ( grid.empty() ) { - OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids"); - } - } - - /// @brief Shallow copy constructor - /// @warning This copy constructor creates shallow copies of data - /// members of the instance passed as the argument. For - /// performance reasons we are not using shared pointers (their - /// mutex-lock impairs multi-threading). - VolumeRayIntersector(const VolumeRayIntersector& other) - : mIsMaster(false) - , mTree(other.mTree)//shallow copy - , mGrid(other.mGrid)//shallow copy - , mAccessor(*mTree)//deep copy - , mRay(other.mRay)//deep copy - , mTmax(other.mTmax)//deep copy - , mBBox(other.mBBox)//deep copy - { - } - - /// @brief Destructor - ~VolumeRayIntersector() { if (mIsMaster) delete mTree; } - - /// @brief Return @c false if the index ray misses the bbox of the grid. - /// @param iRay Ray represented in index space. - /// @warning Call this method (or setWorldRay) before the ray - /// traversal starts and use the return value to decide if further - /// marching is required. - inline bool setIndexRay(const RayT& iRay) - { - mRay = iRay; - const bool hit = mRay.clip(mBBox); - if (hit) mTmax = mRay.t1(); - return hit; - } - - /// @brief Return @c false if the world ray misses the bbox of the grid. - /// @param wRay Ray represented in world space. - /// @warning Call this method (or setIndexRay) before the ray - /// traversal starts and use the return value to decide if further - /// marching is required. - /// @details Since hit times are computed with repect to the ray - /// represented in index space of the current grid, it is - /// recommended that either the client code uses getIndexPos to - /// compute index position from hit times or alternatively keeps - /// an instance of the index ray and instead uses setIndexRay to - /// initialize the ray. - inline bool setWorldRay(const RayT& wRay) - { - return this->setIndexRay(wRay.worldToIndex(*mGrid)); - } - - inline typename RayT::TimeSpan march() - { - const typename RayT::TimeSpan t = mHDDA.march(mRay, mAccessor); - if (t.t1>0) mRay.setTimes(t.t1 + math::Delta::value(), mTmax); - return t; - } - - /// @brief Return @c true if the ray intersects active values, - /// i.e. either active voxels or tiles. Only when a hit is - /// detected are t0 and t1 updated with the corresponding entry - /// and exit times along the INDEX ray! - /// @note Note that t0 and t1 are only resolved at the node level - /// (e.g. a LeafNode with active voxels) as oppose the individual - /// active voxels. - /// @param t0 If the return value > 0 this is the time of the - /// first hit of an active tile or leaf. - /// @param t1 If the return value > t0 this is the time of the - /// first hit (> t0) of an inactive tile or exit point of the - /// BBOX for the leaf nodes. - /// @warning t0 and t1 are computed with repect to the ray represented in - /// index space of the current grid, not world space! - inline bool march(Real& t0, Real& t1) - { - const typename RayT::TimeSpan t = this->march(); - t.get(t0, t1); - return t.valid(); - } - - /// @brief Generates a list of hits along the ray. - /// - /// @param list List of hits represented as time spans. - /// - /// @note ListType is a list of RayType::TimeSpan and is required to - /// have the two methods: clear() and push_back(). Thus, it could - /// be std::vector or - /// std::deque. - template - inline void hits(ListType& list) - { - mHDDA.hits(mRay, mAccessor, list); - } - - /// @brief Return the floating-point index position along the - /// current index ray at the specified time. - inline Vec3R getIndexPos(Real time) const { return mRay(time); } - - /// @brief Return the floating-point world position along the - /// current index ray at the specified time. - inline Vec3R getWorldPos(Real time) const { return mGrid->indexToWorld(mRay(time)); } - - inline Real getWorldTime(Real time) const - { - return time*mGrid->transform().baseMap()->applyJacobian(mRay.dir()).length(); - } - - /// @brief Return a const reference to the input grid. - const GridT& grid() const { return *mGrid; } - - /// @brief Return a const reference to the (potentially dilated) - /// bool tree used to accelerate the ray marching. - const TreeT& tree() const { return *mTree; } - - /// @brief Return a const reference to the BBOX of the grid - const math::CoordBBox& bbox() const { return mBBox; } - - /// @brief Print bbox, statistics, memory usage and other information. - /// @param os a stream to which to write textual information - /// @param verboseLevel 1: print bbox only; 2: include boolean tree - /// statistics; 3: include memory usage - void print(std::ostream& os = std::cout, int verboseLevel = 1) - { - if (verboseLevel>0) { - os << "BBox: " << mBBox << std::endl; - if (verboseLevel==2) { - mTree->print(os, 1); - } else if (verboseLevel>2) { - mTree->print(os, 2); - } - } - } - -private: - - typedef typename tree::ValueAccessor AccessorT; - - const bool mIsMaster; - TreeT* mTree; - const GridT* mGrid; - AccessorT mAccessor; - RayT mRay; - Real mTmax; - math::CoordBBox mBBox; - math::VolumeHDDA mHDDA; - -};// VolumeRayIntersector - - -//////////////////////////////////////// LinearSearchImpl //////////////////////////////////////// - - -/// @brief Implements linear iterative search for an iso-value of -/// the level set along along the direction of the ray. -/// -/// @note Since this class is used internally in -/// LevelSetRayIntersector (define above) and LevelSetHDDA (defined below) -/// client code should never interact directly with its API. This also -/// explains why we are not concerned with the fact that several of -/// its methods are unsafe to call unless roots were already detected. -/// -/// @details It is approximate due to the limited number of iterations -/// which can can be defined with a template parameter. However the default value -/// has proven surprisingly accurate and fast. In fact more iterations -/// are not guaranteed to give significantly better results. -/// -/// @warning Since the root-searching algorithm is approximate -/// (first-order) it is possible to miss intersections if the -/// iso-value is too close to the inside or outside of the narrow -/// band (typically a distance less then a voxel unit). -/// -/// @warning Since this class internally stores a ValueAccessor it is NOT thread-safe, -/// so make sure to give each thread its own instance. This of course also means that -/// the cost of allocating an instance should (if possible) be amortized over -/// as many ray intersections as possible. -template -class LinearSearchImpl -{ -public: - typedef math::Ray RayT; - typedef typename GridT::ValueType ValueT; - typedef typename GridT::ConstAccessor AccessorT; - typedef math::BoxStencil StencilT; - typedef typename StencilT::Vec3Type Vec3T; - - /// @brief Constructor from a grid. - /// @throw RunTimeError if the grid is empty. - /// @throw ValueError if the isoValue is not inside the narrow-band. - LinearSearchImpl(const GridT& grid, const ValueT& isoValue = zeroVal()) - : mStencil(grid), - mIsoValue(isoValue), - mMinValue(isoValue - ValueT(2 * grid.voxelSize()[0])), - mMaxValue(isoValue + ValueT(2 * grid.voxelSize()[0])) - { - if ( grid.empty() ) { - OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids"); - } - if (mIsoValue<= -grid.background() || - mIsoValue>= grid.background() ){ - OPENVDB_THROW(ValueError, "The iso-value must be inside the narrow-band!"); - } - grid.tree().root().evalActiveBoundingBox(mBBox, /*visit individual voxels*/false); - } - - /// @brief Return the iso-value used for ray-intersections - const ValueT& getIsoValue() const { return mIsoValue; } - - /// @brief Return @c false the ray misses the bbox of the grid. - /// @param iRay Ray represented in index space. - /// @warning Call this method before the ray traversal starts. - inline bool setIndexRay(const RayT& iRay) - { - mRay = iRay; - return mRay.clip(mBBox);//did it hit the bbox - } - - /// @brief Return @c false the ray misses the bbox of the grid. - /// @param wRay Ray represented in world space. - /// @warning Call this method before the ray traversal starts. - inline bool setWorldRay(const RayT& wRay) - { - mRay = wRay.worldToIndex(mStencil.grid()); - return mRay.clip(mBBox);//did it hit the bbox - } - - /// @brief Get the intersection point in index space. - /// @param xyz The position in index space of the intersection. - inline void getIndexPos(Vec3d& xyz) const { xyz = mRay(mTime); } - - /// @brief Get the intersection point in world space. - /// @param xyz The position in world space of the intersection. - inline void getWorldPos(Vec3d& xyz) const { xyz = mStencil.grid().indexToWorld(mRay(mTime)); } - - /// @brief Get the intersection point and normal in world space - /// @param xyz The position in world space of the intersection. - /// @param nml The surface normal in world space of the intersection. - inline void getWorldPosAndNml(Vec3d& xyz, Vec3d& nml) - { - this->getIndexPos(xyz); - mStencil.moveTo(xyz); - nml = mStencil.gradient(xyz); - nml.normalize(); - xyz = mStencil.grid().indexToWorld(xyz); - } - - /// @brief Return the time of intersection along the index ray. - inline RealT getIndexTime() const { return mTime; } - - /// @brief Return the time of intersection along the world ray. - inline RealT getWorldTime() const - { - return mTime*mStencil.grid().transform().baseMap()->applyJacobian(mRay.dir()).length(); - } - -private: - - /// @brief Initiate the local voxel intersection test. - /// @warning Make sure to call this method before the local voxel intersection test. - inline void init(RealT t0) - { - mT[0] = t0; - mV[0] = static_cast(this->interpValue(t0)); - } - - inline void setRange(RealT t0, RealT t1) { mRay.setTimes(t0, t1); } - - /// @brief Return a const reference to the ray. - inline const RayT& ray() const { return mRay; } - - /// @brief Return true if a node of the the specified type exists at ijk. - template - inline bool hasNode(const Coord& ijk) - { - return mStencil.accessor().template probeConstNode(ijk) != NULL; - } - - /// @brief Return @c true if an intersection is detected. - /// @param ijk Grid coordinate of the node origin or voxel being tested. - /// @param time Time along the index ray being tested. - /// @warning Only if and intersection is detected is it safe to - /// call getIndexPos, getWorldPos and getWorldPosAndNml! - inline bool operator()(const Coord& ijk, RealT time) - { - ValueT V; - if (mStencil.accessor().probeValue(ijk, V) &&//within narrow band - V>mMinValue && V(this->interpValue(time)); - if (math::ZeroCrossing(mV[0], mV[1])) { - mTime = this->interpTime(); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - for (int n=0; Iterations>0 && n(this->interpValue(mTime)); - const int m = math::ZeroCrossing(mV[0], V) ? 1 : 0; - mV[m] = V; - mT[m] = mTime; - mTime = this->interpTime(); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - return true; - } - mT[0] = mT[1]; - mV[0] = mV[1]; - } - return false; - } - - inline RealT interpTime() - { - assert(math::isApproxLarger(mT[1], mT[0], 1e-6)); - return mT[0]+(mT[1]-mT[0])*mV[0]/(mV[0]-mV[1]); - } - - inline RealT interpValue(RealT time) - { - const Vec3R pos = mRay(time); - mStencil.moveTo(pos); - return mStencil.interpolation(pos) - mIsoValue; - } - - template friend struct math::LevelSetHDDA; - - RayT mRay; - StencilT mStencil; - RealT mTime;//time of intersection - ValueT mV[2]; - RealT mT[2]; - const ValueT mIsoValue, mMinValue, mMaxValue; - math::CoordBBox mBBox; -};// LinearSearchImpl - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/RayTracer.h b/openvdb_3_0_0_library/tools/RayTracer.h deleted file mode 100755 index 2124a75..0000000 --- a/openvdb_3_0_0_library/tools/RayTracer.h +++ /dev/null @@ -1,1099 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file RayTracer.h -/// -/// @author Ken Museth -/// -/// @brief Defines two simple but multithreaded renders, a level-set -/// ray tracer and a volume render. To support these renders we also define -/// perspective and orthographic cameras (both designed to mimic a Houdini camera), -/// a Film class and some rather naive shaders. -/// -/// @note These classes are included mainly as reference implementations for -/// ray-tracing of OpenVDB volumes. In other words they are not intended for -/// production-quality rendering, but could be used for fast pre-visualiztion -/// or as a startingpoint for a more serious render. - -#ifndef OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef OPENVDB_TOOLS_RAYTRACER_USE_EXR -#include -#include -#include -#include -#include -#endif - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -// Forward declarations -class BaseCamera; -class BaseShader; - -/// @brief Ray-trace a volume. -template -inline void rayTrace(const GridT&, - const BaseShader&, - BaseCamera&, - size_t pixelSamples = 1, - unsigned int seed = 0, - bool threaded = true); - -/// @brief Ray-trace a volume using a given ray intersector. -template -inline void rayTrace(const GridT&, - const IntersectorT&, - const BaseShader&, - BaseCamera&, - size_t pixelSamples = 1, - unsigned int seed = 0, - bool threaded = true); - - -///////////////////////////////LEVEL SET RAY TRACER /////////////////////////////////////// - -/// @brief A (very) simple multithreaded ray tracer specifically for narrow-band level sets. -/// @details Included primarily as a reference implementation. -template > -class LevelSetRayTracer -{ -public: - typedef GridT GridType; - typedef typename IntersectorT::Vec3Type Vec3Type; - typedef typename IntersectorT::RayType RayType; - - /// @brief Constructor based on an instance of the grid to be rendered. - LevelSetRayTracer(const GridT& grid, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples = 1, - unsigned int seed = 0); - - /// @brief Constructor based on an instance of the intersector - /// performing the ray-intersections. - LevelSetRayTracer(const IntersectorT& inter, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples = 1, - unsigned int seed = 0); - - /// @brief Copy constructor - LevelSetRayTracer(const LevelSetRayTracer& other); - - /// @brief Destructor - ~LevelSetRayTracer(); - - /// @brief Set the level set grid to be ray-traced - void setGrid(const GridT& grid); - - /// @brief Set the intersector that performs the actual - /// intersection of the rays against the narrow-band level set. - void setIntersector(const IntersectorT& inter); - - /// @brief Set the shader derived from the abstract BaseShader class. - /// - /// @note The shader is not assumed to be thread-safe so each - /// thread will get it's only deep copy. For instance it could - /// contains a ValueAccessor into another grid with auxiliary - /// shading information. Thus, make sure it is relatively - /// light-weight and efficient to copy (which is the case for ValueAccesors). - void setShader(const BaseShader& shader); - - /// @brief Set the camera derived from the abstract BaseCamera class. - void setCamera(BaseCamera& camera); - - /// @brief Set the number of pixel samples and the seed for - /// jittered sub-rays. A value larger then one implies - /// anti-aliasing by jittered super-sampling. - /// @throw ValueError if pixelSamples is equal to zero. - void setPixelSamples(size_t pixelSamples, unsigned int seed = 0); - - /// @brief Perform the actual (potentially multithreaded) ray-tracing. - void render(bool threaded = true) const; - - /// @brief Public method required by tbb::parallel_for. - /// @warning Never call it directly. - void operator()(const tbb::blocked_range& range) const; - -private: - const bool mIsMaster; - double* mRand; - IntersectorT mInter; - boost::scoped_ptr mShader; - BaseCamera* mCamera; - size_t mSubPixels; -};// LevelSetRayTracer - - -///////////////////////////////VOLUME RENDER /////////////////////////////////////// - -/// @brief A (very) simple multithreaded volume render specifically for scalar density. -/// @details Included primarily as a reference implementation. -/// @note It will only compile if the IntersectorT is templated on a Grid with a -/// floating-point voxel type. -template -class VolumeRender -{ -public: - - typedef typename IntersectorT::GridType GridType; - typedef typename IntersectorT::RayType RayType; - typedef typename GridType::ValueType ValueType; - typedef typename GridType::ConstAccessor AccessorType; - typedef tools::GridSampler SamplerType; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - /// @brief Constructor taking an intersector and a base camera. - VolumeRender(const IntersectorT& inter, BaseCamera& camera); - - /// @brief Copy constructor which creates a thread-safe clone - VolumeRender(const VolumeRender& other); - - /// @brief Perform the actual (potentially multithreaded) volume rendering. - void render(bool threaded=true) const; - - /// @brief Set the camera derived from the abstract BaseCamera class. - void setCamera(BaseCamera& camera) { mCamera = &camera; } - - /// @brief Set the intersector that performs the actual - /// intersection of the rays against the volume. - void setIntersector(const IntersectorT& inter); - - /// @brief Set the vector components of a directional light source - /// @throw ArithmeticError if input is a null vector. - void setLightDir(Real x, Real y, Real z) { mLightDir = Vec3R(x,y,z).unit(); } - - /// @brief Set the color of the direcitonal light source. - void setLightColor(Real r, Real g, Real b) { mLightColor = Vec3R(r,g,b); } - - /// @brief Set the integration step-size in voxel units for the primay ray. - void setPrimaryStep(Real primaryStep) { mPrimaryStep = primaryStep; } - - /// @brief Set the integration step-size in voxel units for the primay ray. - void setShadowStep(Real shadowStep) { mShadowStep = shadowStep; } - - /// @brief Set Scattering coefficients. - void setScattering(Real x, Real y, Real z) { mScattering = Vec3R(x,y,z); } - - /// @brief Set absorption coefficients. - void setAbsorption(Real x, Real y, Real z) { mAbsorption = Vec3R(x,y,z); } - - /// @brief Set parameter that imitates multi-scattering. A value - /// of zero implies no multi-scattering. - void setLightGain(Real gain) { mLightGain = gain; } - - /// @brief Set the cut-off value for density and transmittance. - void setCutOff(Real cutOff) { mCutOff = cutOff; } - - /// @brief Print parameters, statistics, memory usage and other information. - /// @param os a stream to which to write textual information - /// @param verboseLevel 1: print parameters only; 2: include grid - /// statistics; 3: include memory usage - void print(std::ostream& os = std::cout, int verboseLevel = 1); - - /// @brief Public method required by tbb::parallel_for. - /// @warning Never call it directly. - void operator()(const tbb::blocked_range& range) const; - -private: - - AccessorType mAccessor; - BaseCamera* mCamera; - boost::scoped_ptr mPrimary, mShadow; - Real mPrimaryStep, mShadowStep, mCutOff, mLightGain; - Vec3R mLightDir, mLightColor, mAbsorption, mScattering; -};//VolumeRender - -//////////////////////////////////////// FILM //////////////////////////////////////// - -/// @brief A simple class that allows for concurrent writes to pixels in an image, -/// background initialization of the image, and PPM or EXR file output. -class Film -{ -public: - /// @brief Floating-point RGBA components in the range [0, 1]. - /// @details This is our preferred representation for color processing. - struct RGBA - { - typedef float ValueT; - - RGBA() : r(0), g(0), b(0), a(1) {} - explicit RGBA(ValueT intensity) : r(intensity), g(intensity), b(intensity), a(1) {} - RGBA(ValueT _r, ValueT _g, ValueT _b, ValueT _a = static_cast(1.0)): - r(_r), g(_g), b(_b), a(_a) - {} - - RGBA operator* (ValueT scale) const { return RGBA(r*scale, g*scale, b*scale);} - RGBA operator+ (const RGBA& rhs) const { return RGBA(r+rhs.r, g+rhs.g, b+rhs.b);} - RGBA operator* (const RGBA& rhs) const { return RGBA(r*rhs.r, g*rhs.g, b*rhs.b);} - RGBA& operator+=(const RGBA& rhs) { r+=rhs.r; g+=rhs.g; b+=rhs.b, a+=rhs.a; return *this;} - - void over(const RGBA& rhs) - { - const float s = rhs.a*(1.0f-a); - r = a*r+s*rhs.r; - g = a*g+s*rhs.g; - b = a*b+s*rhs.b; - a = a + s; - } - - ValueT r, g, b, a; - }; - - - Film(size_t width, size_t height) - : mWidth(width), mHeight(height), mSize(width*height), mPixels(new RGBA[mSize]) - { - } - Film(size_t width, size_t height, const RGBA& bg) - : mWidth(width), mHeight(height), mSize(width*height), mPixels(new RGBA[mSize]) - { - this->fill(bg); - } - - const RGBA& pixel(size_t w, size_t h) const - { - assert(w < mWidth); - assert(h < mHeight); - return mPixels[w + h*mWidth]; - } - - RGBA& pixel(size_t w, size_t h) - { - assert(w < mWidth); - assert(h < mHeight); - return mPixels[w + h*mWidth]; - } - - void fill(const RGBA& rgb=RGBA(0)) { for (size_t i=0; i buffer(new unsigned char[3*mSize]); - unsigned char *tmp = buffer.get(), *q = tmp; - RGBA* p = mPixels.get(); - size_t n = mSize; - while (n--) { - *q++ = static_cast(255.0f*(*p ).r); - *q++ = static_cast(255.0f*(*p ).g); - *q++ = static_cast(255.0f*(*p++).b); - } - - std::ofstream os(name.c_str(), std::ios_base::binary); - if (!os.is_open()) { - std::cerr << "Error opening PPM file \"" << name << "\"" << std::endl; - return; - } - - os << "P6\n" << mWidth << " " << mHeight << "\n255\n"; - os.write((const char *)&(*tmp), 3*mSize*sizeof(unsigned char)); - } - -#ifdef OPENVDB_TOOLS_RAYTRACER_USE_EXR - void saveEXR(const std::string& fileName, size_t compression = 2, size_t threads = 8) - { - std::string name(fileName + ".exr"); - - if (threads>0) Imf::setGlobalThreadCount(threads); - Imf::Header header(mWidth, mHeight); - if (compression==0) header.compression() = Imf::NO_COMPRESSION; - if (compression==1) header.compression() = Imf::RLE_COMPRESSION; - if (compression>=2) header.compression() = Imf::ZIP_COMPRESSION; - header.channels().insert("R", Imf::Channel(Imf::FLOAT)); - header.channels().insert("G", Imf::Channel(Imf::FLOAT)); - header.channels().insert("B", Imf::Channel(Imf::FLOAT)); - header.channels().insert("A", Imf::Channel(Imf::FLOAT)); - - Imf::FrameBuffer framebuffer; - framebuffer.insert("R", Imf::Slice( Imf::FLOAT, (char *) &(mPixels[0].r), - sizeof (RGBA), sizeof (RGBA) * mWidth)); - framebuffer.insert("G", Imf::Slice( Imf::FLOAT, (char *) &(mPixels[0].g), - sizeof (RGBA), sizeof (RGBA) * mWidth)); - framebuffer.insert("B", Imf::Slice( Imf::FLOAT, (char *) &(mPixels[0].b), - sizeof (RGBA), sizeof (RGBA) * mWidth)); - framebuffer.insert("A", Imf::Slice( Imf::FLOAT, (char *) &(mPixels[0].a), - sizeof (RGBA), sizeof (RGBA) * mWidth)); - - Imf::OutputFile file(name.c_str(), header); - file.setFrameBuffer(framebuffer); - file.writePixels(mHeight); - } -#endif - - size_t width() const { return mWidth; } - size_t height() const { return mHeight; } - size_t numPixels() const { return mSize; } - const RGBA* pixels() const { return mPixels.get(); } - -private: - size_t mWidth, mHeight, mSize; - boost::scoped_array mPixels; -};// Film - - -//////////////////////////////////////// CAMERAS //////////////////////////////////////// - -/// Abstract base class for the perspective and orthographic cameras -class BaseCamera -{ -public: - BaseCamera(Film& film, const Vec3R& rotation, const Vec3R& translation, - double frameWidth, double nearPlane, double farPlane) - : mFilm(&film) - , mScaleWidth(frameWidth) - , mScaleHeight(frameWidth * double(film.height()) / double(film.width())) - { - assert(nearPlane > 0 && farPlane > nearPlane); - mScreenToWorld.accumPostRotation(math::X_AXIS, rotation[0] * M_PI / 180.0); - mScreenToWorld.accumPostRotation(math::Y_AXIS, rotation[1] * M_PI / 180.0); - mScreenToWorld.accumPostRotation(math::Z_AXIS, rotation[2] * M_PI / 180.0); - mScreenToWorld.accumPostTranslation(translation); - this->initRay(nearPlane, farPlane); - } - - virtual ~BaseCamera() {} - - Film::RGBA& pixel(size_t i, size_t j) { return mFilm->pixel(i, j); } - - size_t width() const { return mFilm->width(); } - size_t height() const { return mFilm->height(); } - - /// Rotate the camera so its negative z-axis points at xyz and its - /// y axis is in the plane of the xyz and up vectors. In other - /// words the camera will look at xyz and use up as the - /// horizontal direction. - void lookAt(const Vec3R& xyz, const Vec3R& up = Vec3R(0.0, 1.0, 0.0)) - { - const Vec3R orig = mScreenToWorld.applyMap(Vec3R(0.0)); - const Vec3R dir = orig - xyz; - try { - Mat4d xform = math::aim(dir, up); - xform.postTranslate(orig); - mScreenToWorld = math::AffineMap(xform); - this->initRay(mRay.t0(), mRay.t1()); - } catch (...) {} - } - - Vec3R rasterToScreen(double i, double j, double z) const - { - return Vec3R( (2 * i / double(mFilm->width()) - 1) * mScaleWidth, - (1 - 2 * j / double(mFilm->height())) * mScaleHeight, z ); - } - - /// @brief Return a Ray in world space given the pixel indices and - /// optional offsets in the range [0, 1]. An offset of 0.5 corresponds - /// to the center of the pixel. - virtual math::Ray getRay( - size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const = 0; - -protected: - void initRay(double t0, double t1) - { - mRay.setTimes(t0, t1); - mRay.setEye(mScreenToWorld.applyMap(Vec3R(0.0))); - mRay.setDir(mScreenToWorld.applyJacobian(Vec3R(0.0, 0.0, -1.0))); - } - - Film* mFilm; - double mScaleWidth, mScaleHeight; - math::Ray mRay; - math::AffineMap mScreenToWorld; -};// BaseCamera - - -class PerspectiveCamera: public BaseCamera -{ - public: - /// @brief Constructor - /// @param film film (i.e. image) defining the pixel resolution - /// @param rotation rotation in degrees of the camera in world space - /// (applied in x, y, z order) - /// @param translation translation of the camera in world-space units, - /// applied after rotation - /// @param focalLength focal length of the camera in mm - /// (the default of 50mm corresponds to Houdini's default camera) - /// @param aperture width in mm of the frame, i.e., the visible field - /// (the default 41.2136 mm corresponds to Houdini's default camera) - /// @param nearPlane depth of the near clipping plane in world-space units - /// @param farPlane depth of the far clipping plane in world-space units - /// - /// @details If no rotation or translation is provided, the camera is placed - /// at (0,0,0) in world space and points in the direction of the negative z axis. - PerspectiveCamera(Film& film, - const Vec3R& rotation = Vec3R(0.0), - const Vec3R& translation = Vec3R(0.0), - double focalLength = 50.0, - double aperture = 41.2136, - double nearPlane = 1e-3, - double farPlane = std::numeric_limits::max()) - : BaseCamera(film, rotation, translation, 0.5*aperture/focalLength, nearPlane, farPlane) - { - } - - virtual ~PerspectiveCamera() {} - - /// @brief Return a Ray in world space given the pixel indices and - /// optional offsets in the range [0,1]. An offset of 0.5 corresponds - /// to the center of the pixel. - virtual math::Ray getRay( - size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const - { - math::Ray ray(mRay); - Vec3R dir = BaseCamera::rasterToScreen(Real(i) + iOffset, Real(j) + jOffset, -1.0); - dir = BaseCamera::mScreenToWorld.applyJacobian(dir); - dir.normalize(); - ray.scaleTimes(1.0/dir.dot(ray.dir())); - ray.setDir(dir); - return ray; - } - - /// @brief Return the horizontal field of view in degrees given a - /// focal lenth in mm and the specified aperture in mm. - static double focalLengthToFieldOfView(double length, double aperture) - { - return 360.0 / M_PI * atan(aperture/(2.0*length)); - } - /// @brief Return the focal length in mm given a horizontal field of - /// view in degrees and the specified aperture in mm. - static double fieldOfViewToFocalLength(double fov, double aperture) - { - return aperture/(2.0*(tan(fov * M_PI / 360.0))); - } -};// PerspectiveCamera - - -class OrthographicCamera: public BaseCamera -{ -public: - /// @brief Constructor - /// @param film film (i.e. image) defining the pixel resolution - /// @param rotation rotation in degrees of the camera in world space - /// (applied in x, y, z order) - /// @param translation translation of the camera in world-space units, - /// applied after rotation - /// @param frameWidth width in of the frame in world-space units - /// @param nearPlane depth of the near clipping plane in world-space units - /// @param farPlane depth of the far clipping plane in world-space units - /// - /// @details If no rotation or translation is provided, the camera is placed - /// at (0,0,0) in world space and points in the direction of the negative z axis. - OrthographicCamera(Film& film, - const Vec3R& rotation = Vec3R(0.0), - const Vec3R& translation = Vec3R(0.0), - double frameWidth = 1.0, - double nearPlane = 1e-3, - double farPlane = std::numeric_limits::max()) - : BaseCamera(film, rotation, translation, 0.5*frameWidth, nearPlane, farPlane) - { - } - virtual ~OrthographicCamera() {} - - virtual math::Ray getRay( - size_t i, size_t j, double iOffset = 0.5, double jOffset = 0.5) const - { - math::Ray ray(mRay); - Vec3R eye = BaseCamera::rasterToScreen(Real(i) + iOffset, Real(j) + jOffset, 0.0); - ray.setEye(BaseCamera::mScreenToWorld.applyMap(eye)); - return ray; - } -};// OrthographicCamera - - -//////////////////////////////////////// SHADERS //////////////////////////////////////// - - -/// Abstract base class for the shaders -class BaseShader -{ -public: - typedef math::Ray RayT; - BaseShader() {} - virtual ~BaseShader() {} - /// @brief Defines the interface of the virtual function that returns a RGB color. - /// @param xyz World position of the intersection point. - /// @param nml Normal in world space at the intersection point. - /// @param dir Direction of the ray in world space. - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R& nml, const Vec3R& dir) const = 0; - virtual BaseShader* copy() const = 0; -}; - - -/// @brief Shader that produces a simple matte. -/// -/// @details The color can either be constant (if GridT = -/// Film::RGBA which is the default) or defined in a seperate Vec3 -/// color grid. Use SamplerType to define the order of interpolation -/// (default is zero order, i.e. closes-point). -template -class MatteShader: public BaseShader -{ -public: - MatteShader(const GridT& grid) : mAcc(grid.getAccessor()), mXform(&grid.transform()) {} - virtual ~MatteShader() {} - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const - { - typename GridT::ValueType v = zeroVal(); - SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v); - return Film::RGBA( - static_cast(v[0]), - static_cast(v[1]), - static_cast(v[2])); - } - virtual BaseShader* copy() const { return new MatteShader(*this); } - -private: - typename GridT::ConstAccessor mAcc; - const math::Transform* mXform; -}; -// Template specialization using a constant color of the material. -template -class MatteShader: public BaseShader -{ -public: - MatteShader(const Film::RGBA& c = Film::RGBA(1.0f)): mRGBA(c) {} - virtual ~MatteShader() {} - virtual Film::RGBA operator()(const Vec3R&, const Vec3R&, const Vec3R&) const - { - return mRGBA; - } - virtual BaseShader* copy() const { return new MatteShader(*this); } - -private: - const Film::RGBA mRGBA; -}; - - -/// @brief Color shader that treats the surface normal (x, y, z) as an -/// RGB color. -/// -/// @details The color can either be constant (if GridT = -/// Film::RGBA which is the default) or defined in a seperate Vec3 -/// color grid. Use SamplerType to define the order of interpolation -/// (default is zero order, i.e. closes-point). -template -class NormalShader: public BaseShader -{ -public: - NormalShader(const GridT& grid) : mAcc(grid.getAccessor()), mXform(&grid.transform()) {} - virtual ~NormalShader() {} - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R& normal, const Vec3R&) const - { - typename GridT::ValueType v = zeroVal(); - SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v); - return Film::RGBA(v[0]*(normal[0]+1.0f), v[1]*(normal[1]+1.0f), v[2]*(normal[2]+1.0f)); - } - virtual BaseShader* copy() const { return new NormalShader(*this); } - -private: - typename GridT::ConstAccessor mAcc; - const math::Transform* mXform; -}; -// Template specialization using a constant color of the material. -template -class NormalShader: public BaseShader -{ -public: - NormalShader(const Film::RGBA& c = Film::RGBA(1.0f)) : mRGBA(c*0.5f) {} - virtual ~NormalShader() {} - virtual Film::RGBA operator()(const Vec3R&, const Vec3R& normal, const Vec3R&) const - { - return mRGBA*Film::RGBA(normal[0]+1.0f, normal[1]+1.0f, normal[2]+1.0f); - } - virtual BaseShader* copy() const { return new NormalShader(*this); } - -private: - const Film::RGBA mRGBA; -}; - - -/// @brief Color shader that treats position (x, y, z) as an RGB color in a -/// cube defined from an axis-aligned bounding box in world space. -/// -/// @details The color can either be constant (if GridT = -/// Film::RGBA which is the default) or defined in a seperate Vec3 -/// color grid. Use SamplerType to define the order of interpolation -/// (default is zero order, i.e. closes-point). -template -class PositionShader: public BaseShader -{ -public: - PositionShader(const math::BBox& bbox, const GridT& grid) - : mMin(bbox.min()) - , mInvDim(1.0/bbox.extents()) - , mAcc(grid.getAccessor()) - , mXform(&grid.transform()) - { - } - virtual ~PositionShader() {} - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const - { - typename GridT::ValueType v = zeroVal(); - SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v); - const Vec3R rgb = (xyz - mMin)*mInvDim; - return Film::RGBA(v[0],v[1],v[2]) * Film::RGBA(rgb[0], rgb[1], rgb[2]); - } - virtual BaseShader* copy() const { return new PositionShader(*this); } - -private: - const Vec3R mMin, mInvDim; - typename GridT::ConstAccessor mAcc; - const math::Transform* mXform; -}; -// Template specialization using a constant color of the material. -template -class PositionShader: public BaseShader -{ -public: - PositionShader(const math::BBox& bbox, const Film::RGBA& c = Film::RGBA(1.0f)) - : mMin(bbox.min()), mInvDim(1.0/bbox.extents()), mRGBA(c) {} - virtual ~PositionShader() {} - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R&, const Vec3R&) const - { - const Vec3R rgb = (xyz - mMin)*mInvDim; - return mRGBA*Film::RGBA(rgb[0], rgb[1], rgb[2]); - } - virtual BaseShader* copy() const { return new PositionShader(*this); } - -private: - const Vec3R mMin, mInvDim; - const Film::RGBA mRGBA; -}; - -/// @brief Simple diffuse Lambertian surface shader. -/// -/// @details The diffuse color can either be constant (if GridT = -/// Film::RGBA which is the default) or defined in a seperate Vec3 -/// color grid. Lambertian implies that the (radiant) intensity is -/// directly proportional to the cosine of the angle between the -/// surface normal and the direction of the light source. Use -/// SamplerType to define the order of interpolation (default is -/// zero order, i.e. closes-point). -template -class DiffuseShader: public BaseShader -{ -public: - DiffuseShader(const GridT& grid): mAcc(grid.getAccessor()), mXform(&grid.transform()) {} - virtual ~DiffuseShader() {} - virtual Film::RGBA operator()(const Vec3R& xyz, const Vec3R& normal, const Vec3R& rayDir) const - { - typename GridT::ValueType v = zeroVal(); - SamplerType::sample(mAcc, mXform->worldToIndex(xyz), v); - // We take the abs of the dot product corresponding to having - // light sources at +/- rayDir, i.e., two-sided shading. - return Film::RGBA(v[0],v[1],v[2]) * math::Abs(normal.dot(rayDir)); - } - virtual BaseShader* copy() const { return new DiffuseShader(*this); } - -private: - typename GridT::ConstAccessor mAcc; - const math::Transform* mXform; -}; -// Template specialization using a constant color of the material. -template -class DiffuseShader: public BaseShader -{ -public: - DiffuseShader(const Film::RGBA& d = Film::RGBA(1.0f)): mRGBA(d) {} - virtual ~DiffuseShader() {} - virtual Film::RGBA operator()(const Vec3R&, const Vec3R& normal, const Vec3R& rayDir) const - { - // We assume a single directional light source at the camera, - // so the cosine of the angle between the surface normal and the - // direction of the light source becomes the dot product of the - // surface normal and inverse direction of the ray. We also ignore - // negative dot products, corresponding to strict one-sided shading. - //return mRGBA * math::Max(0.0, normal.dot(-rayDir)); - - // We take the abs of the dot product corresponding to having - // light sources at +/- rayDir, i.e., two-sided shading. - return mRGBA * math::Abs(normal.dot(rayDir)); - } - virtual BaseShader* copy() const { return new DiffuseShader(*this); } - -private: - const Film::RGBA mRGBA; -}; - -//////////////////////////////////////// RAYTRACER //////////////////////////////////////// - -template -inline void rayTrace(const GridT& grid, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples, - unsigned int seed, - bool threaded) -{ - LevelSetRayTracer > - tracer(grid, shader, camera, pixelSamples, seed); - tracer.render(threaded); -} - - -template -inline void rayTrace(const GridT&, - const IntersectorT& inter, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples, - unsigned int seed, - bool threaded) -{ - LevelSetRayTracer tracer(inter, shader, camera, pixelSamples, seed); - tracer.render(threaded); -} - - -//////////////////////////////////////// LevelSetRayTracer //////////////////////////////////////// - - -template -inline LevelSetRayTracer:: -LevelSetRayTracer(const GridT& grid, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples, - unsigned int seed) - : mIsMaster(true), - mRand(NULL), - mInter(grid), - mShader(shader.copy()), - mCamera(&camera) -{ - this->setPixelSamples(pixelSamples, seed); -} - -template -inline LevelSetRayTracer:: -LevelSetRayTracer(const IntersectorT& inter, - const BaseShader& shader, - BaseCamera& camera, - size_t pixelSamples, - unsigned int seed) - : mIsMaster(true), - mRand(NULL), - mInter(inter), - mShader(shader.copy()), - mCamera(&camera) -{ - this->setPixelSamples(pixelSamples, seed); -} - -template -inline LevelSetRayTracer:: -LevelSetRayTracer(const LevelSetRayTracer& other) : - mIsMaster(false), - mRand(other.mRand), - mInter(other.mInter), - mShader(other.mShader->copy()), - mCamera(other.mCamera), - mSubPixels(other.mSubPixels) -{ -} - -template -inline LevelSetRayTracer:: -~LevelSetRayTracer() -{ - if (mIsMaster) delete [] mRand; -} - -template -inline void LevelSetRayTracer:: -setGrid(const GridT& grid) -{ - assert(mIsMaster); - mInter = IntersectorT(grid); -} - -template -inline void LevelSetRayTracer:: -setIntersector(const IntersectorT& inter) -{ - assert(mIsMaster); - mInter = inter; -} - -template -inline void LevelSetRayTracer:: -setShader(const BaseShader& shader) -{ - assert(mIsMaster); - mShader.reset(shader.copy()); -} - -template -inline void LevelSetRayTracer:: -setCamera(BaseCamera& camera) -{ - assert(mIsMaster); - mCamera = &camera; -} - -template -inline void LevelSetRayTracer:: -setPixelSamples(size_t pixelSamples, unsigned int seed) -{ - assert(mIsMaster); - if (pixelSamples == 0) { - OPENVDB_THROW(ValueError, "pixelSamples must be larger then zero!"); - } - mSubPixels = pixelSamples - 1; - delete [] mRand; - if (mSubPixels > 0) { - mRand = new double[16]; - math::Rand01 rand(seed);//offsets for anti-aliaing by jittered super-sampling - for (size_t i=0; i<16; ++i) mRand[i] = rand(); - } else { - mRand = NULL; - } -} - -template -inline void LevelSetRayTracer:: -render(bool threaded) const -{ - tbb::blocked_range range(0, mCamera->height()); - threaded ? tbb::parallel_for(range, *this) : (*this)(range); -} - -template -inline void LevelSetRayTracer:: -operator()(const tbb::blocked_range& range) const -{ - const BaseShader& shader = *mShader; - Vec3Type xyz, nml; - const float frac = 1.0f / (1.0f + mSubPixels); - for (size_t j=range.begin(), n=0, je = range.end(); jwidth(); ipixel(i,j); - RayType ray = mCamera->getRay(i, j);//primary ray - Film::RGBA c = mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg; - for (size_t k=0; kgetRay(i, j, mRand[n & 15], mRand[(n+1) & 15]); - c += mInter.intersectsWS(ray, xyz, nml) ? shader(xyz, nml, ray.dir()) : bg; - }//loop over sub-pixels - bg = c*frac; - }//loop over image height - }//loop over image width -} - -//////////////////////////////////////// VolumeRender //////////////////////////////////////// - -template -inline VolumeRender:: -VolumeRender(const IntersectorT& inter, BaseCamera& camera) - : mAccessor(inter.grid().getConstAccessor()) - , mCamera(&camera) - , mPrimary(new IntersectorT(inter)) - , mShadow(new IntersectorT(inter)) - , mPrimaryStep(1.0) - , mShadowStep(3.0) - , mCutOff(0.005) - , mLightGain(0.2) - , mLightDir(Vec3R(0.3, 0.3, 0).unit()) - , mLightColor(0.7, 0.7, 0.7) - , mAbsorption(0.1) - , mScattering(1.5) -{ -} - -template -inline VolumeRender:: -VolumeRender(const VolumeRender& other) - : mAccessor(other.mAccessor) - , mCamera(other.mCamera) - , mPrimary(new IntersectorT(*(other.mPrimary))) - , mShadow(new IntersectorT(*(other.mShadow))) - , mPrimaryStep(other.mPrimaryStep) - , mShadowStep(other.mShadowStep) - , mCutOff(other.mCutOff) - , mLightGain(other.mLightGain) - , mLightDir(other.mLightDir) - , mLightColor(other.mLightColor) - , mAbsorption(other.mAbsorption) - , mScattering(other.mScattering) -{ -} - -template -inline void VolumeRender:: -print(std::ostream& os, int verboseLevel) -{ - if (verboseLevel>0) { - os << "\nPrimary step: " << mPrimaryStep - << "\nShadow step: " << mShadowStep - << "\nCutoff: " << mCutOff - << "\nLightGain: " << mLightGain - << "\nLightDir: " << mLightDir - << "\nLightColor: " << mLightColor - << "\nAbsorption: " << mAbsorption - << "\nScattering: " << mScattering << std::endl; - } - mPrimary->print(os, verboseLevel); -} - -template -inline void VolumeRender:: -setIntersector(const IntersectorT& inter) -{ - mPrimary.reset(new IntersectorT(inter)); - mShadow.reset( new IntersectorT(inter)); -} - -template -inline void VolumeRender:: -render(bool threaded) const -{ - tbb::blocked_range range(0, mCamera->height()); - threaded ? tbb::parallel_for(range, *this) : (*this)(range); -} - -template -inline void VolumeRender:: -operator()(const tbb::blocked_range& range) const -{ - SamplerType sampler(mAccessor, mShadow->grid().transform());//light-weight wrapper - - // Any variable prefixed with p (or s) means it's associate with a primay (or shadow) ray - const Vec3R extinction = -mScattering-mAbsorption, One(1.0); - const Vec3R albedo = mLightColor*mScattering/(mScattering+mAbsorption);//single scattering - const Real sGain = mLightGain;//in-scattering along shadow ray - const Real pStep = mPrimaryStep;//Integration step along primary ray in voxel units - const Real sStep = mShadowStep;//Integration step along shadow ray in voxel units - const Real cutoff = mCutOff;//Cutoff for density and transmittance - - // For the sake of completeness we show how to use two different - // methods (hits/march) in VolumeRayIntersector that produce - // segments along the ray that intersects active values. Comment out - // the line below to use VolumeRayIntersector::march instead of - // VolumeRayIntersector::hits. -#define USE_HITS -#ifdef USE_HITS - std::vector pTS, sTS; - //std::deque pTS, sTS; -#endif - - RayType sRay(Vec3R(0), mLightDir);//Shadow ray - for (size_t j=range.begin(), je = range.end(); jwidth(); ipixel(i, j); - bg.a = bg.r = bg.g = bg.b = 0; - RayType pRay = mCamera->getRay(i, j);// Primary ray - if( !mPrimary->setWorldRay(pRay)) continue; - Vec3R pTrans(1.0), pLumi(0.0); -#ifndef USE_HITS - Real pT0, pT1; - while (mPrimary->march(pT0, pT1)) { - for (Real pT = pStep*ceil(pT0/pStep); pT <= pT1; pT += pStep) { -#else - mPrimary->hits(pTS); - for (size_t k=0; kgetWorldPos(pT); - const Real density = sampler.wsSample(pPos); - if (density < cutoff) continue; - const Vec3R dT = math::Exp(extinction * density * pStep); - Vec3R sTrans(1.0); - sRay.setEye(pPos); - if( !mShadow->setWorldRay(sRay)) continue; -#ifndef USE_HITS - Real sT0, sT1; - while (mShadow->march(sT0, sT1)) { - for (Real sT = sStep*ceil(sT0/sStep); sT <= sT1; sT+= sStep) { -#else - mShadow->hits(sTS); - for (size_t l=0; lgetWorldPos(sT)); - if (d < cutoff) continue; - sTrans *= math::Exp(extinction * d * sStep/(1.0+sT*sGain)); - if (sTrans.lengthSqr()(pLumi[0]); - bg.g = static_cast(pLumi[1]); - bg.b = static_cast(pLumi[2]); - bg.a = static_cast(1.0f - pTrans.sum()/3.0f); - }//Horizontal pixel scan - }//Vertical pixel scan -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_RAYTRACER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/SignedFloodFill.h b/openvdb_3_0_0_library/tools/SignedFloodFill.h deleted file mode 100755 index 911e2c4..0000000 --- a/openvdb_3_0_0_library/tools/SignedFloodFill.h +++ /dev/null @@ -1,298 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file SignedFloodFill.h -/// -/// @brief Propagates the sign of distance values from the active -/// voxels in the narrow band to the inactive values outside the -/// narrow band. -/// -/// @author Ken Museth - -#ifndef OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_SIGNEDFLOODFILL_HAS_BEEN_INCLUDED - -#include -#include // for math::negative -#include // for Index typedef -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Set the values of all inactive voxels and tiles of a narrow-band -/// level set from the signs of the active voxels, setting outside values to -/// +background and inside values to -background. -/// -/// @warning This method should only be used on closed, symmetric narrow-band level sets. -/// -/// @note If a LeafManager is used the cached leaf nodes are reused, -/// resulting in slightly better overall performance. -/// -/// @param tree Tree or LeafManager that will be flood filled. -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -/// -/// @throw TypeError if the ValueType of @a tree is not floating-point. -template -inline void -signedFloodFill(TreeOrLeafManagerT& tree, bool threaded = true, size_t grainSize = 1); - - -/// @brief Set the values of all inactive voxels and tiles of a narrow-band -/// level set from the signs of the active voxels, setting exterior values to -/// @a outsideWidth and interior values to @a insideWidth. Set the background value -/// of this tree to @a outsideWidth. -/// -/// @warning This method should only be used on closed, narrow-band level sets. -/// -/// @note If a LeafManager is used the cached leaf nodes are reused -/// resulting in slightly better overall performance. -/// -/// @param tree Tree or LeafManager that will be flood filled -/// @param outsideWidth the width of the outside of the narrow band -/// @param insideWidth the width of the inside of the narrow band -/// @param threaded enable or disable threading (threading is enabled by default) -/// @param grainSize used to control the threading granularity (default is 1) -/// -/// @throw TypeError if the ValueType of @a tree is not floating-point. -template -inline void -signedFloodFillWithValues( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& outsideWidth, - const typename TreeOrLeafManagerT::ValueType& insideWidth, - bool threaded = true, - size_t grainSize = 1); - - -////////////////////////// Implementation of SignedFloodFill //////////////////////////// - - -template -class SignedFloodFillOp -{ -public: - typedef typename TreeOrLeafManagerT::ValueType ValueT; - typedef typename TreeOrLeafManagerT::RootNodeType RootT; - typedef typename TreeOrLeafManagerT::LeafNodeType LeafT; - BOOST_STATIC_ASSERT(boost::is_floating_point::value); - - SignedFloodFillOp(const TreeOrLeafManagerT& tree) - : mOutside(math::Abs(tree.background())) - , mInside(math::negative(mOutside)) - { - } - - SignedFloodFillOp(const TreeOrLeafManagerT& tree, const ValueT& background) - : mOutside(math::Abs(background)) - , mInside(math::negative(mOutside)) - { - } - - SignedFloodFillOp(ValueT outsideValue, ValueT insideValue) - : mOutside(math::Abs(outsideValue)) - , mInside(math::negative(math::Abs(insideValue))) - { - } - - // Nothing to do at the leaf node level - void operator()(LeafT& leaf) const - { -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!leaf.allocate()) return;//this assures that the buffer is allocated and in-memory -#endif - const typename LeafT::NodeMaskType& valueMask = leaf.getValueMask(); - // WARNING: "Never do what you're about to see at home, we're what you call experts!" - typename LeafT::ValueType* buffer = - const_cast(&(leaf.getFirstValue())); - - const Index first = valueMask.findFirstOn(); - if (first < LeafT::SIZE) { - bool xInside = buffer[first]<0, yInside = xInside, zInside = xInside; - for (Index x = 0; x != (1 << LeafT::LOG2DIM); ++x) { - const Index x00 = x << (2 * LeafT::LOG2DIM); - if (valueMask.isOn(x00)) xInside = buffer[x00] < 0; // element(x, 0, 0) - yInside = xInside; - for (Index y = 0; y != (1 << LeafT::LOG2DIM); ++y) { - const Index xy0 = x00 + (y << LeafT::LOG2DIM); - if (valueMask.isOn(xy0)) yInside = buffer[xy0] < 0; // element(x, y, 0) - zInside = yInside; - for (Index z = 0; z != (1 << LeafT::LOG2DIM); ++z) { - const Index xyz = xy0 + z; // element(x, y, z) - if (valueMask.isOn(xyz)) { - zInside = buffer[xyz] < 0; - } else { - buffer[xyz] = zInside ? mInside : mOutside; - } - } - } - } - } else {// if no active voxels exist simply use the sign of the first value - leaf.fill(buffer[0] < 0 ? mInside : mOutside); - } - } - - // Prune the child nodes of the internal nodes - template - void operator()(NodeT& node) const - { - // We assume the child nodes have already been flood filled! - const typename NodeT::NodeMaskType& childMask = node.getChildMask(); - // WARNING: "Never do what you're about to see at home, we're what you call experts!" - typename NodeT::UnionType* table = const_cast(node.getTable()); - - const Index first = childMask.findFirstOn(); - if (first < NodeT::NUM_VALUES) { - bool xInside = table[first].getChild()->getFirstValue()<0; - bool yInside = xInside, zInside = xInside; - for (Index x = 0; x != (1 << NodeT::LOG2DIM); ++x) { - const int x00 = x << (2 * NodeT::LOG2DIM); // offset for block(x, 0, 0) - if (childMask.isOn(x00)) xInside = table[x00].getChild()->getLastValue()<0; - yInside = xInside; - for (Index y = 0; y != (1 << NodeT::LOG2DIM); ++y) { - const Index xy0 = x00 + (y << NodeT::LOG2DIM); // offset for block(x, y, 0) - if (childMask.isOn(xy0)) yInside = table[xy0].getChild()->getLastValue()<0; - zInside = yInside; - for (Index z = 0; z != (1 << NodeT::LOG2DIM); ++z) { - const Index xyz = xy0 + z; // offset for block(x, y, z) - if (childMask.isOn(xyz)) { - zInside = table[xyz].getChild()->getLastValue()<0; - } else { - table[xyz].setValue(zInside ? mInside : mOutside); - } - } - } - } - } else {//no child nodes exist simply use the sign of the first tile value. - const ValueT v = table[0].getValue()<0 ? mInside : mOutside; - for (Index i = 0; i < NodeT::NUM_VALUES; ++i) table[i].setValue(v); - } - } - - // Prune the child nodes of the root node - void operator()(RootT& root) const - { - typedef typename RootT::ChildNodeType ChildT; - // Insert the child nodes into a map sorted according to their origin - std::map nodeKeys; - typename RootT::ChildOnIter it = root.beginChildOn(); - for (; it; ++it) nodeKeys.insert(std::pair(it.getCoord(), &(*it))); - static const Index DIM = RootT::ChildNodeType::DIM; - - // We employ a simple z-scanline algorithm that inserts inactive tiles with - // the inside value if they are sandwiched between inside child nodes only! - typename std::map::const_iterator b = nodeKeys.begin(), e = nodeKeys.end(); - if ( b == e ) return; - for (typename std::map::const_iterator a = b++; b != e; ++a, ++b) { - Coord d = b->first - a->first; // delta of neighboring coordinates - if (d[0]!=0 || d[1]!=0 || d[2]==Int32(DIM)) continue;// not same z-scanline or neighbors - const ValueT fill[] = { a->second->getLastValue(), b->second->getFirstValue() }; - if (!(fill[0] < 0) || !(fill[1] < 0)) continue; // scanline isn't inside - Coord c = a->first + Coord(0u, 0u, DIM); - for (; c[2] != b->first[2]; c[2] += DIM) root.addTile(c, mInside, false); - } - root.setBackground(mOutside, /*updateChildNodes=*/false); - } - -private: - const ValueT mOutside, mInside; -};// SignedFloodFillOp - - -template -inline -typename boost::enable_if::type>::type -doSignedFloodFill(TreeOrLeafManagerT& tree, - typename TreeOrLeafManagerT::ValueType outsideValue, - typename TreeOrLeafManagerT::ValueType insideValue, - bool threaded, - size_t grainSize) -{ - tree::NodeManager nodes(tree); - SignedFloodFillOp op(outsideValue, insideValue); - nodes.processBottomUp(op, threaded, grainSize); -} - -// Dummy (no-op) implementation for non-float types -template -inline -typename boost::disable_if::type>::type -doSignedFloodFill(TreeOrLeafManagerT&, - const typename TreeOrLeafManagerT::ValueType&, - const typename TreeOrLeafManagerT::ValueType&, - bool, - size_t) -{ - OPENVDB_THROW(TypeError, - "signedFloodFill is supported only for scalar, floating-point grids"); -} - - -// If the narrow-band is symmetric and unchanged -template -inline void -signedFloodFillWithValues( - TreeOrLeafManagerT& tree, - const typename TreeOrLeafManagerT::ValueType& outsideValue, - const typename TreeOrLeafManagerT::ValueType& insideValue, - bool threaded, - size_t grainSize) -{ - doSignedFloodFill(tree, outsideValue, insideValue, threaded, grainSize); -} - - -template -inline void -signedFloodFill(TreeOrLeafManagerT& tree, - bool threaded, - size_t grainSize) -{ - const typename TreeOrLeafManagerT::ValueType v = tree.root().background(); - doSignedFloodFill(tree, v, math::negative(v), threaded, grainSize); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_RESETBACKGROUND_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/Statistics.h b/openvdb_3_0_0_library/tools/Statistics.h deleted file mode 100755 index c0d6f60..0000000 --- a/openvdb_3_0_0_library/tools/Statistics.h +++ /dev/null @@ -1,438 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Statistics.h -/// -/// @brief Functions to efficiently compute histograms, extremas -/// (min/max) and statistics (mean, variance, etc.) of grid values - -#ifndef OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include "ValueTransformer.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Iterate over a scalar grid and compute a histogram of the values -/// of the voxels that are visited, or iterate over a vector-valued grid -/// and compute a histogram of the magnitudes of the vectors. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param minVal the smallest value that can be added to the histogram -/// @param maxVal the largest value that can be added to the histogram -/// @param numBins the number of histogram bins -/// @param threaded if true, iterate over the grid in parallel -template -inline math::Histogram -histogram(const IterT& iter, double minVal, double maxVal, - size_t numBins = 10, bool threaded = true); - -/// @brief Iterate over a scalar grid and compute extrema (min/max) of the -/// values of the voxels that are visited, or iterate over a vector-valued grid -/// and compute extrema of the magnitudes of the vectors. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param threaded if true, iterate over the grid in parallel -template -inline math::Extrema -extrema(const IterT& iter, bool threaded = true); - -/// @brief Iterate over a scalar grid and compute statistics (mean, variance, etc.) -/// of the values of the voxels that are visited, or iterate over a vector-valued grid -/// and compute statistics of the magnitudes of the vectors. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param threaded if true, iterate over the grid in parallel -template -inline math::Stats -statistics(const IterT& iter, bool threaded = true); - -/// @brief Iterate over a grid and compute extremas (min/max) of -/// the values produced by applying the given functor at each voxel that is visited. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param op a functor of the form void op(const IterT&, math::Stats&), -/// where @c IterT is the type of @a iter, that inserts zero or more -/// floating-point values into the provided @c math::Stats object -/// @param threaded if true, iterate over the grid in parallel -/// @note When @a threaded is true, each thread gets its own copy of the functor. -/// -/// @par Example: -/// Compute statistics of just the active and positive-valued voxels of a scalar, -/// floating-point grid. -/// @code -/// struct Local { -/// static inline -/// void addIfPositive(const FloatGrid::ValueOnCIter& iter, math::Extrema& ex) -/// { -/// const float f = *iter; -/// if (f > 0.0) { -/// if (iter.isVoxelValue()) ex.add(f); -/// else ex.add(f, iter.getVoxelCount()); -/// } -/// } -/// }; -/// FloatGrid grid = ...; -/// math::Extrema stats = -/// tools::extrema(grid.cbeginValueOn(), Local::addIfPositive, /*threaded=*/true); -/// @endcode -template -inline math::Extrema -extrema(const IterT& iter, const ValueOp& op, bool threaded); - -/// @brief Iterate over a grid and compute statistics (mean, variance, etc.) of -/// the values produced by applying the given functor at each voxel that is visited. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param op a functor of the form void op(const IterT&, math::Stats&), -/// where @c IterT is the type of @a iter, that inserts zero or more -/// floating-point values into the provided @c math::Stats object -/// @param threaded if true, iterate over the grid in parallel -/// @note When @a threaded is true, each thread gets its own copy of the functor. -/// -/// @par Example: -/// Compute statistics of just the active and positive-valued voxels of a scalar, -/// floating-point grid. -/// @code -/// struct Local { -/// static inline -/// void addIfPositive(const FloatGrid::ValueOnCIter& iter, math::Stats& stats) -/// { -/// const float f = *iter; -/// if (f > 0.0) { -/// if (iter.isVoxelValue()) stats.add(f); -/// else stats.add(f, iter.getVoxelCount()); -/// } -/// } -/// }; -/// FloatGrid grid = ...; -/// math::Stats stats = -/// tools::statistics(grid.cbeginValueOn(), Local::addIfPositive, /*threaded=*/true); -/// @endcode -template -inline math::Stats -statistics(const IterT& iter, const ValueOp& op, bool threaded); - - -/// @brief Iterate over a grid and compute statistics (mean, variance, etc.) -/// of the values produced by applying a given operator (see math/Operators.h) -/// at each voxel that is visited. -/// @param iter an iterator over the values of a grid or its tree -/// (@c Grid::ValueOnCIter, @c Tree::ValueOffIter, etc.) -/// @param op an operator object with a method of the form -/// double result(Accessor&, const Coord&) -/// @param threaded if true, iterate over the grid in parallel -/// @note World-space operators, whose @c result() methods are of the form -/// double result(const Map&, Accessor&, const Coord&), must be wrapped -/// in a math::MapAdapter. -/// @note Vector-valued operators like math::Gradient must be wrapped in an adapter -/// such as math::OpMagnitude. -/// -/// @par Example: -/// Compute statistics of the magnitude of the gradient at the active voxels of -/// a scalar, floating-point grid. (Note the use of the math::MapAdapter and -/// math::OpMagnitude adapters.) -/// @code -/// FloatGrid grid = ...; -/// -/// // Assume that we know that the grid has a uniform scale map. -/// typedef math::UniformScaleMap MapType; -/// // Specify a world-space gradient operator that uses first-order differencing. -/// typedef math::Gradient GradientOp; -/// // Wrap the operator with an adapter that computes the magnitude of the gradient. -/// typedef math::OpMagnitude MagnitudeOp; -/// // Wrap the operator with an adapter that associates a map with it. -/// typedef math::MapAdapter CompoundOp; -/// -/// if (MapType::Ptr map = grid.constTransform().constMap()) { -/// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), CompoundOp(*map)); -/// } -/// @endcode -/// -/// @par Example: -/// Compute statistics of the divergence at the active voxels of a vector-valued grid. -/// @code -/// Vec3SGrid grid = ...; -/// -/// // Assume that we know that the grid has a uniform scale map. -/// typedef math::UniformScaleMap MapType; -/// // Specify a world-space divergence operator that uses first-order differencing. -/// typedef math::Divergence DivergenceOp; -/// // Wrap the operator with an adapter that associates a map with it. -/// typedef math::MapAdapter CompoundOp; -/// -/// if (MapType::Ptr map = grid.constTransform().constMap()) { -/// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), CompoundOp(*map)); -/// } -/// @endcode -/// -/// @par Example: -/// As above, but computing the divergence in index space. -/// @code -/// Vec3SGrid grid = ...; -/// -/// // Specify an index-space divergence operator that uses first-order differencing. -/// typedef math::ISDivergence DivergenceOp; -/// -/// math::Stats stats = tools::opStatistics(grid.cbeginValueOn(), DivergenceOp()); -/// @endcode -template -inline math::Stats -opStatistics(const IterT& iter, const OperatorT& op = OperatorT(), bool threaded = true); - -/// @brief Same as opStatistics except it returns a math::Extrema vs a math::Stats -template -inline math::Extrema -opExtrema(const IterT& iter, const OperatorT& op = OperatorT(), bool threaded = true); - -//////////////////////////////////////// - - -namespace stats_internal { - -/// @todo This traits class is needed because tree::TreeValueIteratorBase uses -/// the name ValueT for the type of the value to which the iterator points, -/// whereas node-level iterators use the name ValueType. -template -struct IterTraits { - typedef typename IterT::ValueType ValueType; -}; - -template -struct IterTraits > { - typedef typename tree::TreeValueIteratorBase::ValueT ValueType; -}; - - -// Helper class to compute a scalar value from either a scalar or a vector value -// (the latter by computing the vector's magnitude) -template struct GetValImpl; - -template -struct GetValImpl { - static inline double get(const T& val) { return double(val); } -}; - -template -struct GetValImpl { - static inline double get(const T& val) { return val.length(); } -}; - - -// Helper class to compute a scalar value from a tree or node iterator -// that points to a value in either a scalar or a vector grid, and to -// add that value to a math::Stats object. -template -struct GetVal -{ - typedef typename IterTraits::ValueType ValueT; - typedef GetValImpl::IsVec> ImplT; - - inline void operator()(const IterT& iter, StatsT& stats) const { - if (iter.isVoxelValue()) stats.add(ImplT::get(*iter)); - else stats.add(ImplT::get(*iter), iter.getVoxelCount()); - } -}; - -// Helper class to accumulate scalar voxel values or vector voxel magnitudes -// into a math::Stats object -template -struct StatsOp -{ - StatsOp(const ValueOp& op): getValue(op) {} - - // Accumulate voxel and tile values into this functor's Stats object. - inline void operator()(const IterT& iter) { getValue(iter, stats); } - - // Accumulate another functor's Stats object into this functor's. - inline void join(StatsOp& other) { stats.add(other.stats); } - - StatsT stats; - ValueOp getValue; -}; - - -// Helper class to accumulate scalar voxel values or vector voxel magnitudes -// into a math::Histogram object -template -struct HistOp -{ - HistOp(const ValueOp& op, double vmin, double vmax, size_t bins): - hist(vmin, vmax, bins), getValue(op) - {} - - // Accumulate voxel and tile values into this functor's Histogram object. - inline void operator()(const IterT& iter) { getValue(iter, hist); } - - // Accumulate another functor's Histogram object into this functor's. - inline void join(HistOp& other) { hist.add(other.hist); } - - math::Histogram hist; - ValueOp getValue; -}; - - -// Helper class to apply an operator such as math::Gradient or math::Laplacian -// to voxels and accumulate the scalar results or the magnitudes of vector results -// into a math::Stats object -template -struct MathOp -{ - typedef typename IterT::TreeT TreeT; - typedef typename TreeT::ValueType ValueT; - typedef typename tree::ValueAccessor ConstAccessor; - - // Each thread gets its own accessor and its own copy of the operator. - ConstAccessor mAcc; - OpT mOp; - StatsT mStats; - - template - static inline TreeT* THROW_IF_NULL(TreeT* ptr) { - if (ptr == NULL) OPENVDB_THROW(ValueError, "iterator references a null tree"); - return ptr; - } - - MathOp(const IterT& iter, const OpT& op): - mAcc(*THROW_IF_NULL(iter.getTree())), mOp(op) - {} - - // Accumulate voxel and tile values into this functor's Stats object. - void operator()(const IterT& it) - { - if (it.isVoxelValue()) { - // Add the magnitude of the gradient at a single voxel. - mStats.add(mOp.result(mAcc, it.getCoord())); - } else { - // Iterate over the voxels enclosed by a tile and add the results - // of applying the operator at each voxel. - /// @todo This could be specialized to be done more efficiently for some operators. - /// For example, all voxels in the interior of a tile (i.e., not on the borders) - /// have gradient zero, so there's no need to apply the operator to every voxel. - CoordBBox bbox = it.getBoundingBox(); - Coord xyz; - int &x = xyz.x(), &y = xyz.y(), &z = xyz.z(); - for (x = bbox.min().x(); x <= bbox.max().x(); ++x) { - for (y = bbox.min().y(); y <= bbox.max().y(); ++y) { - for (z = bbox.min().z(); z <= bbox.max().z(); ++z) { - mStats.add(mOp.result(mAcc, it.getCoord())); - } - } - } - } - } - - // Accumulate another functor's Stats object into this functor's. - inline void join(MathOp& other) { mStats.add(other.mStats); } -}; // struct MathOp - -} // namespace stats_internal - - -template -inline math::Histogram -histogram(const IterT& iter, double vmin, double vmax, size_t numBins, bool threaded) -{ - typedef stats_internal::GetVal ValueOp; - ValueOp valOp; - stats_internal::HistOp op(valOp, vmin, vmax, numBins); - tools::accumulate(iter, op, threaded); - return op.hist; -} - -template -inline math::Extrema -extrema(const IterT& iter, bool threaded) -{ - stats_internal::GetVal valOp; - return extrema(iter, valOp, threaded); -} - -template -inline math::Stats -statistics(const IterT& iter, bool threaded) -{ - stats_internal::GetVal valOp; - return statistics(iter, valOp, threaded); -} - -template -inline math::Extrema -extrema(const IterT& iter, const ValueOp& valOp, bool threaded) -{ - stats_internal::StatsOp op(valOp); - tools::accumulate(iter, op, threaded); - return op.stats; -} - -template -inline math::Stats -statistics(const IterT& iter, const ValueOp& valOp, bool threaded) -{ - stats_internal::StatsOp op(valOp); - tools::accumulate(iter, op, threaded); - return op.stats; -} - - -template -inline math::Extrema -opExtrema(const IterT& iter, const OperatorT& op, bool threaded) -{ - stats_internal::MathOp func(iter, op); - tools::accumulate(iter, func, threaded); - return func.mStats; -} - -template -inline math::Stats -opStatistics(const IterT& iter, const OperatorT& op, bool threaded) -{ - stats_internal::MathOp func(iter, op); - tools::accumulate(iter, func, threaded); - return func.mStats; -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_STATISTICS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/ValueTransformer.h b/openvdb_3_0_0_library/tools/ValueTransformer.h deleted file mode 100755 index d356d47..0000000 --- a/openvdb_3_0_0_library/tools/ValueTransformer.h +++ /dev/null @@ -1,707 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file ValueTransformer.h -/// -/// @author Peter Cucka -/// -/// tools::foreach() and tools::transformValues() transform the values in a grid -/// by iterating over the grid with a user-supplied iterator and applying a -/// user-supplied functor at each step of the iteration. With tools::foreach(), -/// the transformation is done in-place on the input grid, whereas with -/// tools::transformValues(), transformed values are written to an output grid -/// (which can, for example, have a different value type than the input grid). -/// Both functions can optionally transform multiple values of the grid in parallel. -/// -/// tools::accumulate() can be used to accumulate the results of applying a functor -/// at each step of a grid iteration. (The functor is responsible for storing and -/// updating intermediate results.) When the iteration is done serially the behavior is -/// the same as with tools::foreach(), but when multiple values are processed in parallel, -/// an additional step is performed: when any two threads finish processing, -/// @c op.join(otherOp) is called on one thread's functor to allow it to coalesce -/// its intermediate result with the other thread's. -/// -/// Finally, tools::setValueOnMin(), tools::setValueOnMax(), tools::setValueOnSum() -/// and tools::setValueOnMult() are wrappers around Tree::modifyValue() (or -/// ValueAccessor::modifyValue()) for some commmon in-place operations. -/// These are typically significantly faster than calling getValue() followed by setValue(). - -#ifndef OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED - -#include // for std::min(), std::max() -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// Iterate over a grid and at each step call @c op(iter). -/// @param iter an iterator over a grid or its tree (@c Grid::ValueOnCIter, -/// @c Tree::NodeIter, etc.) -/// @param op a functor of the form void op(const IterT&), where @c IterT is -/// the type of @a iter -/// @param threaded if true, transform multiple values of the grid in parallel -/// @param shareOp if true and @a threaded is true, all threads use the same functor; -/// otherwise, each thread gets its own copy of the @e original functor -/// -/// @par Example: -/// Multiply all values (both set and unset) of a scalar, floating-point grid by two. -/// @code -/// struct Local { -/// static inline void op(const FloatGrid::ValueAllIter& iter) { -/// iter.setValue(*iter * 2); -/// } -/// }; -/// FloatGrid grid = ...; -/// tools::foreach(grid.beginValueAll(), Local::op); -/// @endcode -/// -/// @par Example: -/// Rotate all active vectors of a vector grid by 45 degrees about the y axis. -/// @code -/// namespace { -/// struct MatMul { -/// math::Mat3s M; -/// MatMul(const math::Mat3s& mat): M(mat) {} -/// inline void operator()(const VectorGrid::ValueOnIter& iter) const { -/// iter.setValue(M.transform(*iter)); -/// } -/// }; -/// } -/// { -/// VectorGrid grid = ...; -/// tools::foreach(grid.beginValueOn(), -/// MatMul(math::rotation(math::Y, M_PI_4))); -/// } -/// @endcode -/// -/// @note For more complex operations that require finer control over threading, -/// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction -/// with a tree::IteratorRange that wraps a grid or tree iterator. -template -inline void foreach(const IterT& iter, XformOp& op, - bool threaded = true, bool shareOp = true); - -template -inline void foreach(const IterT& iter, const XformOp& op, - bool threaded = true, bool shareOp = true); - - -/// Iterate over a grid and at each step call op(iter, accessor) to -/// populate (via the accessor) the given output grid, whose @c ValueType -/// need not be the same as the input grid's. -/// @param inIter a non-const or (preferably) @c const iterator over an -/// input grid or its tree (@c Grid::ValueOnCIter, @c Tree::NodeIter, etc.) -/// @param outGrid an empty grid to be populated -/// @param op a functor of the form -/// void op(const InIterT&, OutGridT::ValueAccessor&), -/// where @c InIterT is the type of @a inIter -/// @param threaded if true, transform multiple values of the input grid in parallel -/// @param shareOp if true and @a threaded is true, all threads use the same functor; -/// otherwise, each thread gets its own copy of the @e original functor -/// @param merge how to merge intermediate results from multiple threads (see Types.h) -/// -/// @par Example: -/// Populate a scalar floating-point grid with the lengths of the vectors from all -/// active voxels of a vector-valued input grid. -/// @code -/// struct Local { -/// static void op( -/// const Vec3fGrid::ValueOnCIter& iter, -/// FloatGrid::ValueAccessor& accessor) -/// { -/// if (iter.isVoxelValue()) { // set a single voxel -/// accessor.setValue(iter.getCoord(), iter->length()); -/// } else { // fill an entire tile -/// CoordBBox bbox; -/// iter.getBoundingBox(bbox); -/// accessor.getTree()->fill(bbox, iter->length()); -/// } -/// } -/// }; -/// Vec3fGrid inGrid = ...; -/// FloatGrid outGrid; -/// tools::transformValues(inGrid.cbeginValueOn(), outGrid, Local::op); -/// @endcode -/// -/// @note For more complex operations that require finer control over threading, -/// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction -/// with a tree::IteratorRange that wraps a grid or tree iterator. -template -inline void transformValues(const InIterT& inIter, OutGridT& outGrid, - XformOp& op, bool threaded = true, bool shareOp = true, - MergePolicy merge = MERGE_ACTIVE_STATES); - -#ifndef _MSC_VER -template -inline void transformValues(const InIterT& inIter, OutGridT& outGrid, - const XformOp& op, bool threaded = true, bool shareOp = true, - MergePolicy merge = MERGE_ACTIVE_STATES); -#endif - - -/// Iterate over a grid and at each step call @c op(iter). If threading is enabled, -/// call @c op.join(otherOp) to accumulate intermediate results from pairs of threads. -/// @param iter an iterator over a grid or its tree (@c Grid::ValueOnCIter, -/// @c Tree::NodeIter, etc.) -/// @param op a functor with a join method of the form void join(XformOp&) -/// and a call method of the form void op(const IterT&), -/// where @c IterT is the type of @a iter -/// @param threaded if true, transform multiple values of the grid in parallel -/// @note If @a threaded is true, each thread gets its own copy of the @e original functor. -/// The order in which threads are joined is unspecified. -/// @note If @a threaded is false, the join method is never called. -/// -/// @par Example: -/// Compute the average of the active values of a scalar, floating-point grid -/// using the math::Stats class. -/// @code -/// namespace { -/// struct Average { -/// math::Stats stats; -/// -/// // Accumulate voxel and tile values into this functor's Stats object. -/// inline void operator()(const FloatGrid::ValueOnCIter& iter) { -/// if (iter.isVoxelValue()) stats.add(*iter); -/// else stats.add(*iter, iter.getVoxelCount()); -/// } -/// -/// // Accumulate another functor's Stats object into this functor's. -/// inline void join(Average& other) { stats.add(other.stats); } -/// -/// // Return the cumulative result. -/// inline double average() const { return stats.mean(); } -/// }; -/// } -/// { -/// FloatGrid grid = ...; -/// Average op; -/// tools::accumulate(grid.cbeginValueOn(), op); -/// double average = op.average(); -/// } -/// @endcode -/// -/// @note For more complex operations that require finer control over threading, -/// consider using @c tbb::parallel_for() or @c tbb::parallel_reduce() in conjunction -/// with a tree::IteratorRange that wraps a grid or tree iterator. -template -inline void accumulate(const IterT& iter, XformOp& op, bool threaded = true); - - -/// @brief Set the value of the voxel at the given coordinates in @a tree to -/// the minimum of its current value and @a value, and mark the voxel as active. -/// @details This is typically significantly faster than calling getValue() -/// followed by setValueOn(). -/// @note @a TreeT can be either a Tree or a ValueAccessor. -template -inline void setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); - -/// @brief Set the value of the voxel at the given coordinates in @a tree to -/// the maximum of its current value and @a value, and mark the voxel as active. -/// @details This is typically significantly faster than calling getValue() -/// followed by setValueOn(). -/// @note @a TreeT can be either a Tree or a ValueAccessor. -template -inline void setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); - -/// @brief Set the value of the voxel at the given coordinates in @a tree to -/// the sum of its current value and @a value, and mark the voxel as active. -/// @details This is typically significantly faster than calling getValue() -/// followed by setValueOn(). -/// @note @a TreeT can be either a Tree or a ValueAccessor. -template -inline void setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); - -/// @brief Set the value of the voxel at the given coordinates in @a tree to -/// the product of its current value and @a value, and mark the voxel as active. -/// @details This is typically significantly faster than calling getValue() -/// followed by setValueOn(). -/// @note @a TreeT can be either a Tree or a ValueAccessor. -template -inline void setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value); - - -//////////////////////////////////////// - - -namespace valxform { - -template -struct MinOp { - const ValueType val; - MinOp(const ValueType& v): val(v) {} - inline void operator()(ValueType& v) const { v = std::min(v, val); } -}; - -template -struct MaxOp { - const ValueType val; - MaxOp(const ValueType& v): val(v) {} - inline void operator()(ValueType& v) const { v = std::max(v, val); } -}; - -template -struct SumOp { - const ValueType val; - SumOp(const ValueType& v): val(v) {} - inline void operator()(ValueType& v) const { v += val; } -}; - -template -struct MultOp { - const ValueType val; - MultOp(const ValueType& v): val(v) {} - inline void operator()(ValueType& v) const { v *= val; } -}; - -} - - -template -inline void -setValueOnMin(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) -{ - tree.modifyValue(xyz, valxform::MinOp(value)); -} - - -template -inline void -setValueOnMax(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) -{ - tree.modifyValue(xyz, valxform::MaxOp(value)); -} - - -template -inline void -setValueOnSum(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) -{ - tree.modifyValue(xyz, valxform::SumOp(value)); -} - - -template -inline void -setValueOnMult(TreeT& tree, const Coord& xyz, const typename TreeT::ValueType& value) -{ - tree.modifyValue(xyz, valxform::MultOp(value)); -} - - -//////////////////////////////////////// - - -namespace valxform { - -template -class SharedOpApplier -{ -public: - typedef typename tree::IteratorRange IterRange; - - SharedOpApplier(const IterT& iter, OpT& op): mIter(iter), mOp(op) {} - - void process(bool threaded = true) - { - IterRange range(mIter); - if (threaded) { - tbb::parallel_for(range, *this); - } else { - (*this)(range); - } - } - - void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); } - -private: - IterT mIter; - OpT& mOp; -}; - - -template -class CopyableOpApplier -{ -public: - typedef typename tree::IteratorRange IterRange; - - CopyableOpApplier(const IterT& iter, const OpT& op): mIter(iter), mOp(op), mOrigOp(&op) {} - - // When splitting this task, give the subtask a copy of the original functor, - // not of this task's functor, which might have been modified arbitrarily. - CopyableOpApplier(const CopyableOpApplier& other): - mIter(other.mIter), mOp(*other.mOrigOp), mOrigOp(other.mOrigOp) {} - - void process(bool threaded = true) - { - IterRange range(mIter); - if (threaded) { - tbb::parallel_for(range, *this); - } else { - (*this)(range); - } - } - - void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); } - -private: - IterT mIter; - OpT mOp; // copy of original functor - OpT const * const mOrigOp; // pointer to original functor -}; - -} // namespace valxform - - -template -inline void -foreach(const IterT& iter, XformOp& op, bool threaded, bool shared) -{ - if (shared) { - typename valxform::SharedOpApplier proc(iter, op); - proc.process(threaded); - } else { - typedef typename valxform::CopyableOpApplier Processor; - Processor proc(iter, op); - proc.process(threaded); - } -} - -template -inline void -foreach(const IterT& iter, const XformOp& op, bool threaded, bool /*shared*/) -{ - // Const ops are shared across threads, not copied. - typename valxform::SharedOpApplier proc(iter, op); - proc.process(threaded); -} - - -//////////////////////////////////////// - - -namespace valxform { - -template -class SharedOpTransformer -{ -public: - typedef typename InIterT::TreeT InTreeT; - typedef typename tree::IteratorRange IterRange; - typedef typename OutTreeT::ValueType OutValueT; - - SharedOpTransformer(const InIterT& inIter, OutTreeT& outTree, OpT& op, MergePolicy merge): - mIsRoot(true), - mInputIter(inIter), - mInputTree(inIter.getTree()), - mOutputTree(&outTree), - mOp(op), - mMergePolicy(merge) - { - if (static_cast(mInputTree) == static_cast(mOutputTree)) { - OPENVDB_LOG_INFO("use tools::foreach(), not transformValues()," - " to transform a grid in place"); - } - } - - /// Splitting constructor - SharedOpTransformer(SharedOpTransformer& other, tbb::split): - mIsRoot(false), - mInputIter(other.mInputIter), - mInputTree(other.mInputTree), - mOutputTree(new OutTreeT(zeroVal())), - mOp(other.mOp), - mMergePolicy(other.mMergePolicy) - {} - - ~SharedOpTransformer() - { - // Delete the output tree only if it was allocated locally - // (the top-level output tree was supplied by the caller). - if (!mIsRoot) { - delete mOutputTree; - mOutputTree = NULL; - } - } - - void process(bool threaded = true) - { - if (!mInputTree || !mOutputTree) return; - - IterRange range(mInputIter); - - // Independently transform elements in the iterator range, - // either in parallel or serially. - if (threaded) { - tbb::parallel_reduce(range, *this); - } else { - (*this)(range); - } - } - - /// Transform each element in the given range. - void operator()(IterRange& range) const - { - if (!mOutputTree) return; - typename tree::ValueAccessor outAccessor(*mOutputTree); - for ( ; range; ++range) { - mOp(range.iterator(), outAccessor); - } - } - - void join(const SharedOpTransformer& other) - { - if (mOutputTree && other.mOutputTree) { - mOutputTree->merge(*other.mOutputTree, mMergePolicy); - } - } - -private: - bool mIsRoot; - InIterT mInputIter; - const InTreeT* mInputTree; - OutTreeT* mOutputTree; - OpT& mOp; - MergePolicy mMergePolicy; -}; // class SharedOpTransformer - - -template -class CopyableOpTransformer -{ -public: - typedef typename InIterT::TreeT InTreeT; - typedef typename tree::IteratorRange IterRange; - typedef typename OutTreeT::ValueType OutValueT; - - CopyableOpTransformer(const InIterT& inIter, OutTreeT& outTree, - const OpT& op, MergePolicy merge): - mIsRoot(true), - mInputIter(inIter), - mInputTree(inIter.getTree()), - mOutputTree(&outTree), - mOp(op), - mOrigOp(&op), - mMergePolicy(merge) - { - if (static_cast(mInputTree) == static_cast(mOutputTree)) { - OPENVDB_LOG_INFO("use tools::foreach(), not transformValues()," - " to transform a grid in place"); - } - } - - // When splitting this task, give the subtask a copy of the original functor, - // not of this task's functor, which might have been modified arbitrarily. - CopyableOpTransformer(CopyableOpTransformer& other, tbb::split): - mIsRoot(false), - mInputIter(other.mInputIter), - mInputTree(other.mInputTree), - mOutputTree(new OutTreeT(zeroVal())), - mOp(*other.mOrigOp), - mOrigOp(other.mOrigOp), - mMergePolicy(other.mMergePolicy) - {} - - ~CopyableOpTransformer() - { - // Delete the output tree only if it was allocated locally - // (the top-level output tree was supplied by the caller). - if (!mIsRoot) { - delete mOutputTree; - mOutputTree = NULL; - } - } - - void process(bool threaded = true) - { - if (!mInputTree || !mOutputTree) return; - - IterRange range(mInputIter); - - // Independently transform elements in the iterator range, - // either in parallel or serially. - if (threaded) { - tbb::parallel_reduce(range, *this); - } else { - (*this)(range); - } - } - - /// Transform each element in the given range. - void operator()(IterRange& range) - { - if (!mOutputTree) return; - typename tree::ValueAccessor outAccessor(*mOutputTree); - for ( ; range; ++range) { - mOp(range.iterator(), outAccessor); - } - } - - void join(const CopyableOpTransformer& other) - { - if (mOutputTree && other.mOutputTree) { - mOutputTree->merge(*other.mOutputTree, mMergePolicy); - } - } - -private: - bool mIsRoot; - InIterT mInputIter; - const InTreeT* mInputTree; - OutTreeT* mOutputTree; - OpT mOp; // copy of original functor - OpT const * const mOrigOp; // pointer to original functor - MergePolicy mMergePolicy; -}; // class CopyableOpTransformer - -} // namespace valxform - - -//////////////////////////////////////// - - -template -inline void -transformValues(const InIterT& inIter, OutGridT& outGrid, XformOp& op, - bool threaded, bool shared, MergePolicy merge) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType OutTreeT; - if (shared) { - typedef typename valxform::SharedOpTransformer Processor; - Processor proc(inIter, Adapter::tree(outGrid), op, merge); - proc.process(threaded); - } else { - typedef typename valxform::CopyableOpTransformer Processor; - Processor proc(inIter, Adapter::tree(outGrid), op, merge); - proc.process(threaded); - } -} - -#ifndef _MSC_VER -template -inline void -transformValues(const InIterT& inIter, OutGridT& outGrid, const XformOp& op, - bool threaded, bool /*share*/, MergePolicy merge) -{ - typedef TreeAdapter Adapter; - typedef typename Adapter::TreeType OutTreeT; - // Const ops are shared across threads, not copied. - typedef typename valxform::SharedOpTransformer Processor; - Processor proc(inIter, Adapter::tree(outGrid), op, merge); - proc.process(threaded); -} -#endif - - -//////////////////////////////////////// - - -namespace valxform { - -template -class OpAccumulator -{ -public: - typedef typename tree::IteratorRange IterRange; - - // The root task makes a const copy of the original functor (mOrigOp) - // and keeps a pointer to the original functor (mOp), which it then modifies. - // Each subtask keeps a const pointer to the root task's mOrigOp - // and makes and then modifies a non-const copy (mOp) of it. - OpAccumulator(const IterT& iter, OpT& op): - mIsRoot(true), - mIter(iter), - mOp(&op), - mOrigOp(new OpT(op)) - {} - - // When splitting this task, give the subtask a copy of the original functor, - // not of this task's functor, which might have been modified arbitrarily. - OpAccumulator(OpAccumulator& other, tbb::split): - mIsRoot(false), - mIter(other.mIter), - mOp(new OpT(*other.mOrigOp)), - mOrigOp(other.mOrigOp) - {} - - ~OpAccumulator() { if (mIsRoot) delete mOrigOp; else delete mOp; } - - void process(bool threaded = true) - { - IterRange range(mIter); - if (threaded) { - tbb::parallel_reduce(range, *this); - } else { - (*this)(range); - } - } - - void operator()(IterRange& r) { for ( ; r; ++r) (*mOp)(r.iterator()); } - - void join(OpAccumulator& other) { mOp->join(*other.mOp); } - -private: - const bool mIsRoot; - const IterT mIter; - OpT* mOp; // pointer to original functor, which might get modified - OpT const * const mOrigOp; // const copy of original functor -}; // class OpAccumulator - -} // namespace valxform - - -//////////////////////////////////////// - - -template -inline void -accumulate(const IterT& iter, XformOp& op, bool threaded) -{ - typename valxform::OpAccumulator proc(iter, op); - proc.process(threaded); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/VectorTransformer.h b/openvdb_3_0_0_library/tools/VectorTransformer.h deleted file mode 100755 index b047b2b..0000000 --- a/openvdb_3_0_0_library/tools/VectorTransformer.h +++ /dev/null @@ -1,158 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file VectorTransformer.h - -#ifndef OPENVDB_TOOLS_VECTORTRANSFORMER_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_VECTORTRANSFORMER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include "ValueTransformer.h" // for tools::foreach() -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - -/// @brief Apply an affine transform to the voxel values of a vector-valued grid -/// in accordance with the grid's vector type (covariant, contravariant, etc.). -/// @throw TypeError if the grid is not vector-valued -template -inline void -transformVectors(GridType&, const Mat4d&); - - -//////////////////////////////////////// - - -// Functors for use with tools::foreach() to transform vector voxel values - -struct HomogeneousMatMul -{ - const Mat4d mat; - HomogeneousMatMul(const Mat4d& _mat): mat(_mat) {} - template void operator()(const TreeIterT& it) const - { - Vec3d v(*it); - it.setValue(mat.transformH(v)); - } -}; - -struct MatMul -{ - const Mat4d mat; - MatMul(const Mat4d& _mat): mat(_mat) {} - template - void operator()(const TreeIterT& it) const - { - Vec3d v(*it); - it.setValue(mat.transform3x3(v)); - } -}; - -struct MatMulNormalize -{ - const Mat4d mat; - MatMulNormalize(const Mat4d& _mat): mat(_mat) {} - template - void operator()(const TreeIterT& it) const - { - Vec3d v(*it); - v = mat.transform3x3(v); - v.normalize(); - it.setValue(v); - } -}; - - -/// @internal This overload is enabled only for scalar-valued grids. -template inline -typename boost::disable_if_c::IsVec, void>::type -doTransformVectors(GridType&, const Mat4d&) -{ - OPENVDB_THROW(TypeError, "tools::transformVectors() requires a vector-valued grid"); -} - -/// @internal This overload is enabled only for vector-valued grids. -template inline -typename boost::enable_if_c::IsVec, void>::type -doTransformVectors(GridType& grid, const Mat4d& mat) -{ - if (!grid.isInWorldSpace()) return; - - const VecType vecType = grid.getVectorType(); - switch (vecType) { - case VEC_COVARIANT: - case VEC_COVARIANT_NORMALIZE: - { - Mat4d invmat = mat.inverse(); - invmat = invmat.transpose(); - - if (vecType == VEC_COVARIANT_NORMALIZE) { - foreach(grid.beginValueAll(), MatMulNormalize(invmat)); - } else { - foreach(grid.beginValueAll(), MatMul(invmat)); - } - break; - } - - case VEC_CONTRAVARIANT_RELATIVE: - foreach(grid.beginValueAll(), MatMul(mat)); - break; - - case VEC_CONTRAVARIANT_ABSOLUTE: - foreach(grid.beginValueAll(), HomogeneousMatMul(mat)); - break; - - case VEC_INVARIANT: - break; - } -} - - -template -inline void -transformVectors(GridType& grid, const Mat4d& mat) -{ - doTransformVectors(grid, mat); -} - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_VECTORTRANSFORMER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/VolumeToMesh.h b/openvdb_3_0_0_library/tools/VolumeToMesh.h deleted file mode 100755 index cd16c6f..0000000 --- a/openvdb_3_0_0_library/tools/VolumeToMesh.h +++ /dev/null @@ -1,4683 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED - -#include // for OPENVDB_HAS_CXX11 -#include -#include // for COORD_OFFSETS -#include // for ISGradient -#include // for dilateVoxels() -#include -#include "Prune.h" // for pruneInactive - -#include -#include -#include -#include -#include -#include -#include - -#include -#include // for auto_ptr/unique_ptr - - -////////// - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -//////////////////////////////////////// - - -// Wrapper functions for the VolumeToMesh converter - - -/// @brief Uniformly mesh any scalar grid that has a continuous isosurface. -/// -/// @param grid a scalar grid to mesh -/// @param points output list of world space points -/// @param quads output quad index list -/// @param isovalue determines which isosurface to mesh -/// -/// @throw TypeError if @a grid does not have a scalar value type -template -inline void -volumeToMesh( - const GridType& grid, - std::vector& points, - std::vector& quads, - double isovalue = 0.0); - - -/// @brief Adaptively mesh any scalar grid that has a continuous isosurface. -/// -/// @param grid a scalar grid to mesh -/// @param points output list of world space points -/// @param triangles output quad index list -/// @param quads output quad index list -/// @param isovalue determines which isosurface to mesh -/// @param adaptivity surface adaptivity threshold [0 to 1] -/// -/// @throw TypeError if @a grid does not have a scalar value type -template -inline void -volumeToMesh( - const GridType& grid, - std::vector& points, - std::vector& triangles, - std::vector& quads, - double isovalue = 0.0, - double adaptivity = 0.0); - - -//////////////////////////////////////// - - -/// @brief Polygon flags, used for reference based meshing. -enum { POLYFLAG_EXTERIOR = 0x1, POLYFLAG_FRACTURE_SEAM = 0x2, POLYFLAG_SUBDIVIDED = 0x4}; - - -/// @brief Collection of quads and triangles -class PolygonPool -{ -public: - - inline PolygonPool(); - inline PolygonPool(const size_t numQuads, const size_t numTriangles); - - - inline void copy(const PolygonPool& rhs); - - inline void resetQuads(size_t size); - inline void clearQuads(); - - inline void resetTriangles(size_t size); - inline void clearTriangles(); - - - // polygon accessor methods - - const size_t& numQuads() const { return mNumQuads; } - - openvdb::Vec4I& quad(size_t n) { return mQuads[n]; } - const openvdb::Vec4I& quad(size_t n) const { return mQuads[n]; } - - - const size_t& numTriangles() const { return mNumTriangles; } - - openvdb::Vec3I& triangle(size_t n) { return mTriangles[n]; } - const openvdb::Vec3I& triangle(size_t n) const { return mTriangles[n]; } - - - // polygon flags accessor methods - - char& quadFlags(size_t n) { return mQuadFlags[n]; } - const char& quadFlags(size_t n) const { return mQuadFlags[n]; } - - char& triangleFlags(size_t n) { return mTriangleFlags[n]; } - const char& triangleFlags(size_t n) const { return mTriangleFlags[n]; } - - - // reduce the polygon containers, n has to - // be smaller than the current container size. - - inline bool trimQuads(const size_t n, bool reallocate = false); - inline bool trimTrinagles(const size_t n, bool reallocate = false); - -private: - // disallow copy by assignment - void operator=(const PolygonPool&) {} - - size_t mNumQuads, mNumTriangles; - boost::scoped_array mQuads; - boost::scoped_array mTriangles; - boost::scoped_array mQuadFlags, mTriangleFlags; -}; - - -/// @{ -/// @brief Point and primitive list types. -typedef boost::scoped_array PointList; -typedef boost::scoped_array PolygonPoolList; -/// @} - - -//////////////////////////////////////// - - -/// @brief Mesh any scalar grid that has a continuous isosurface. -class VolumeToMesh -{ -public: - - /// @param isovalue Determines which isosurface to mesh. - /// @param adaptivity Adaptivity threshold [0 to 1] - VolumeToMesh(double isovalue = 0, double adaptivity = 0); - - - ////////// - - // Mesh data accessors - - const size_t& pointListSize() const; - PointList& pointList(); - - const size_t& polygonPoolListSize() const; - PolygonPoolList& polygonPoolList(); - const PolygonPoolList& polygonPoolList() const; - - std::vector& pointFlags(); - const std::vector& pointFlags() const; - - - ////////// - - - /// @brief Main call - /// @note Call with scalar typed grid. - template - void operator()(const GridT&); - - - ////////// - - - /// @brief When surfacing fractured SDF fragments, the original unfractured - /// SDF grid can be used to eliminate seam lines and tag polygons that are - /// coincident with the reference surface with the @c POLYFLAG_EXTERIOR - /// flag and polygons that are in proximity to the seam lines with the - /// @c POLYFLAG_FRACTURE_SEAM flag. (The performance cost for using this - /// reference based scheme compared to the regular meshing scheme is - /// approximately 15% for the first fragment and neglect-able for - /// subsequent fragments.) - /// - /// @note Attributes from the original asset such as uv coordinates, normals etc. - /// are typically transfered to polygons that are marked with the - /// @c POLYFLAG_EXTERIOR flag. Polygons that are not marked with this flag - /// are interior to reference surface and might need projected UV coordinates - /// or a different material. Polygons marked as @c POLYFLAG_FRACTURE_SEAM can - /// be used to drive secondary elements such as debris and dust in a FX pipeline. - /// - /// @param grid reference surface grid of @c GridT type. - /// @param secAdaptivity Secondary adaptivity threshold [0 to 1]. Used in regions - /// that do not exist in the reference grid. (Parts of the - /// fragment surface that are not coincident with the - /// reference surface.) - void setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity = 0); - - - /// @param mask A boolean grid whose active topology defines the region to mesh. - /// @param invertMask Toggle to mesh the complement of the mask. - /// @note The mask's tree configuration has to match @c GridT's tree configuration. - void setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask = false); - - /// @param grid A scalar grid used as an spatial multiplier for the adaptivity threshold. - /// @note The grid's tree configuration has to match @c GridT's tree configuration. - void setSpatialAdaptivity(const GridBase::ConstPtr& grid); - - - /// @param tree A boolean tree whose active topology defines the adaptivity mask. - /// @note The tree configuration has to match @c GridT's tree configuration. - void setAdaptivityMask(const TreeBase::ConstPtr& tree); - - - /// @brief Subdivide volume and mesh into disjoint parts - /// @param partitions Number of partitions. - /// @param activePart Specific partition to mesh, 0 to @c partitions - 1. - void partition(unsigned partitions = 1, unsigned activePart = 0); - -private: - - PointList mPoints; - PolygonPoolList mPolygons; - - size_t mPointListSize, mSeamPointListSize, mPolygonPoolListSize; - double mIsovalue, mPrimAdaptivity, mSecAdaptivity; - - GridBase::ConstPtr mRefGrid, mSurfaceMaskGrid, mAdaptivityGrid; - TreeBase::ConstPtr mAdaptivityMaskTree; - - TreeBase::Ptr mRefSignTree, mRefIdxTree; - - bool mInvertSurfaceMask; - unsigned mPartitions, mActivePart; - - boost::scoped_array mQuantizedSeamPoints; - - std::vector mPointFlags; -}; - - -//////////////////////////////////////// - - -/// @brief Given a set of tangent elements, @c points with corresponding @c normals, -/// this method returns the intersection point of all tangent elements. -/// -/// @note Used to extract surfaces with sharp edges and corners from volume data, -/// see the following paper for details: "Feature Sensitive Surface -/// Extraction from Volume Data, Kobbelt et al. 2001". -inline Vec3d findFeaturePoint( - const std::vector& points, - const std::vector& normals) -{ - typedef math::Mat3d Mat3d; - - Vec3d avgPos(0.0); - - if (points.empty()) return avgPos; - - for (size_t n = 0, N = points.size(); n < N; ++n) { - avgPos += points[n]; - } - - avgPos /= double(points.size()); - - // Unique components of the 3x3 A^TA matrix, where A is - // the matrix of normals. - double m00=0,m01=0,m02=0, - m11=0,m12=0, - m22=0; - - // The rhs vector, A^Tb, where b = n dot p - Vec3d rhs(0.0); - - for (size_t n = 0, N = points.size(); n < N; ++n) { - - const Vec3d& n_ref = normals[n]; - - // A^TA - m00 += n_ref[0] * n_ref[0]; // diagonal - m11 += n_ref[1] * n_ref[1]; - m22 += n_ref[2] * n_ref[2]; - - m01 += n_ref[0] * n_ref[1]; // Upper-tri - m02 += n_ref[0] * n_ref[2]; - m12 += n_ref[1] * n_ref[2]; - - // A^Tb (centered around the origin) - rhs += n_ref * n_ref.dot(points[n] - avgPos); - } - - Mat3d A(m00,m01,m02, - m01,m11,m12, - m02,m12,m22); - - /* - // Inverse - const double det = A.det(); - if (det > 0.01) { - Mat3d A_inv = A.adjoint(); - A_inv *= (1.0 / det); - - return avgPos + A_inv * rhs; - } - */ - - // Compute the pseudo inverse - - math::Mat3d eigenVectors; - Vec3d eigenValues; - - diagonalizeSymmetricMatrix(A, eigenVectors, eigenValues, 300); - - Mat3d D = Mat3d::identity(); - - - double tolerance = std::max(std::abs(eigenValues[0]), std::abs(eigenValues[1])); - tolerance = std::max(tolerance, std::abs(eigenValues[2])); - tolerance *= 0.01; - - int clamped = 0; - for (int i = 0; i < 3; ++i ) { - if (std::abs(eigenValues[i]) < tolerance) { - D[i][i] = 0.0; - ++clamped; - } else { - D[i][i] = 1.0 / eigenValues[i]; - } - } - - // Assemble the pseudo inverse and calc. the intersection point - if (clamped < 3) { - Mat3d pseudoInv = eigenVectors * D * eigenVectors.transpose(); - return avgPos + pseudoInv * rhs; - } - - return avgPos; -} - - -//////////////////////////////////////// - - -// Internal utility methods -namespace internal { - -template -struct UniquePtr -{ -#ifdef OPENVDB_HAS_CXX11 - typedef std::unique_ptr type; -#else - typedef std::auto_ptr type; -#endif -}; - - -/// @brief Bit-flags used to classify cells. -enum { SIGNS = 0xFF, EDGES = 0xE00, INSIDE = 0x100, - XEDGE = 0x200, YEDGE = 0x400, ZEDGE = 0x800, SEAM = 0x1000}; - - -/// @brief Used to quickly determine if a given cell is adaptable. -const bool sAdaptable[256] = { - 1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1, - 1,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,0,1, - 1,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,1, - 1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,1, - 1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1, - 1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1}; - - -/// @brief Contains the ambiguous face index for certain cell configuration. -const unsigned char sAmbiguousFace[256] = { - 0,0,0,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,1,0,0,5,1,0,4,0,0,0,4,0,0,0, - 0,1,0,0,2,0,0,0,0,1,5,0,2,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0,0,0,0,0, - 0,0,2,2,0,5,0,0,3,3,0,0,0,0,0,0,6,6,0,0,6,0,0,0,0,0,0,0,0,0,0,0, - 0,1,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,4,0,4,3,0,3,0,0,0,5,0,0,0,0,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0, - 6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - -/// @brief Lookup table for different cell sign configurations. The first entry specifies -/// the total number of points that need to be generated inside a cell and the -/// remaining 12 entries indicate different edge groups. -const unsigned char sEdgeGroupTable[256][13] = { - {0,0,0,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0}, - {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},{1,1,1,1,1,0,0,0,0,1,0,1,0}, - {1,1,0,1,0,0,0,0,0,0,1,1,0},{1,0,0,1,1,0,0,0,0,1,1,1,0},{1,0,0,1,1,0,0,0,0,0,0,0,1}, - {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,1,1,1,1,0,0,0,0,0,1,0,1},{1,0,1,1,0,0,0,0,0,1,1,0,1}, - {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1}, - {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,0,0,0,0,1,0,0,1,1,0,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0}, - {1,1,1,0,0,1,0,0,1,1,1,0,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},{2,0,1,1,0,2,0,0,2,2,0,1,0}, - {1,1,1,1,1,1,0,0,1,0,0,1,0},{1,1,0,1,0,1,0,0,1,1,1,1,0},{1,0,0,1,1,1,0,0,1,0,1,1,0}, - {1,0,0,1,1,1,0,0,1,1,0,0,1},{1,1,0,1,0,1,0,0,1,0,0,0,1},{2,2,1,1,2,1,0,0,1,2,1,0,1}, - {1,0,1,1,0,1,0,0,1,0,1,0,1},{1,0,1,0,1,1,0,0,1,1,0,1,1},{1,1,1,0,0,1,0,0,1,0,0,1,1}, - {2,1,0,0,1,2,0,0,2,1,2,2,2},{1,0,0,0,0,1,0,0,1,0,1,1,1},{1,0,0,0,0,1,1,0,0,0,1,0,0}, - {1,1,0,0,1,1,1,0,0,1,1,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},{1,0,1,0,1,1,1,0,0,1,0,0,0}, - {1,0,1,1,0,1,1,0,0,0,1,1,0},{2,2,2,1,1,1,1,0,0,1,2,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0}, - {1,0,0,1,1,1,1,0,0,1,0,1,0},{2,0,0,2,2,1,1,0,0,0,1,0,2},{1,1,0,1,0,1,1,0,0,1,1,0,1}, - {1,1,1,1,1,1,1,0,0,0,0,0,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},{1,0,1,0,1,1,1,0,0,0,1,1,1}, - {2,1,1,0,0,2,2,0,0,2,1,2,2},{1,1,0,0,1,1,1,0,0,0,0,1,1},{1,0,0,0,0,1,1,0,0,1,0,1,1}, - {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0}, - {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,0,1,1,0,0,1,0,1,1,1,1,0},{2,1,1,2,2,0,2,0,2,0,1,2,0}, - {1,1,0,1,0,0,1,0,1,1,0,1,0},{1,0,0,1,1,0,1,0,1,0,0,1,0},{1,0,0,1,1,0,1,0,1,1,1,0,1}, - {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,1,2,2,1,0,2,0,2,1,0,0,2},{1,0,1,1,0,0,1,0,1,0,0,0,1}, - {2,0,2,0,2,0,1,0,1,2,2,1,1},{2,2,2,0,0,0,1,0,1,0,2,1,1},{2,2,0,0,2,0,1,0,1,2,0,1,1}, - {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,0,0,0,0,0,1,1,0,0,0,1,0},{2,1,0,0,1,0,2,2,0,1,0,2,0}, - {1,1,1,0,0,0,1,1,0,0,1,1,0},{1,0,1,0,1,0,1,1,0,1,1,1,0},{1,0,1,1,0,0,1,1,0,0,0,0,0}, - {1,1,1,1,1,0,1,1,0,1,0,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},{1,0,0,1,1,0,1,1,0,1,1,0,0}, - {1,0,0,1,1,0,1,1,0,0,0,1,1},{1,1,0,1,0,0,1,1,0,1,0,1,1},{2,1,2,2,1,0,1,1,0,0,1,2,1}, - {2,0,1,1,0,0,2,2,0,2,2,1,2},{1,0,1,0,1,0,1,1,0,0,0,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1}, - {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,0,0,0,0,0,1,1,0,1,1,0,1},{1,0,0,0,0,1,1,1,1,1,0,1,0}, - {1,1,0,0,1,1,1,1,1,0,0,1,0},{2,1,1,0,0,2,2,1,1,1,2,1,0},{2,0,2,0,2,1,1,2,2,0,1,2,0}, - {1,0,1,1,0,1,1,1,1,1,0,0,0},{2,2,2,1,1,2,2,1,1,0,0,0,0},{2,2,0,2,0,1,1,2,2,2,1,0,0}, - {2,0,0,1,1,2,2,1,1,0,2,0,0},{2,0,0,1,1,1,1,2,2,1,0,1,2},{2,2,0,2,0,2,2,1,1,0,0,2,1}, - {4,3,2,2,3,4,4,1,1,3,4,2,1},{3,0,2,2,0,1,1,3,3,0,1,2,3},{2,0,2,0,2,2,2,1,1,2,0,0,1}, - {2,1,1,0,0,1,1,2,2,0,0,0,2},{3,1,0,0,1,2,2,3,3,1,2,0,3},{2,0,0,0,0,1,1,2,2,0,1,0,2}, - {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,1,0,0,1,1,0,1,0,1,1,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0}, - {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},{2,1,1,2,2,2,0,2,0,2,1,0,0}, - {1,1,0,1,0,1,0,1,0,0,0,0,0},{1,0,0,1,1,1,0,1,0,1,0,0,0},{1,0,0,1,1,1,0,1,0,0,1,1,1}, - {2,2,0,2,0,1,0,1,0,1,2,2,1},{2,2,1,1,2,2,0,2,0,0,0,1,2},{2,0,2,2,0,1,0,1,0,1,0,2,1}, - {1,0,1,0,1,1,0,1,0,0,1,0,1},{2,2,2,0,0,1,0,1,0,1,2,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1}, - {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,0,0,0,0,0,0,1,1,1,1,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0}, - {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},{1,0,1,1,0,0,0,1,1,1,1,0,0}, - {2,2,2,1,1,0,0,1,1,0,2,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},{1,0,0,1,1,0,0,1,1,0,0,0,0}, - {2,0,0,2,2,0,0,1,1,2,2,2,1},{2,1,0,1,0,0,0,2,2,0,1,1,2},{3,2,1,1,2,0,0,3,3,2,0,1,3}, - {2,0,1,1,0,0,0,2,2,0,0,1,2},{2,0,1,0,1,0,0,2,2,1,1,0,2},{2,1,1,0,0,0,0,2,2,0,1,0,2}, - {2,1,0,0,1,0,0,2,2,1,0,0,2},{1,0,0,0,0,0,0,1,1,0,0,0,1},{1,0,0,0,0,0,0,1,1,0,0,0,1}, - {1,1,0,0,1,0,0,1,1,1,0,0,1},{2,1,1,0,0,0,0,2,2,0,1,0,2},{1,0,1,0,1,0,0,1,1,1,1,0,1}, - {1,0,1,1,0,0,0,1,1,0,0,1,1},{2,1,1,2,2,0,0,1,1,1,0,1,2},{1,1,0,1,0,0,0,1,1,0,1,1,1}, - {2,0,0,1,1,0,0,2,2,2,2,2,1},{1,0,0,1,1,0,0,1,1,0,0,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0}, - {1,1,1,1,1,0,0,1,1,0,1,0,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},{1,0,1,0,1,0,0,1,1,0,0,1,0}, - {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},{1,0,0,0,0,0,0,1,1,1,1,1,0}, - {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},{1,1,1,0,0,1,0,1,0,1,1,0,1}, - {1,0,1,0,1,1,0,1,0,0,1,0,1},{1,0,1,1,0,1,0,1,0,1,0,1,1},{2,2,2,1,1,2,0,2,0,0,0,2,1}, - {2,1,0,1,0,2,0,2,0,1,2,2,1},{2,0,0,2,2,1,0,1,0,0,1,1,2},{1,0,0,1,1,1,0,1,0,1,0,0,0}, - {1,1,0,1,0,1,0,1,0,0,0,0,0},{2,1,2,2,1,2,0,2,0,1,2,0,0},{1,0,1,1,0,1,0,1,0,0,1,0,0}, - {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},{2,2,0,0,2,1,0,1,0,2,1,1,0}, - {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,0,0,0,0,1,1,1,1,0,1,0,1},{2,1,0,0,1,2,1,1,2,2,1,0,1}, - {1,1,1,0,0,1,1,1,1,0,0,0,1},{2,0,2,0,2,1,2,2,1,1,0,0,2},{2,0,1,1,0,1,2,2,1,0,1,2,1}, - {4,1,1,3,3,2,4,4,2,2,1,4,3},{2,2,0,2,0,2,1,1,2,0,0,1,2},{3,0,0,1,1,2,3,3,2,2,0,3,1}, - {1,0,0,1,1,1,1,1,1,0,1,0,0},{2,2,0,2,0,1,2,2,1,1,2,0,0},{2,2,1,1,2,2,1,1,2,0,0,0,0}, - {2,0,1,1,0,2,1,1,2,2,0,0,0},{2,0,2,0,2,2,1,1,2,0,2,1,0},{3,1,1,0,0,3,2,2,3,3,1,2,0}, - {2,1,0,0,1,1,2,2,1,0,0,2,0},{2,0,0,0,0,2,1,1,2,2,0,1,0},{1,0,0,0,0,0,1,1,0,1,1,0,1}, - {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},{1,0,1,0,1,0,1,1,0,0,0,0,1}, - {2,0,2,2,0,0,1,1,0,2,2,1,2},{3,1,1,2,2,0,3,3,0,0,1,3,2},{2,1,0,1,0,0,2,2,0,1,0,2,1}, - {2,0,0,1,1,0,2,2,0,0,0,2,1},{1,0,0,1,1,0,1,1,0,1,1,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0}, - {2,2,1,1,2,0,1,1,0,2,0,0,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},{2,0,1,0,1,0,2,2,0,1,1,2,0}, - {2,1,1,0,0,0,2,2,0,0,1,2,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},{1,0,0,0,0,0,1,1,0,0,0,1,0}, - {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,1,0,0,1,0,1,0,1,1,0,1,1},{1,1,1,0,0,0,1,0,1,0,1,1,1}, - {2,0,2,0,2,0,1,0,1,1,1,2,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},{2,2,2,1,1,0,2,0,2,2,0,0,1}, - {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,0,0,2,2,0,1,0,1,1,1,0,2},{1,0,0,1,1,0,1,0,1,0,0,1,0}, - {1,1,0,1,0,0,1,0,1,1,0,1,0},{2,2,1,1,2,0,2,0,2,0,2,1,0},{2,0,2,2,0,0,1,0,1,1,1,2,0}, - {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0}, - {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,0,0,0,0,1,1,0,0,1,0,1,1},{1,1,0,0,1,1,1,0,0,0,0,1,1}, - {2,2,2,0,0,1,1,0,0,2,1,2,2},{2,0,1,0,1,2,2,0,0,0,2,1,1},{1,0,1,1,0,1,1,0,0,1,0,0,1}, - {2,1,1,2,2,1,1,0,0,0,0,0,2},{2,1,0,1,0,2,2,0,0,1,2,0,1},{2,0,0,2,2,1,1,0,0,0,1,0,2}, - {1,0,0,1,1,1,1,0,0,1,0,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},{3,1,2,2,1,3,3,0,0,1,3,2,0}, - {2,0,1,1,0,2,2,0,0,0,2,1,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0}, - {2,2,0,0,2,1,1,0,0,2,1,0,0},{1,0,0,0,0,1,1,0,0,0,1,0,0},{1,0,0,0,0,1,0,0,1,0,1,1,1}, - {2,2,0,0,2,1,0,0,1,1,2,2,2},{1,1,1,0,0,1,0,0,1,0,0,1,1},{2,0,1,0,1,2,0,0,2,2,0,1,1}, - {1,0,1,1,0,1,0,0,1,0,1,0,1},{3,1,1,3,3,2,0,0,2,2,1,0,3},{1,1,0,1,0,1,0,0,1,0,0,0,1}, - {2,0,0,2,2,1,0,0,1,1,0,0,2},{1,0,0,1,1,1,0,0,1,0,1,1,0},{2,1,0,1,0,2,0,0,2,2,1,1,0}, - {2,1,2,2,1,1,0,0,1,0,0,2,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},{1,0,1,0,1,1,0,0,1,0,1,0,0}, - {2,1,1,0,0,2,0,0,2,2,1,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},{1,0,0,0,0,1,0,0,1,1,0,0,0}, - {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1}, - {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},{2,1,1,2,2,0,0,0,0,0,1,0,2}, - {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,0,0,1,1,0,0,0,0,0,0,0,1},{1,0,0,1,1,0,0,0,0,1,1,1,0}, - {1,1,0,1,0,0,0,0,0,0,1,1,0},{2,1,2,2,1,0,0,0,0,1,0,2,0},{1,0,1,1,0,0,0,0,0,0,0,1,0}, - {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0}}; - - -//////////////////////////////////////// - -inline bool -isPlanarQuad( - const Vec3d& p0, const Vec3d& p1, - const Vec3d& p2, const Vec3d& p3, - double epsilon = 0.001) -{ - // compute representative plane - Vec3d normal = (p2-p0).cross(p1-p3); - normal.normalize(); - const Vec3d centroid = (p0 + p1 + p2 + p3); - const double d = centroid.dot(normal) * 0.25; - - - // test vertice distance to plane - double absDist = std::abs(p0.dot(normal) - d); - if (absDist > epsilon) return false; - - absDist = std::abs(p1.dot(normal) - d); - if (absDist > epsilon) return false; - - absDist = std::abs(p2.dot(normal) - d); - if (absDist > epsilon) return false; - - absDist = std::abs(p3.dot(normal) - d); - if (absDist > epsilon) return false; - - return true; -} - - -//////////////////////////////////////// - - -/// @{ -/// @brief Utility methods for point quantization. - -enum { - MASK_FIRST_10_BITS = 0x000003FF, - MASK_DIRTY_BIT = 0x80000000, - MASK_INVALID_BIT = 0x40000000 -}; - -inline uint32_t -packPoint(const Vec3d& v) -{ - uint32_t data = 0; - - // values are expected to be in the [0.0 to 1.0] range. - assert(!(v.x() > 1.0) && !(v.y() > 1.0) && !(v.z() > 1.0)); - assert(!(v.x() < 0.0) && !(v.y() < 0.0) && !(v.z() < 0.0)); - - data |= (uint32_t(v.x() * 1023.0) & MASK_FIRST_10_BITS) << 20; - data |= (uint32_t(v.y() * 1023.0) & MASK_FIRST_10_BITS) << 10; - data |= (uint32_t(v.z() * 1023.0) & MASK_FIRST_10_BITS); - - return data; -} - -inline Vec3d -unpackPoint(uint32_t data) -{ - Vec3d v; - v.z() = double(data & MASK_FIRST_10_BITS) * 0.0009775171; - data = data >> 10; - v.y() = double(data & MASK_FIRST_10_BITS) * 0.0009775171; - data = data >> 10; - v.x() = double(data & MASK_FIRST_10_BITS) * 0.0009775171; - - return v; -} - -/// @} - -//////////////////////////////////////// - - -/// @brief General method that computes the cell-sign configuration at the given -/// @c ijk coordinate. -template -inline unsigned char -evalCellSigns(const AccessorT& accessor, const Coord& ijk, typename AccessorT::ValueType iso) -{ - unsigned signs = 0; - Coord coord = ijk; // i, j, k - if (accessor.getValue(coord) < iso) signs |= 1u; - coord[0] += 1; // i+1, j, k - if (accessor.getValue(coord) < iso) signs |= 2u; - coord[2] += 1; // i+1, j, k+1 - if (accessor.getValue(coord) < iso) signs |= 4u; - coord[0] = ijk[0]; // i, j, k+1 - if (accessor.getValue(coord) < iso) signs |= 8u; - coord[1] += 1; coord[2] = ijk[2]; // i, j+1, k - if (accessor.getValue(coord) < iso) signs |= 16u; - coord[0] += 1; // i+1, j+1, k - if (accessor.getValue(coord) < iso) signs |= 32u; - coord[2] += 1; // i+1, j+1, k+1 - if (accessor.getValue(coord) < iso) signs |= 64u; - coord[0] = ijk[0]; // i, j+1, k+1 - if (accessor.getValue(coord) < iso) signs |= 128u; - return uint8_t(signs); -} - - -/// @brief Leaf node optimized method that computes the cell-sign configuration -/// at the given local @c offset -template -inline unsigned char -evalCellSigns(const LeafT& leaf, const Index offset, typename LeafT::ValueType iso) -{ - unsigned char signs = 0; - - // i, j, k - if (leaf.getValue(offset) < iso) signs |= 1u; - - // i, j, k+1 - if (leaf.getValue(offset + 1) < iso) signs |= 8u; - - // i, j+1, k - if (leaf.getValue(offset + LeafT::DIM) < iso) signs |= 16u; - - // i, j+1, k+1 - if (leaf.getValue(offset + LeafT::DIM + 1) < iso) signs |= 128u; - - // i+1, j, k - if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) ) < iso) signs |= 2u; - - // i+1, j, k+1 - if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1) < iso) signs |= 4u; - - // i+1, j+1, k - if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM) < iso) signs |= 32u; - - // i+1, j+1, k+1 - if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1) < iso) signs |= 64u; - - return signs; -} - - -/// @brief Used to correct topological ambiguities related to two adjacent cells -/// that share an ambiguous face. -template -inline void -correctCellSigns(unsigned char& signs, unsigned char face, - const AccessorT& acc, Coord ijk, typename AccessorT::ValueType iso) -{ - if (face == 1) { - ijk[2] -= 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 3) signs = uint8_t(~signs); - } else if (face == 3) { - ijk[2] += 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 1) signs = uint8_t(~signs); - } else if (face == 2) { - ijk[0] += 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 4) signs = uint8_t(~signs); - } else if (face == 4) { - ijk[0] -= 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 2) signs = uint8_t(~signs); - } else if (face == 5) { - ijk[1] -= 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 6) signs = uint8_t(~signs); - } else if (face == 6) { - ijk[1] += 1; - if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 5) signs = uint8_t(~signs); - } -} - - -template -inline bool -isNonManifold(const AccessorT& accessor, const Coord& ijk, - typename AccessorT::ValueType isovalue, const int dim) -{ - int hDim = dim >> 1; - bool m, p[8]; // Corner signs - - Coord coord = ijk; // i, j, k - p[0] = accessor.getValue(coord) < isovalue; - coord[0] += dim; // i+dim, j, k - p[1] = accessor.getValue(coord) < isovalue; - coord[2] += dim; // i+dim, j, k+dim - p[2] = accessor.getValue(coord) < isovalue; - coord[0] = ijk[0]; // i, j, k+dim - p[3] = accessor.getValue(coord) < isovalue; - coord[1] += dim; coord[2] = ijk[2]; // i, j+dim, k - p[4] = accessor.getValue(coord) < isovalue; - coord[0] += dim; // i+dim, j+dim, k - p[5] = accessor.getValue(coord) < isovalue; - coord[2] += dim; // i+dim, j+dim, k+dim - p[6] = accessor.getValue(coord) < isovalue; - coord[0] = ijk[0]; // i, j+dim, k+dim - p[7] = accessor.getValue(coord) < isovalue; - - // Check if the corner sign configuration is ambiguous - unsigned signs = 0; - if (p[0]) signs |= 1u; - if (p[1]) signs |= 2u; - if (p[2]) signs |= 4u; - if (p[3]) signs |= 8u; - if (p[4]) signs |= 16u; - if (p[5]) signs |= 32u; - if (p[6]) signs |= 64u; - if (p[7]) signs |= 128u; - if (!sAdaptable[signs]) return true; - - // Manifold check - - // Evaluate edges - int i = ijk[0], ip = ijk[0] + hDim, ipp = ijk[0] + dim; - int j = ijk[1], jp = ijk[1] + hDim, jpp = ijk[1] + dim; - int k = ijk[2], kp = ijk[2] + hDim, kpp = ijk[2] + dim; - - // edge 1 - coord.reset(ip, j, k); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[1] != m) return true; - - // edge 2 - coord.reset(ipp, j, kp); - m = accessor.getValue(coord) < isovalue; - if (p[1] != m && p[2] != m) return true; - - // edge 3 - coord.reset(ip, j, kpp); - m = accessor.getValue(coord) < isovalue; - if (p[2] != m && p[3] != m) return true; - - // edge 4 - coord.reset(i, j, kp); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[3] != m) return true; - - // edge 5 - coord.reset(ip, jpp, k); - m = accessor.getValue(coord) < isovalue; - if (p[4] != m && p[5] != m) return true; - - // edge 6 - coord.reset(ipp, jpp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[5] != m && p[6] != m) return true; - - // edge 7 - coord.reset(ip, jpp, kpp); - m = accessor.getValue(coord) < isovalue; - if (p[6] != m && p[7] != m) return true; - - // edge 8 - coord.reset(i, jpp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[7] != m && p[4] != m) return true; - - // edge 9 - coord.reset(i, jp, k); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[4] != m) return true; - - // edge 10 - coord.reset(ipp, jp, k); - m = accessor.getValue(coord) < isovalue; - if (p[1] != m && p[5] != m) return true; - - // edge 11 - coord.reset(ipp, jp, kpp); - m = accessor.getValue(coord) < isovalue; - if (p[2] != m && p[6] != m) return true; - - - // edge 12 - coord.reset(i, jp, kpp); - m = accessor.getValue(coord) < isovalue; - if (p[3] != m && p[7] != m) return true; - - - // Evaluate faces - - // face 1 - coord.reset(ip, jp, k); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[1] != m && p[4] != m && p[5] != m) return true; - - // face 2 - coord.reset(ipp, jp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[1] != m && p[2] != m && p[5] != m && p[6] != m) return true; - - // face 3 - coord.reset(ip, jp, kpp); - m = accessor.getValue(coord) < isovalue; - if (p[2] != m && p[3] != m && p[6] != m && p[7] != m) return true; - - // face 4 - coord.reset(i, jp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[3] != m && p[4] != m && p[7] != m) return true; - - // face 5 - coord.reset(ip, j, kp); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[1] != m && p[2] != m && p[3] != m) return true; - - // face 6 - coord.reset(ip, jpp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[4] != m && p[5] != m && p[6] != m && p[7] != m) return true; - - // test cube center - coord.reset(ip, jp, kp); - m = accessor.getValue(coord) < isovalue; - if (p[0] != m && p[1] != m && p[2] != m && p[3] != m && - p[4] != m && p[5] != m && p[6] != m && p[7] != m) return true; - - return false; -} - - -//////////////////////////////////////// - - -template -inline void -mergeVoxels(LeafType& leaf, const Coord& start, int dim, int regionId) -{ - Coord ijk, end = start; - end[0] += dim; - end[1] += dim; - end[2] += dim; - - for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) { - for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) { - for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) { - leaf.setValueOnly(ijk, regionId); - } - } - } -} - - -// Note that we must use ValueType::value_type or else Visual C++ gets confused -// thinking that it is a constructor. -template -inline bool -isMergable(LeafType& leaf, const Coord& start, int dim, - typename LeafType::ValueType::value_type adaptivity) -{ - if (adaptivity < 1e-6) return false; - - typedef typename LeafType::ValueType VecT; - Coord ijk, end = start; - end[0] += dim; - end[1] += dim; - end[2] += dim; - - std::vector norms; - for (ijk[0] = start[0]; ijk[0] < end[0]; ++ijk[0]) { - for (ijk[1] = start[1]; ijk[1] < end[1]; ++ijk[1]) { - for (ijk[2] = start[2]; ijk[2] < end[2]; ++ijk[2]) { - - if(!leaf.isValueOn(ijk)) continue; - norms.push_back(leaf.getValue(ijk)); - } - } - } - - size_t N = norms.size(); - for (size_t ni = 0; ni < N; ++ni) { - VecT n_i = norms[ni]; - for (size_t nj = 0; nj < N; ++nj) { - VecT n_j = norms[nj]; - if ((1.0 - n_i.dot(n_j)) > adaptivity) return false; - } - } - return true; -} - - -//////////////////////////////////////// - - -template -class SignData -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef tree::ValueAccessor AccessorT; - - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef tree::ValueAccessor IntAccessorT; - - typedef typename TreeT::template ValueConverter::Type Int16TreeT; - typedef tree::ValueAccessor Int16AccessorT; - - ////////// - - - SignData(const TreeT& distTree, const LeafManagerT& leafs, ValueT iso); - - void run(bool threaded = true); - - typename Int16TreeT::Ptr signTree() const { return mSignTree; } - typename IntTreeT::Ptr idxTree() const { return mIdxTree; } - - ////////// - - SignData(SignData&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(const SignData& rhs) - { - mSignTree->merge(*rhs.mSignTree); - mIdxTree->merge(*rhs.mIdxTree); - } - -private: - - const TreeT& mDistTree; - AccessorT mDistAcc; - - const LeafManagerT& mLeafs; - ValueT mIsovalue; - - typename Int16TreeT::Ptr mSignTree; - Int16AccessorT mSignAcc; - - typename IntTreeT::Ptr mIdxTree; - IntAccessorT mIdxAcc; - -}; - - -template -SignData::SignData(const TreeT& distTree, - const LeafManagerT& leafs, ValueT iso) - : mDistTree(distTree) - , mDistAcc(mDistTree) - , mLeafs(leafs) - , mIsovalue(iso) - , mSignTree(new Int16TreeT(0)) - , mSignAcc(*mSignTree) - , mIdxTree(new IntTreeT(int(util::INVALID_IDX))) - , mIdxAcc(*mIdxTree) -{ -} - - -template -SignData::SignData(SignData& rhs, tbb::split) - : mDistTree(rhs.mDistTree) - , mDistAcc(mDistTree) - , mLeafs(rhs.mLeafs) - , mIsovalue(rhs.mIsovalue) - , mSignTree(new Int16TreeT(0)) - , mSignAcc(*mSignTree) - , mIdxTree(new IntTreeT(int(util::INVALID_IDX))) - , mIdxAcc(*mIdxTree) -{ -} - - -template -void -SignData::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mLeafs.getRange(), *this); - else (*this)(mLeafs.getRange()); -} - -template -void -SignData::operator()(const tbb::blocked_range& range) -{ - typedef typename Int16TreeT::LeafNodeType Int16LeafT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter; - unsigned char signs, face; - Coord ijk, coord; - - typename internal::UniquePtr::type signLeafPt(new Int16LeafT(ijk, 0)); - - for (size_t n = range.begin(); n != range.end(); ++n) { - - bool collectedData = false; - - coord = mLeafs.leaf(n).origin(); - - if (!signLeafPt.get()) signLeafPt.reset(new Int16LeafT(coord, 0)); - else signLeafPt->setOrigin(coord); - - const typename TreeT::LeafNodeType *leafPt = mDistAcc.probeConstLeaf(coord); - - coord.offset(TreeT::LeafNodeType::DIM - 1); - - for (iter = mLeafs.leaf(n).cbeginValueOn(); iter; ++iter) { - - ijk = iter.getCoord(); - - if (leafPt && ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]) { - signs = evalCellSigns(*leafPt, iter.pos(), mIsovalue); - } else { - signs = evalCellSigns(mDistAcc, ijk, mIsovalue); - } - - if (signs != 0 && signs != 0xFF) { - Int16 flags = (signs & 0x1) ? INSIDE : 0; - - if (bool(signs & 0x1) != bool(signs & 0x2)) flags |= XEDGE; - if (bool(signs & 0x1) != bool(signs & 0x10)) flags |= YEDGE; - if (bool(signs & 0x1) != bool(signs & 0x8)) flags |= ZEDGE; - - face = internal::sAmbiguousFace[signs]; - if (face != 0) correctCellSigns(signs, face, mDistAcc, ijk, mIsovalue); - - flags = Int16(flags | Int16(signs)); - - signLeafPt->setValue(ijk, flags); - collectedData = true; - } - } - - if (collectedData) { - - IntLeafT* idxLeaf = mIdxAcc.touchLeaf(coord); - idxLeaf->topologyUnion(*signLeafPt); - typename IntLeafT::ValueOnIter it = idxLeaf->beginValueOn(); - for (; it; ++it) { - it.setValue(0); - } - - mSignAcc.addLeaf(signLeafPt.release()); - } - } -} - - -//////////////////////////////////////// - - -/// @brief Counts the total number of points per leaf, accounts for cells with multiple points. -class CountPoints -{ -public: - CountPoints(std::vector& pointList) : mPointList(pointList) {} - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - size_t points = 0; - - typename LeafNodeType::ValueOnCIter iter = leaf.cbeginValueOn(); - for (; iter; ++iter) { - points += size_t(sEdgeGroupTable[(SIGNS & iter.getValue())][0]); - } - - mPointList[leafIndex] = points; - } - -private: - std::vector& mPointList; -}; - - -/// @brief Computes the point list indices for the index tree. -template -class MapPoints -{ -public: - typedef tree::ValueAccessor Int16AccessorT; - - MapPoints(std::vector& pointList, const Int16TreeT& signTree) - : mPointList(pointList) - , mSignAcc(signTree) - { - } - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - size_t ptnIdx = mPointList[leafIndex]; - typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn(); - - const typename Int16TreeT::LeafNodeType *signLeafPt = - mSignAcc.probeConstLeaf(leaf.origin()); - - for (; iter; ++iter) { - iter.setValue(static_cast(ptnIdx)); - unsigned signs = SIGNS & signLeafPt->getValue(iter.pos()); - ptnIdx += size_t(sEdgeGroupTable[signs][0]); - } - } - -private: - std::vector& mPointList; - Int16AccessorT mSignAcc; -}; - - -/// @brief Counts the total number of points per collapsed region -template -class CountRegions -{ -public: - typedef tree::ValueAccessor IntAccessorT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - - CountRegions(IntTreeT& idxTree, std::vector& regions) - : mIdxAcc(idxTree) - , mRegions(regions) - { - } - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - - size_t regions = 0; - - IntLeafT tmpLeaf(*mIdxAcc.probeConstLeaf(leaf.origin())); - - typename IntLeafT::ValueOnIter iter = tmpLeaf.beginValueOn(); - for (; iter; ++iter) { - if(iter.getValue() == 0) { - iter.setValueOff(); - regions += size_t(sEdgeGroupTable[(SIGNS & leaf.getValue(iter.pos()))][0]); - } - } - - int onVoxelCount = int(tmpLeaf.onVoxelCount()); - while (onVoxelCount > 0) { - ++regions; - iter = tmpLeaf.beginValueOn(); - int regionId = iter.getValue(); - for (; iter; ++iter) { - if (iter.getValue() == regionId) { - iter.setValueOff(); - --onVoxelCount; - } - } - } - - mRegions[leafIndex] = regions; - } - -private: - IntAccessorT mIdxAcc; - std::vector& mRegions; -}; - - -//////////////////////////////////////// - - -// @brief linear interpolation. -inline double evalRoot(double v0, double v1, double iso) { return (iso - v0) / (v1 - v0); } - - -/// @brief Extracts the eight corner values for leaf inclusive cells. -template -inline void -collectCornerValues(const LeafT& leaf, const Index offset, std::vector& values) -{ - values[0] = double(leaf.getValue(offset)); // i, j, k - values[3] = double(leaf.getValue(offset + 1)); // i, j, k+1 - values[4] = double(leaf.getValue(offset + LeafT::DIM)); // i, j+1, k - values[7] = double(leaf.getValue(offset + LeafT::DIM + 1)); // i, j+1, k+1 - values[1] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM))); // i+1, j, k - values[2] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1)); // i+1, j, k+1 - values[5] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM)); // i+1, j+1, k - values[6] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1)); // i+1, j+1, k+1 -} - - -/// @brief Extracts the eight corner values for a cell starting at the given @ijk coordinate. -template -inline void -collectCornerValues(const AccessorT& acc, const Coord& ijk, std::vector& values) -{ - Coord coord = ijk; - values[0] = double(acc.getValue(coord)); // i, j, k - - coord[0] += 1; - values[1] = double(acc.getValue(coord)); // i+1, j, k - - coord[2] += 1; - values[2] = double(acc.getValue(coord)); // i+i, j, k+1 - - coord[0] = ijk[0]; - values[3] = double(acc.getValue(coord)); // i, j, k+1 - - coord[1] += 1; coord[2] = ijk[2]; - values[4] = double(acc.getValue(coord)); // i, j+1, k - - coord[0] += 1; - values[5] = double(acc.getValue(coord)); // i+1, j+1, k - - coord[2] += 1; - values[6] = double(acc.getValue(coord)); // i+1, j+1, k+1 - - coord[0] = ijk[0]; - values[7] = double(acc.getValue(coord)); // i, j+1, k+1 -} - - -/// @brief Computes the average cell point for a given edge group. -inline Vec3d -computePoint(const std::vector& values, unsigned char signs, - unsigned char edgeGroup, double iso) -{ - Vec3d avg(0.0, 0.0, 0.0); - int samples = 0; - - if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1 - avg[0] += evalRoot(values[0], values[1], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2 - avg[0] += 1.0; - avg[2] += evalRoot(values[1], values[2], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2 - avg[0] += evalRoot(values[3], values[2], iso); - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3 - avg[2] += evalRoot(values[0], values[3], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5 - avg[0] += evalRoot(values[4], values[5], iso); - avg[1] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6 - avg[0] += 1.0; - avg[1] += 1.0; - avg[2] += evalRoot(values[5], values[6], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6 - avg[0] += evalRoot(values[7], values[6], iso); - avg[1] += 1.0; - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7 - avg[1] += 1.0; - avg[2] += evalRoot(values[4], values[7], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4 - avg[1] += evalRoot(values[0], values[4], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5 - avg[0] += 1.0; - avg[1] += evalRoot(values[1], values[5], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6 - avg[0] += 1.0; - avg[1] += evalRoot(values[2], values[6], iso); - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7 - avg[1] += evalRoot(values[3], values[7], iso); - avg[2] += 1.0; - ++samples; - } - - if (samples > 1) { - double w = 1.0 / double(samples); - avg[0] *= w; - avg[1] *= w; - avg[2] *= w; - } - - return avg; -} - - -/// @brief Computes the average cell point for a given edge group, ignoring edge -/// samples present in the @c signsMask configuration. -inline int -computeMaskedPoint(Vec3d& avg, const std::vector& values, unsigned char signs, - unsigned char signsMask, unsigned char edgeGroup, double iso) -{ - avg = Vec3d(0.0, 0.0, 0.0); - int samples = 0; - - if (sEdgeGroupTable[signs][1] == edgeGroup - && sEdgeGroupTable[signsMask][1] == 0) { // Edged: 0 - 1 - avg[0] += evalRoot(values[0], values[1], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][2] == edgeGroup - && sEdgeGroupTable[signsMask][2] == 0) { // Edged: 1 - 2 - avg[0] += 1.0; - avg[2] += evalRoot(values[1], values[2], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][3] == edgeGroup - && sEdgeGroupTable[signsMask][3] == 0) { // Edged: 3 - 2 - avg[0] += evalRoot(values[3], values[2], iso); - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][4] == edgeGroup - && sEdgeGroupTable[signsMask][4] == 0) { // Edged: 0 - 3 - avg[2] += evalRoot(values[0], values[3], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][5] == edgeGroup - && sEdgeGroupTable[signsMask][5] == 0) { // Edged: 4 - 5 - avg[0] += evalRoot(values[4], values[5], iso); - avg[1] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][6] == edgeGroup - && sEdgeGroupTable[signsMask][6] == 0) { // Edged: 5 - 6 - avg[0] += 1.0; - avg[1] += 1.0; - avg[2] += evalRoot(values[5], values[6], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][7] == edgeGroup - && sEdgeGroupTable[signsMask][7] == 0) { // Edged: 7 - 6 - avg[0] += evalRoot(values[7], values[6], iso); - avg[1] += 1.0; - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][8] == edgeGroup - && sEdgeGroupTable[signsMask][8] == 0) { // Edged: 4 - 7 - avg[1] += 1.0; - avg[2] += evalRoot(values[4], values[7], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][9] == edgeGroup - && sEdgeGroupTable[signsMask][9] == 0) { // Edged: 0 - 4 - avg[1] += evalRoot(values[0], values[4], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][10] == edgeGroup - && sEdgeGroupTable[signsMask][10] == 0) { // Edged: 1 - 5 - avg[0] += 1.0; - avg[1] += evalRoot(values[1], values[5], iso); - ++samples; - } - - if (sEdgeGroupTable[signs][11] == edgeGroup - && sEdgeGroupTable[signsMask][11] == 0) { // Edged: 2 - 6 - avg[0] += 1.0; - avg[1] += evalRoot(values[2], values[6], iso); - avg[2] += 1.0; - ++samples; - } - - if (sEdgeGroupTable[signs][12] == edgeGroup - && sEdgeGroupTable[signsMask][12] == 0) { // Edged: 3 - 7 - avg[1] += evalRoot(values[3], values[7], iso); - avg[2] += 1.0; - ++samples; - } - - if (samples > 1) { - double w = 1.0 / double(samples); - avg[0] *= w; - avg[1] *= w; - avg[2] *= w; - } - - return samples; -} - - -/// @brief Computes the average cell point for a given edge group, by computing -/// convex weights based on the distance from the sample point @c p. -inline Vec3d -computeWeightedPoint(const Vec3d& p, const std::vector& values, - unsigned char signs, unsigned char edgeGroup, double iso) -{ - std::vector samples; - samples.reserve(8); - - std::vector weights; - weights.reserve(8); - - Vec3d avg(0.0, 0.0, 0.0); - - if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1 - avg[0] = evalRoot(values[0], values[1], iso); - avg[1] = 0.0; - avg[2] = 0.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2 - avg[0] = 1.0; - avg[1] = 0.0; - avg[2] = evalRoot(values[1], values[2], iso); - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2 - avg[0] = evalRoot(values[3], values[2], iso); - avg[1] = 0.0; - avg[2] = 1.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3 - avg[0] = 0.0; - avg[1] = 0.0; - avg[2] = evalRoot(values[0], values[3], iso); - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5 - avg[0] = evalRoot(values[4], values[5], iso); - avg[1] = 1.0; - avg[2] = 0.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6 - avg[0] = 1.0; - avg[1] = 1.0; - avg[2] = evalRoot(values[5], values[6], iso); - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6 - avg[0] = evalRoot(values[7], values[6], iso); - avg[1] = 1.0; - avg[2] = 1.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7 - avg[0] = 0.0; - avg[1] = 1.0; - avg[2] = evalRoot(values[4], values[7], iso); - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4 - avg[0] = 0.0; - avg[1] = evalRoot(values[0], values[4], iso); - avg[2] = 0.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5 - avg[0] = 1.0; - avg[1] = evalRoot(values[1], values[5], iso); - avg[2] = 0.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6 - avg[0] = 1.0; - avg[1] = evalRoot(values[2], values[6], iso); - avg[2] = 1.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7 - avg[0] = 0.0; - avg[1] = evalRoot(values[3], values[7], iso); - avg[2] = 1.0; - - samples.push_back(avg); - weights.push_back((avg-p).lengthSqr()); - } - - - double minWeight = std::numeric_limits::max(); - double maxWeight = -std::numeric_limits::max(); - - for (size_t i = 0, I = weights.size(); i < I; ++i) { - minWeight = std::min(minWeight, weights[i]); - maxWeight = std::max(maxWeight, weights[i]); - } - - const double offset = maxWeight + minWeight * 0.1; - for (size_t i = 0, I = weights.size(); i < I; ++i) { - weights[i] = offset - weights[i]; - } - - - double weightSum = 0.0; - for (size_t i = 0, I = weights.size(); i < I; ++i) { - weightSum += weights[i]; - } - - avg[0] = 0.0; - avg[1] = 0.0; - avg[2] = 0.0; - - if (samples.size() > 1) { - for (size_t i = 0, I = samples.size(); i < I; ++i) { - avg += samples[i] * (weights[i] / weightSum); - } - } else { - avg = samples.front(); - } - - return avg; -} - - -/// @brief Computes the average cell points defined by the sign configuration -/// @c signs and the given corner values @c values. -inline void -computeCellPoints(std::vector& points, - const std::vector& values, unsigned char signs, double iso) -{ - for (size_t n = 1, N = sEdgeGroupTable[signs][0] + 1; n < N; ++n) { - points.push_back(computePoint(values, signs, uint8_t(n), iso)); - } -} - - -/// @brief Given a sign configuration @c lhsSigns and an edge group @c groupId, -/// finds the corresponding edge group in a different sign configuration -/// @c rhsSigns. Returns -1 if no match is found. -inline int -matchEdgeGroup(unsigned char groupId, unsigned char lhsSigns, unsigned char rhsSigns) -{ - int id = -1; - for (size_t i = 1; i <= 12; ++i) { - if (sEdgeGroupTable[lhsSigns][i] == groupId && sEdgeGroupTable[rhsSigns][i] != 0) { - id = sEdgeGroupTable[rhsSigns][i]; - break; - } - } - return id; -} - - -/// @brief Computes the average cell points defined by the sign configuration -/// @c signs and the given corner values @c values. Combines data from -/// two different level sets to eliminate seam lines when meshing -/// fractured segments. -inline void -computeCellPoints(std::vector& points, std::vector& weightedPointMask, - const std::vector& lhsValues, const std::vector& rhsValues, - unsigned char lhsSigns, unsigned char rhsSigns, - double iso, size_t pointIdx, const boost::scoped_array& seamPoints) -{ - for (size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) { - - int id = matchEdgeGroup(uint8_t(n), lhsSigns, rhsSigns); - - if (id != -1) { - - const unsigned char e = uint8_t(id); - uint32_t& quantizedPoint = seamPoints[pointIdx + (id - 1)]; - - if ((quantizedPoint & MASK_DIRTY_BIT) && !(quantizedPoint & MASK_INVALID_BIT)) { - Vec3d p = unpackPoint(quantizedPoint); - points.push_back(computeWeightedPoint(p, rhsValues, rhsSigns, e, iso)); - weightedPointMask.push_back(true); - } else { - points.push_back(computePoint(rhsValues, rhsSigns, e, iso)); - weightedPointMask.push_back(false); - } - - } else { - points.push_back(computePoint(lhsValues, lhsSigns, uint8_t(n), iso)); - weightedPointMask.push_back(false); - } - } -} - - -template -class GenPoints -{ -public: - typedef tree::ValueAccessor AccessorT; - - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef tree::ValueAccessor IntAccessorT; - typedef tree::ValueAccessor IntCAccessorT; - - typedef typename TreeT::template ValueConverter::Type Int16TreeT; - typedef tree::ValueAccessor Int16CAccessorT; - - typedef boost::scoped_array QuantizedPointList; - - ////////// - - - GenPoints(const LeafManagerT& signLeafs, const TreeT& distTree, - IntTreeT& idxTree, PointList& points, std::vector& indices, - const math::Transform& xform, double iso); - - void run(bool threaded = true); - - void setRefData(const Int16TreeT* refSignTree = NULL, const TreeT* refDistTree = NULL, - IntTreeT* refIdxTree = NULL, const QuantizedPointList* seamPoints = NULL, - std::vector* mSeamPointMaskPt = NULL); - - ////////// - - - void operator()(const tbb::blocked_range&) const; - -private: - const LeafManagerT& mSignLeafs; - - AccessorT mDistAcc; - IntTreeT& mIdxTree; - - PointList& mPoints; - std::vector& mIndices; - const math::Transform& mTransform; - const double mIsovalue; - - // reference data - const Int16TreeT *mRefSignTreePt; - const TreeT* mRefDistTreePt; - const IntTreeT* mRefIdxTreePt; - const QuantizedPointList* mSeamPointsPt; - std::vector* mSeamPointMaskPt; -}; - - -template -GenPoints::GenPoints(const LeafManagerT& signLeafs, - const TreeT& distTree, IntTreeT& idxTree, PointList& points, - std::vector& indices, const math::Transform& xform, double iso) - : mSignLeafs(signLeafs) - , mDistAcc(distTree) - , mIdxTree(idxTree) - , mPoints(points) - , mIndices(indices) - , mTransform(xform) - , mIsovalue(iso) - , mRefSignTreePt(NULL) - , mRefDistTreePt(NULL) - , mRefIdxTreePt(NULL) - , mSeamPointsPt(NULL) - , mSeamPointMaskPt(NULL) -{ -} - - -template -void -GenPoints::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this); - else (*this)(mSignLeafs.getRange()); -} - - -template -void -GenPoints::setRefData( - const Int16TreeT *refSignTree, - const TreeT *refDistTree, - IntTreeT* refIdxTree, - const QuantizedPointList* seamPoints, - std::vector* seamPointMask) -{ - mRefSignTreePt = refSignTree; - mRefDistTreePt = refDistTree; - mRefIdxTreePt = refIdxTree; - mSeamPointsPt = seamPoints; - mSeamPointMaskPt = seamPointMask; -} - - -template -void -GenPoints::operator()(const tbb::blocked_range& range) const -{ - typename IntTreeT::LeafNodeType::ValueOnIter iter; - unsigned char signs, refSigns; - Index offset; - Coord ijk, coord; - std::vector points(4); - std::vector weightedPointMask(4); - std::vector values(8), refValues(8); - - - IntAccessorT idxAcc(mIdxTree); - - // reference data accessors - boost::scoped_ptr refSignAcc; - if (mRefSignTreePt) refSignAcc.reset(new Int16CAccessorT(*mRefSignTreePt)); - - boost::scoped_ptr refIdxAcc; - if (mRefIdxTreePt) refIdxAcc.reset(new IntCAccessorT(*mRefIdxTreePt)); - - boost::scoped_ptr refDistAcc; - if (mRefDistTreePt) refDistAcc.reset(new AccessorT(*mRefDistTreePt)); - - - for (size_t n = range.begin(); n != range.end(); ++n) { - - coord = mSignLeafs.leaf(n).origin(); - - const typename TreeT::LeafNodeType *leafPt = mDistAcc.probeConstLeaf(coord); - typename IntTreeT::LeafNodeType *idxLeafPt = idxAcc.probeLeaf(coord); - - - // reference data leafs - const typename Int16TreeT::LeafNodeType *refSignLeafPt = NULL; - if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(coord); - - const typename IntTreeT::LeafNodeType *refIdxLeafPt = NULL; - if (refIdxAcc) refIdxLeafPt = refIdxAcc->probeConstLeaf(coord); - - const typename TreeT::LeafNodeType *refDistLeafPt = NULL; - if (refDistAcc) refDistLeafPt = refDistAcc->probeConstLeaf(coord); - - - // generate cell points - size_t ptnIdx = mIndices[n]; - coord.offset(TreeT::LeafNodeType::DIM - 1); - - - - for (iter = idxLeafPt->beginValueOn(); iter; ++iter) { - - if(iter.getValue() != 0) continue; - - iter.setValue(static_cast(ptnIdx)); - iter.setValueOff(); - offset = iter.pos(); - ijk = iter.getCoord(); - - const bool inclusiveCell = ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]; - - const Int16& flags = mSignLeafs.leaf(n).getValue(offset); - signs = uint8_t(SIGNS & flags); - refSigns = 0; - - if ((flags & SEAM) && refSignLeafPt && refIdxLeafPt) { - if (refSignLeafPt->isValueOn(offset)) { - refSigns = uint8_t(SIGNS & refSignLeafPt->getValue(offset)); - } - } - - - if (inclusiveCell) collectCornerValues(*leafPt, offset, values); - else collectCornerValues(mDistAcc, ijk, values); - - - points.clear(); - weightedPointMask.clear(); - - if (refSigns == 0) { - computeCellPoints(points, values, signs, mIsovalue); - } else { - - if (inclusiveCell) collectCornerValues(*refDistLeafPt, offset, refValues); - else collectCornerValues(*refDistAcc, ijk, refValues); - - computeCellPoints(points, weightedPointMask, values, refValues, signs, refSigns, - mIsovalue, refIdxLeafPt->getValue(offset), *mSeamPointsPt); - } - - - for (size_t i = 0, I = points.size(); i < I; ++i) { - - // offset by cell-origin - points[i][0] += double(ijk[0]); - points[i][1] += double(ijk[1]); - points[i][2] += double(ijk[2]); - - - points[i] = mTransform.indexToWorld(points[i]); - - mPoints[ptnIdx][0] = float(points[i][0]); - mPoints[ptnIdx][1] = float(points[i][1]); - mPoints[ptnIdx][2] = float(points[i][2]); - - if (mSeamPointMaskPt && !weightedPointMask.empty() && weightedPointMask[i]) { - (*mSeamPointMaskPt)[ptnIdx] = 1; - } - - ++ptnIdx; - } - } - - // generate collapsed region points - int onVoxelCount = int(idxLeafPt->onVoxelCount()); - while (onVoxelCount > 0) { - - iter = idxLeafPt->beginValueOn(); - int regionId = iter.getValue(), count = 0; - - Vec3d avg(0.0), point; - - for (; iter; ++iter) { - if (iter.getValue() != regionId) continue; - - iter.setValue(static_cast(ptnIdx)); - iter.setValueOff(); - --onVoxelCount; - - ijk = iter.getCoord(); - offset = iter.pos(); - - signs = uint8_t(SIGNS & mSignLeafs.leaf(n).getValue(offset)); - - if (ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]) { - collectCornerValues(*leafPt, offset, values); - } else { - collectCornerValues(mDistAcc, ijk, values); - } - - points.clear(); - computeCellPoints(points, values, signs, mIsovalue); - - avg[0] += double(ijk[0]) + points[0][0]; - avg[1] += double(ijk[1]) + points[0][1]; - avg[2] += double(ijk[2]) + points[0][2]; - - ++count; - } - - - if (count > 1) { - double w = 1.0 / double(count); - avg[0] *= w; - avg[1] *= w; - avg[2] *= w; - } - - avg = mTransform.indexToWorld(avg); - - mPoints[ptnIdx][0] = float(avg[0]); - mPoints[ptnIdx][1] = float(avg[1]); - mPoints[ptnIdx][2] = float(avg[2]); - - ++ptnIdx; - } - } -} - - -//////////////////////////////////////// - - -template -class SeamWeights -{ -public: - typedef tree::ValueAccessor AccessorT; - - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef tree::ValueAccessor IntAccessorT; - - typedef typename TreeT::template ValueConverter::Type Int16TreeT; - typedef tree::ValueAccessor Int16AccessorT; - - typedef boost::scoped_array QuantizedPointList; - - ////////// - - SeamWeights(const TreeT& distTree, const Int16TreeT& refSignTree, - IntTreeT& refIdxTree, QuantizedPointList& points, double iso); - - template - void operator()(LeafNodeType &signLeaf, size_t leafIndex) const; - -private: - AccessorT mDistAcc; - Int16AccessorT mRefSignAcc; - IntAccessorT mRefIdxAcc; - - QuantizedPointList& mPoints; - const double mIsovalue; -}; - - -template -SeamWeights::SeamWeights(const TreeT& distTree, const Int16TreeT& refSignTree, - IntTreeT& refIdxTree, QuantizedPointList& points, double iso) - : mDistAcc(distTree) - , mRefSignAcc(refSignTree) - , mRefIdxAcc(refIdxTree) - , mPoints(points) - , mIsovalue(iso) -{ -} - - -template -template -void -SeamWeights::operator()(LeafNodeType &signLeaf, size_t /*leafIndex*/) const -{ - Coord coord = signLeaf.origin(); - const typename Int16TreeT::LeafNodeType *refSignLeafPt = mRefSignAcc.probeConstLeaf(coord); - - if (!refSignLeafPt) return; - - const typename TreeT::LeafNodeType *distLeafPt = mDistAcc.probeConstLeaf(coord); - const typename IntTreeT::LeafNodeType *refIdxLeafPt = mRefIdxAcc.probeConstLeaf(coord); - - std::vector values(8); - unsigned char lhsSigns, rhsSigns; - Vec3d point; - Index offset; - - Coord ijk; - coord.offset(TreeT::LeafNodeType::DIM - 1); - - typename LeafNodeType::ValueOnCIter iter = signLeaf.cbeginValueOn(); - for (; iter; ++iter) { - - offset = iter.pos(); - ijk = iter.getCoord(); - - const bool inclusiveCell = ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]; - - if ((iter.getValue() & SEAM) && refSignLeafPt->isValueOn(offset)) { - - lhsSigns = uint8_t(SIGNS & iter.getValue()); - rhsSigns = uint8_t(SIGNS & refSignLeafPt->getValue(offset)); - - - if (inclusiveCell) { - collectCornerValues(*distLeafPt, offset, values); - } else { - collectCornerValues(mDistAcc, ijk, values); - } - - - for (size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) { - - int id = matchEdgeGroup(uint8_t(n), lhsSigns, rhsSigns); - - if (id != -1) { - - uint32_t& data = mPoints[refIdxLeafPt->getValue(offset) + (id - 1)]; - - if (!(data & MASK_DIRTY_BIT)) { - - int smaples = computeMaskedPoint( - point, values, lhsSigns, rhsSigns, uint8_t(n), mIsovalue); - - if (smaples > 0) data = packPoint(point); - else data = MASK_INVALID_BIT; - - data |= MASK_DIRTY_BIT; - } - } - } - } - } -} - - -//////////////////////////////////////// - - -template -class MergeVoxelRegions -{ -public: - typedef typename TreeT::ValueType ValueT; - typedef tree::ValueAccessor AccessorT; - - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef tree::ValueAccessor IntAccessorT; - - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - - typedef typename LeafManagerT::TreeType::template ValueConverter::Type Int16TreeT; - typedef tree::ValueAccessor Int16AccessorT; - - typedef typename TreeT::template ValueConverter::Type FloatTreeT; - typedef Grid FloatGridT; - - - ////////// - - MergeVoxelRegions(const LeafManagerT& signLeafs, const Int16TreeT& signTree, - const TreeT& distTree, IntTreeT& idxTree, ValueT iso, ValueT adaptivity); - - void run(bool threaded = true); - - void setSpatialAdaptivity( - const math::Transform& distGridXForm, const FloatGridT& adaptivityField); - - void setAdaptivityMask(const BoolTreeT* mask); - - void setRefData(const Int16TreeT* signTree, ValueT adaptivity); - - ////////// - - - void operator()(const tbb::blocked_range&) const; - -private: - - const LeafManagerT& mSignLeafs; - - const Int16TreeT& mSignTree; - Int16AccessorT mSignAcc; - - const TreeT& mDistTree; - AccessorT mDistAcc; - - IntTreeT& mIdxTree; - ValueT mIsovalue, mSurfaceAdaptivity, mInternalAdaptivity; - - const math::Transform* mTransform; - const FloatGridT* mAdaptivityGrid; - const BoolTreeT* mAdaptivityMask; - - const Int16TreeT* mRefSignTree; -}; - - -template -MergeVoxelRegions::MergeVoxelRegions( - const LeafManagerT& signLeafs, const Int16TreeT& signTree, - const TreeT& distTree, IntTreeT& idxTree, ValueT iso, ValueT adaptivity) - : mSignLeafs(signLeafs) - , mSignTree(signTree) - , mSignAcc(mSignTree) - , mDistTree(distTree) - , mDistAcc(mDistTree) - , mIdxTree(idxTree) - , mIsovalue(iso) - , mSurfaceAdaptivity(adaptivity) - , mInternalAdaptivity(adaptivity) - , mTransform(NULL) - , mAdaptivityGrid(NULL) - , mAdaptivityMask(NULL) - , mRefSignTree(NULL) -{ -} - - -template -void -MergeVoxelRegions::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this); - else (*this)(mSignLeafs.getRange()); -} - - -template -void -MergeVoxelRegions::setSpatialAdaptivity( - const math::Transform& distGridXForm, const FloatGridT& adaptivityField) -{ - mTransform = &distGridXForm; - mAdaptivityGrid = &adaptivityField; -} - - -template -void -MergeVoxelRegions::setAdaptivityMask(const BoolTreeT* mask) -{ - mAdaptivityMask = mask; -} - -template -void -MergeVoxelRegions::setRefData(const Int16TreeT* signTree, ValueT adaptivity) -{ - mRefSignTree = signTree; - mInternalAdaptivity = adaptivity; -} - - -template -void -MergeVoxelRegions::operator()(const tbb::blocked_range& range) const -{ - typedef math::Vec3 Vec3T; - - typedef typename TreeT::LeafNodeType LeafT; - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typedef typename LeafT::template ValueConverter::Type Vec3LeafT; - - const int LeafDim = LeafT::DIM; - - IntAccessorT idxAcc(mIdxTree); - - typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter; - - typedef typename tree::ValueAccessor FloatTreeCAccessorT; - boost::scoped_ptr adaptivityAcc; - if (mAdaptivityGrid) { - adaptivityAcc.reset(new FloatTreeCAccessorT(mAdaptivityGrid->tree())); - } - - typedef typename tree::ValueAccessor Int16TreeCAccessorT; - boost::scoped_ptr refAcc; - if (mRefSignTree) { - refAcc.reset(new Int16TreeCAccessorT(*mRefSignTree)); - } - - typedef typename tree::ValueAccessor BoolTreeCAccessorT; - boost::scoped_ptr maskAcc; - if (mAdaptivityMask) { - maskAcc.reset(new BoolTreeCAccessorT(*mAdaptivityMask)); - } - - - BoolLeafT mask; - Vec3LeafT gradients; - Coord ijk, end; - - for (size_t n = range.begin(); n != range.end(); ++n) { - - mask.setValuesOff(); - - const Coord& origin = mSignLeafs.leaf(n).origin(); - - ValueT adaptivity = (refAcc && !refAcc->probeConstLeaf(origin)) ? - mInternalAdaptivity : mSurfaceAdaptivity; - - IntLeafT& idxLeaf = *idxAcc.probeLeaf(origin); - - end[0] = origin[0] + LeafDim; - end[1] = origin[1] + LeafDim; - end[2] = origin[2] + LeafDim; - - // Mask off seam line adjacent voxels - if (maskAcc) { - const BoolLeafT* maskLeaf = maskAcc->probeConstLeaf(origin); - if (maskLeaf != NULL) { - typename BoolLeafT::ValueOnCIter it; - for (it = maskLeaf->cbeginValueOn(); it; ++it) { - mask.setActiveState(it.getCoord() & ~1u, true); - } - } - } - - // Set region adaptivity - LeafT adaptivityLeaf(origin, adaptivity); - if (mAdaptivityGrid) { - for (Index offset = 0; offset < LeafT::NUM_VALUES; ++offset) { - ijk = adaptivityLeaf.offsetToGlobalCoord(offset); - Vec3d xyz = mAdaptivityGrid->transform().worldToIndex( - mTransform->indexToWorld(ijk)); - ValueT tmpA = ValueT(adaptivityAcc->getValue(util::nearestCoord(xyz))); - adaptivityLeaf.setValueOnly(offset, tmpA * adaptivity); - } - } - - // Mask off ambiguous voxels - for (iter = mSignLeafs.leaf(n).cbeginValueOn(); iter; ++iter) { - unsigned char signs = static_cast(SIGNS & int(iter.getValue())); - if (!sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) { - mask.setActiveState(iter.getCoord() & ~1u, true); - } - } - - // Mask off topologically ambiguous 2x2x2 voxel sub-blocks - int dim = 2; - for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) { - for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) { - for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) { - if (!mask.isValueOn(ijk) & isNonManifold(mDistAcc, ijk, mIsovalue, dim)) { - mask.setActiveState(ijk, true); - } - } - } - } - - // Compute the gradient for the remaining voxels - gradients.setValuesOff(); - for (iter = mSignLeafs.leaf(n).cbeginValueOn(); iter; ++iter) { - ijk = iter.getCoord(); - if(!mask.isValueOn(ijk & ~1u)) { - Vec3T dir(math::ISGradient::result(mDistAcc, ijk)); - dir.normalize(); - gradients.setValueOn(iter.pos(), dir); - } - } - - // Merge regions - int regionId = 1; - for ( ; dim <= LeafDim; dim = dim << 1) { - const unsigned coordMask = ~((dim << 1) - 1); - for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) { - for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) { - for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) { - - adaptivity = adaptivityLeaf.getValue(ijk); - - if (mask.isValueOn(ijk) || isNonManifold(mDistAcc, ijk, mIsovalue, dim) - || !isMergable(gradients, ijk, dim, adaptivity)) { - mask.setActiveState(ijk & coordMask, true); - } else { - mergeVoxels(idxLeaf, ijk, dim, regionId++); - } - } - } - } - } - } -} - - -//////////////////////////////////////// - - -// Constructs qudas -struct UniformPrimBuilder -{ - UniformPrimBuilder(): mIdx(0), mPolygonPool(NULL) {} - - void init(const size_t upperBound, PolygonPool& quadPool) - { - mPolygonPool = &quadPool; - mPolygonPool->resetQuads(upperBound); - mIdx = 0; - } - - void addPrim(const Vec4I& verts, bool reverse, char flags = 0) - { - if (!reverse) { - mPolygonPool->quad(mIdx) = verts; - } else { - Vec4I& quad = mPolygonPool->quad(mIdx); - quad[0] = verts[3]; - quad[1] = verts[2]; - quad[2] = verts[1]; - quad[3] = verts[0]; - } - mPolygonPool->quadFlags(mIdx) = flags; - ++mIdx; - } - - void done() - { - mPolygonPool->trimQuads(mIdx); - } - -private: - size_t mIdx; - PolygonPool* mPolygonPool; -}; - - -// Constructs qudas and triangles -struct AdaptivePrimBuilder -{ - AdaptivePrimBuilder() : mQuadIdx(0), mTriangleIdx(0), mPolygonPool(NULL) {} - - void init(const size_t upperBound, PolygonPool& polygonPool) - { - mPolygonPool = &polygonPool; - mPolygonPool->resetQuads(upperBound); - mPolygonPool->resetTriangles(upperBound); - - mQuadIdx = 0; - mTriangleIdx = 0; - } - - void addPrim(const Vec4I& verts, bool reverse, char flags = 0) - { - if (verts[0] != verts[1] && verts[0] != verts[2] && verts[0] != verts[3] - && verts[1] != verts[2] && verts[1] != verts[3] && verts[2] != verts[3]) { - mPolygonPool->quadFlags(mQuadIdx) = flags; - addQuad(verts, reverse); - } else if ( - verts[0] == verts[3] && - verts[1] != verts[2] && - verts[1] != verts[0] && - verts[2] != verts[0]) { - mPolygonPool->triangleFlags(mTriangleIdx) = flags; - addTriangle(verts[0], verts[1], verts[2], reverse); - } else if ( - verts[1] == verts[2] && - verts[0] != verts[3] && - verts[0] != verts[1] && - verts[3] != verts[1]) { - mPolygonPool->triangleFlags(mTriangleIdx) = flags; - addTriangle(verts[0], verts[1], verts[3], reverse); - } else if ( - verts[0] == verts[1] && - verts[2] != verts[3] && - verts[2] != verts[0] && - verts[3] != verts[0]) { - mPolygonPool->triangleFlags(mTriangleIdx) = flags; - addTriangle(verts[0], verts[2], verts[3], reverse); - } else if ( - verts[2] == verts[3] && - verts[0] != verts[1] && - verts[0] != verts[2] && - verts[1] != verts[2]) { - mPolygonPool->triangleFlags(mTriangleIdx) = flags; - addTriangle(verts[0], verts[1], verts[2], reverse); - } - } - - - void done() - { - mPolygonPool->trimQuads(mQuadIdx, /*reallocate=*/true); - mPolygonPool->trimTrinagles(mTriangleIdx, /*reallocate=*/true); - } - -private: - - void addQuad(const Vec4I& verts, bool reverse) - { - if (!reverse) { - mPolygonPool->quad(mQuadIdx) = verts; - } else { - Vec4I& quad = mPolygonPool->quad(mQuadIdx); - quad[0] = verts[3]; - quad[1] = verts[2]; - quad[2] = verts[1]; - quad[3] = verts[0]; - } - ++mQuadIdx; - } - - void addTriangle(unsigned v0, unsigned v1, unsigned v2, bool reverse) - { - Vec3I& prim = mPolygonPool->triangle(mTriangleIdx); - - prim[1] = v1; - - if (!reverse) { - prim[0] = v0; - prim[2] = v2; - } else { - prim[0] = v2; - prim[2] = v0; - } - ++mTriangleIdx; - } - - size_t mQuadIdx, mTriangleIdx; - PolygonPool *mPolygonPool; -}; - - -template -inline void -constructPolygons(Int16 flags, Int16 refFlags, const Vec4i& offsets, const Coord& ijk, - const SignAccT& signAcc, const IdxAccT& idxAcc, PrimBuilder& mesher, Index32 pointListSize) -{ - const Index32 v0 = idxAcc.getValue(ijk); - if (v0 == util::INVALID_IDX) return; - - char tag[2]; - tag[0] = (flags & SEAM) ? POLYFLAG_FRACTURE_SEAM : 0; - tag[1] = tag[0] | char(POLYFLAG_EXTERIOR); - - const bool isInside = flags & INSIDE; - - Coord coord; - openvdb::Vec4I quad; - unsigned char cell; - Index32 tmpIdx = 0; - - if (flags & XEDGE) { - - quad[0] = v0 + offsets[0]; - - // i, j-1, k - coord[0] = ijk[0]; - coord[1] = ijk[1] - 1; - coord[2] = ijk[2]; - - quad[1] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][5] - 1); - if (tmpIdx < pointListSize) quad[1] = tmpIdx; - } - - // i, j-1, k-1 - coord[2] -= 1; - - quad[2] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][7] - 1); - if (tmpIdx < pointListSize) quad[2] = tmpIdx; - } - - // i, j, k-1 - coord[1] = ijk[1]; - - quad[3] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][3] - 1); - if (tmpIdx < pointListSize) quad[3] = tmpIdx; - } - - if (quad[1] != util::INVALID_IDX && - quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) { - mesher.addPrim(quad, isInside, tag[bool(refFlags & XEDGE)]); - } - } - - - if (flags & YEDGE) { - - quad[0] = v0 + offsets[1]; - - // i, j, k-1 - coord[0] = ijk[0]; - coord[1] = ijk[1]; - coord[2] = ijk[2] - 1; - - quad[1] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][12] - 1); - if (tmpIdx < pointListSize) quad[1] = tmpIdx; - } - - // i-1, j, k-1 - coord[0] -= 1; - - quad[2] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][11] - 1); - if (tmpIdx < pointListSize) quad[2] = tmpIdx; - } - - // i-1, j, k - coord[2] = ijk[2]; - - quad[3] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][10] - 1); - if (tmpIdx < pointListSize) quad[3] = tmpIdx; - } - - if (quad[1] != util::INVALID_IDX && - quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) { - mesher.addPrim(quad, isInside, tag[bool(refFlags & YEDGE)]); - } - } - - if (flags & ZEDGE) { - - quad[0] = v0 + offsets[2]; - - // i, j-1, k - coord[0] = ijk[0]; - coord[1] = ijk[1] - 1; - coord[2] = ijk[2]; - - quad[1] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][8] - 1); - if (tmpIdx < pointListSize) quad[1] = tmpIdx; - } - - // i-1, j-1, k - coord[0] -= 1; - - quad[2] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][6] - 1); - if (tmpIdx < pointListSize) quad[2] = tmpIdx; - } - - // i-1, j, k - coord[1] = ijk[1]; - - quad[3] = idxAcc.getValue(coord); - cell = uint8_t(SIGNS & signAcc.getValue(coord)); - if (sEdgeGroupTable[cell][0] > 1) { - tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][2] - 1); - if (tmpIdx < pointListSize) quad[3] = tmpIdx; - } - - if (quad[1] != util::INVALID_IDX && - quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) { - mesher.addPrim(quad, !isInside, tag[bool(refFlags & ZEDGE)]); - } - } -} - - -//////////////////////////////////////// - - -template -class GenPolygons -{ -public: - typedef typename LeafManagerT::TreeType::template ValueConverter::Type IntTreeT; - typedef typename LeafManagerT::TreeType::template ValueConverter::Type Int16TreeT; - - typedef tree::ValueAccessor IntAccessorT; - typedef tree::ValueAccessor Int16AccessorT; - - ////////// - - - GenPolygons(const LeafManagerT& signLeafs, const Int16TreeT& signTree, - const IntTreeT& idxTree, PolygonPoolList& polygons, Index32 pointListSize); - - void run(bool threaded = true); - - - void setRefSignTree(const Int16TreeT *r) { mRefSignTree = r; } - - ////////// - - - void operator()(const tbb::blocked_range&) const; - -private: - const LeafManagerT& mSignLeafs; - const Int16TreeT& mSignTree; - const IntTreeT& mIdxTree; - const PolygonPoolList& mPolygonPoolList; - const Index32 mPointListSize; - - const Int16TreeT *mRefSignTree; - }; - - -template -GenPolygons::GenPolygons(const LeafManagerT& signLeafs, - const Int16TreeT& signTree, const IntTreeT& idxTree, PolygonPoolList& polygons, - Index32 pointListSize) - : mSignLeafs(signLeafs) - , mSignTree(signTree) - , mIdxTree(idxTree) - , mPolygonPoolList(polygons) - , mPointListSize(pointListSize) - , mRefSignTree(NULL) -{ -} - -template -void -GenPolygons::run(bool threaded) -{ - if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this); - else (*this)(mSignLeafs.getRange()); -} - -template -void -GenPolygons::operator()( - const tbb::blocked_range& range) const -{ - typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter; - IntAccessorT idxAcc(mIdxTree); - Int16AccessorT signAcc(mSignTree); - - - PrimBuilder mesher; - size_t edgeCount; - Coord ijk, origin; - - - // reference data - boost::scoped_ptr refSignAcc; - if (mRefSignTree) refSignAcc.reset(new Int16AccessorT(*mRefSignTree)); - - - for (size_t n = range.begin(); n != range.end(); ++n) { - - origin = mSignLeafs.leaf(n).origin(); - - // Get an upper bound on the number of primitives. - edgeCount = 0; - iter = mSignLeafs.leaf(n).cbeginValueOn(); - for (; iter; ++iter) { - if (iter.getValue() & XEDGE) ++edgeCount; - if (iter.getValue() & YEDGE) ++edgeCount; - if (iter.getValue() & ZEDGE) ++edgeCount; - } - - if(edgeCount == 0) continue; - - mesher.init(edgeCount, mPolygonPoolList[n]); - - const typename Int16TreeT::LeafNodeType *signleafPt = signAcc.probeConstLeaf(origin); - const typename IntTreeT::LeafNodeType *idxLeafPt = idxAcc.probeConstLeaf(origin); - - if (!signleafPt || !idxLeafPt) continue; - - - const typename Int16TreeT::LeafNodeType *refSignLeafPt = NULL; - if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(origin); - - Vec4i offsets; - - iter = mSignLeafs.leaf(n).cbeginValueOn(); - for (; iter; ++iter) { - ijk = iter.getCoord(); - - Int16 flags = iter.getValue(); - - if (!(flags & 0xE00)) continue; - - Int16 refFlags = 0; - if (refSignLeafPt) { - refFlags = refSignLeafPt->getValue(iter.pos()); - } - - offsets[0] = 0; - offsets[1] = 0; - offsets[2] = 0; - - const unsigned char cell = uint8_t(SIGNS & flags); - - if (sEdgeGroupTable[cell][0] > 1) { - offsets[0] = (sEdgeGroupTable[cell][1] - 1); - offsets[1] = (sEdgeGroupTable[cell][9] - 1); - offsets[2] = (sEdgeGroupTable[cell][4] - 1); - } - - if (ijk[0] > origin[0] && ijk[1] > origin[1] && ijk[2] > origin[2]) { - constructPolygons(flags, refFlags, offsets, ijk, - *signleafPt, *idxLeafPt, mesher, mPointListSize); - } else { - constructPolygons(flags, refFlags, offsets, ijk, - signAcc, idxAcc, mesher, mPointListSize); - } - } - - mesher.done(); - } -} - - -//////////////////////////////////////// - -// Masking and mesh partitioning - -struct PartOp -{ - - PartOp(size_t leafCount, size_t partitions, size_t activePart) - { - size_t leafSegments = leafCount / partitions; - mStart = leafSegments * activePart; - mEnd = activePart >= (partitions - 1) ? leafCount : mStart + leafSegments; - } - - template - void operator()(LeafNodeType &leaf, size_t leafIndex) const - { - if (leafIndex < mStart || leafIndex >= mEnd) leaf.setValuesOff(); - } - -private: - size_t mStart, mEnd; -}; - - -//////////////////////////////////////// - - -template -class PartGen -{ -public: - typedef tree::LeafManager LeafManagerT; - typedef typename SrcTreeT::template ValueConverter::Type BoolTreeT; - typedef tree::ValueAccessor BoolAccessorT; - - ////////// - - - PartGen(const LeafManagerT& leafs, size_t partitions, size_t activePart); - - void run(bool threaded = true); - - BoolTreeT& tree() { return mTree; } - - - ////////// - - PartGen(PartGen&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(PartGen& rhs) { mTree.merge(rhs.mTree); } - -private: - const LeafManagerT& mLeafManager; - BoolTreeT mTree; - size_t mStart, mEnd; -}; - -template -PartGen::PartGen(const LeafManagerT& leafs, size_t partitions, size_t activePart) - : mLeafManager(leafs) - , mTree(false) - , mStart(0) - , mEnd(0) -{ - size_t leafCount = leafs.leafCount(); - size_t leafSegments = leafCount / partitions; - mStart = leafSegments * activePart; - mEnd = activePart >= (partitions - 1) ? leafCount : mStart + leafSegments; -} - -template -PartGen::PartGen(PartGen& rhs, tbb::split) - : mLeafManager(rhs.mLeafManager) - , mTree(false) - , mStart(rhs.mStart) - , mEnd(rhs.mEnd) -{ -} - - -template -void -PartGen::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mLeafManager.getRange(), *this); - else (*this)(mLeafManager.getRange()); -} - - -template -void -PartGen::operator()(const tbb::blocked_range& range) -{ - Coord ijk; - BoolAccessorT acc(mTree); - - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - typename SrcTreeT::LeafNodeType::ValueOnCIter iter; - - for (size_t n = range.begin(); n != range.end(); ++n) { - if (n < mStart || n >= mEnd) continue; - BoolLeafT* leaf = acc.touchLeaf(mLeafManager.leaf(n).origin()); - leaf->topologyUnion(mLeafManager.leaf(n)); - } -} - - -//////////////////////////////////////// - - -template -class GenSeamMask -{ -public: - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - - ////////// - - GenSeamMask(const LeafManagerT& leafs, const TreeT& tree); - - void run(bool threaded = true); - - BoolTreeT& mask() { return mMaskTree; } - - ////////// - - GenSeamMask(GenSeamMask&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(GenSeamMask& rhs) { mMaskTree.merge(rhs.mMaskTree); } - -private: - - const LeafManagerT& mLeafManager; - const TreeT& mTree; - - BoolTreeT mMaskTree; -}; - - -template -GenSeamMask::GenSeamMask(const LeafManagerT& leafs, const TreeT& tree) - : mLeafManager(leafs) - , mTree(tree) - , mMaskTree(false) -{ -} - - -template -GenSeamMask::GenSeamMask(GenSeamMask& rhs, tbb::split) - : mLeafManager(rhs.mLeafManager) - , mTree(rhs.mTree) - , mMaskTree(false) -{ -} - - -template -void -GenSeamMask::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(mLeafManager.getRange(), *this); - else (*this)(mLeafManager.getRange()); -} - - -template -void -GenSeamMask::operator()(const tbb::blocked_range& range) -{ - Coord ijk; - tree::ValueAccessor acc(mTree); - tree::ValueAccessor maskAcc(mMaskTree); - - typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter it; - - for (size_t n = range.begin(); n != range.end(); ++n) { - - it = mLeafManager.leaf(n).cbeginValueOn(); - - for (; it; ++it) { - - ijk = it.getCoord(); - - unsigned char rhsSigns = uint8_t(acc.getValue(ijk) & SIGNS); - - if (sEdgeGroupTable[rhsSigns][0] > 0) { - unsigned char lhsSigns = uint8_t(it.getValue() & SIGNS); - if (rhsSigns != lhsSigns) { - maskAcc.setValueOn(ijk); - } - } - } - } -} - - -//////////////////////////////////////// - - -template -class TagSeamEdges -{ -public: - typedef tree::ValueAccessor AccessorT; - - TagSeamEdges(const TreeT& tree) : mAcc(tree) {} - - template - void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const - { - const typename TreeT::LeafNodeType *maskLeaf = - mAcc.probeConstLeaf(leaf.origin()); - - if (!maskLeaf) return; - - typename LeafNodeType::ValueOnIter it = leaf.beginValueOn(); - - for (; it; ++it) { - - if (maskLeaf->isValueOn(it.pos())) { - it.setValue(it.getValue() | SEAM); - } - } - } - -private: - AccessorT mAcc; -}; - - - -template -struct MaskEdges -{ - typedef tree::ValueAccessor BoolAccessorT; - - MaskEdges(const BoolTreeT& valueMask) : mMaskAcc(valueMask) {} - - template - void operator()(LeafNodeType &leaf, size_t /*leafIndex*/) const - { - typename LeafNodeType::ValueOnIter it = leaf.beginValueOn(); - - const typename BoolTreeT::LeafNodeType * maskLeaf = - mMaskAcc.probeConstLeaf(leaf.origin()); - - if (maskLeaf) { - for (; it; ++it) { - if (!maskLeaf->isValueOn(it.pos())) { - it.setValue(0x1FF & it.getValue()); - } - } - } else { - for (; it; ++it) { - it.setValue(0x1FF & it.getValue()); - } - } - } - -private: - BoolAccessorT mMaskAcc; -}; - - -class FlagUsedPoints -{ -public: - ////////// - - FlagUsedPoints(const PolygonPoolList& polygons, size_t polyListCount, - std::vector& usedPointMask) - : mPolygons(polygons) - , mPolyListCount(polyListCount) - , mUsedPointMask(usedPointMask) - { - } - - void run(bool threaded = true) - { - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mPolyListCount), *this); - } else { - (*this)(tbb::blocked_range(0, mPolyListCount)); - } - } - - ////////// - - void operator()(const tbb::blocked_range& range) const - { - // Concurrent writes to same memory address can occur, but - // all threads are writing the same value and char is atomic. - for (size_t n = range.begin(); n != range.end(); ++n) { - const PolygonPool& polygons = mPolygons[n]; - for (size_t i = 0; i < polygons.numQuads(); ++i) { - const Vec4I& quad = polygons.quad(i); - mUsedPointMask[quad[0]] = 1; - mUsedPointMask[quad[1]] = 1; - mUsedPointMask[quad[2]] = 1; - mUsedPointMask[quad[3]] = 1; - } - - for (size_t i = 0; i < polygons.numTriangles(); ++i) { - const Vec3I& triangle = polygons.triangle(i); - mUsedPointMask[triangle[0]] = 1; - mUsedPointMask[triangle[1]] = 1; - mUsedPointMask[triangle[2]] = 1; - } - } - } - - -private: - const PolygonPoolList& mPolygons; - size_t mPolyListCount; - std::vector& mUsedPointMask; -}; - -class RemapIndices -{ -public: - ////////// - - RemapIndices(PolygonPoolList& polygons, - size_t polyListCount, const std::vector& indexMap) - : mPolygons(polygons) - , mPolyListCount(polyListCount) - , mIndexMap(indexMap) - { - } - - void run(bool threaded = true) - { - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mPolyListCount), *this); - } else { - (*this)(tbb::blocked_range(0, mPolyListCount)); - } - } - - ////////// - - void operator()(const tbb::blocked_range& range) const - { - for (size_t n = range.begin(); n != range.end(); ++n) { - PolygonPool& polygons = mPolygons[n]; - for (size_t i = 0; i < polygons.numQuads(); ++i) { - Vec4I& quad = polygons.quad(i); - quad[0] = mIndexMap[quad[0]]; - quad[1] = mIndexMap[quad[1]]; - quad[2] = mIndexMap[quad[2]]; - quad[3] = mIndexMap[quad[3]]; - } - - for (size_t i = 0; i < polygons.numTriangles(); ++i) { - Vec3I& triangle = polygons.triangle(i); - triangle[0] = mIndexMap[triangle[0]]; - triangle[1] = mIndexMap[triangle[1]]; - triangle[2] = mIndexMap[triangle[2]]; - } - } - } - - -private: - PolygonPoolList& mPolygons; - size_t mPolyListCount; - const std::vector& mIndexMap; -}; - - -class MovePoints -{ -public: - ////////// - - MovePoints( - internal::UniquePtr::type& newPointList, - const PointList& oldPointList, - const std::vector& indexMap, - const std::vector& usedPointMask) - : mNewPointList(newPointList) - , mOldPointList(oldPointList) - , mIndexMap(indexMap) - , mUsedPointMask(usedPointMask) - { - } - - void run(bool threaded = true) - { - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mIndexMap.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mIndexMap.size())); - } - } - - ////////// - - void operator()(const tbb::blocked_range& range) const - { - for (size_t n = range.begin(); n != range.end(); ++n) { - if (mUsedPointMask[n]) { - const size_t index = mIndexMap[n]; - mNewPointList.get()[index] = mOldPointList[n]; - } - } - } - -private: - internal::UniquePtr::type& mNewPointList; - const PointList& mOldPointList; - const std::vector& mIndexMap; - const std::vector& mUsedPointMask; -}; - - -//////////////////////////////////////// - - -template -class GenTopologyMask -{ -public: - typedef tree::LeafManager LeafManagerT; - typedef typename SrcTreeT::template ValueConverter::Type BoolTreeT; - typedef tree::ValueAccessor SrcAccessorT; - typedef tree::ValueAccessor BoolAccessorT; - typedef Grid BoolGridT; - - - ////////// - - - GenTopologyMask(const BoolGridT& mask, const LeafManagerT& srcLeafs, - const math::Transform& srcXForm, bool invertMask); - - void run(bool threaded = true); - - BoolTreeT& tree() { return mTree; } - - - ////////// - - GenTopologyMask(GenTopologyMask&, tbb::split); - - void operator()(const tbb::blocked_range&); - - void join(GenTopologyMask& rhs) { mTree.merge(rhs.mTree); } - -private: - - const BoolGridT& mMask; - const LeafManagerT& mLeafManager; - const math::Transform& mSrcXForm; - bool mInvertMask; - BoolTreeT mTree; -}; - - -template -GenTopologyMask::GenTopologyMask(const BoolGridT& mask, const LeafManagerT& srcLeafs, - const math::Transform& srcXForm, bool invertMask) - : mMask(mask) - , mLeafManager(srcLeafs) - , mSrcXForm(srcXForm) - , mInvertMask(invertMask) - , mTree(false) -{ -} - - -template -GenTopologyMask::GenTopologyMask(GenTopologyMask& rhs, tbb::split) - : mMask(rhs.mMask) - , mLeafManager(rhs.mLeafManager) - , mSrcXForm(rhs.mSrcXForm) - , mInvertMask(rhs.mInvertMask) - , mTree(false) -{ -} - - -template -void -GenTopologyMask::run(bool threaded) -{ - if (threaded) { - tbb::parallel_reduce(mLeafManager.getRange(), *this); - } else { - (*this)(mLeafManager.getRange()); - } -} - - -template -void -GenTopologyMask::operator()(const tbb::blocked_range& range) -{ - Coord ijk; - Vec3d xyz; - typedef typename BoolTreeT::LeafNodeType BoolLeafT; - const math::Transform& maskXForm = mMask.transform(); - tree::ValueAccessor maskAcc(mMask.tree()); - tree::ValueAccessor acc(mTree); - - typename SrcTreeT::LeafNodeType::ValueOnCIter iter; - for (size_t n = range.begin(); n != range.end(); ++n) { - - ijk = mLeafManager.leaf(n).origin(); - BoolLeafT* leaf = new BoolLeafT(ijk, false); - bool addLeaf = false; - - if (maskXForm == mSrcXForm) { - - const BoolLeafT* maskLeaf = maskAcc.probeConstLeaf(ijk); - - if (maskLeaf) { - - for (iter = mLeafManager.leaf(n).cbeginValueOn(); iter; ++iter) { - Index pos = iter.pos(); - if(maskLeaf->isValueOn(pos) != mInvertMask) { - leaf->setValueOn(pos); - addLeaf = true; - } - } - - } else if (maskAcc.isValueOn(ijk) != mInvertMask) { - leaf->topologyUnion(mLeafManager.leaf(n)); - addLeaf = true; - } - - } else { - for (iter = mLeafManager.leaf(n).cbeginValueOn(); iter; ++iter) { - ijk = iter.getCoord(); - xyz = maskXForm.worldToIndex(mSrcXForm.indexToWorld(ijk)); - if(maskAcc.isValueOn(util::nearestCoord(xyz)) != mInvertMask) { - leaf->setValueOn(iter.pos()); - addLeaf = true; - } - } - } - - if (addLeaf) acc.addLeaf(leaf); - else delete leaf; - } -} - - -//////////////////////////////////////// - - -template -class GenBoundaryMask -{ -public: - typedef typename SrcTreeT::template ValueConverter::Type IntTreeT; - typedef typename SrcTreeT::template ValueConverter::Type BoolTreeT; - typedef tree::LeafManager LeafManagerT; - - ////////// - - GenBoundaryMask(const LeafManagerT& leafs, const BoolTreeT&, const IntTreeT&); - - void run(bool threaded = true); - - BoolTreeT& tree() { return mTree; } - - ////////// - - GenBoundaryMask(GenBoundaryMask&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(GenBoundaryMask& rhs) { mTree.merge(rhs.mTree); } - -private: - // This typedef is needed for Windows - typedef tree::ValueAccessor IntTreeAccessorT; - - bool neighboringLeaf(const Coord&, const IntTreeAccessorT&) const; - - const LeafManagerT& mLeafManager; - const BoolTreeT& mMaskTree; - const IntTreeT& mIdxTree; - BoolTreeT mTree; - CoordBBox mLeafBBox; -}; - - -template -GenBoundaryMask::GenBoundaryMask(const LeafManagerT& leafs, - const BoolTreeT& maskTree, const IntTreeT& auxTree) - : mLeafManager(leafs) - , mMaskTree(maskTree) - , mIdxTree(auxTree) - , mTree(false) -{ - mIdxTree.evalLeafBoundingBox(mLeafBBox); - mLeafBBox.expand(IntTreeT::LeafNodeType::DIM); -} - - -template -GenBoundaryMask::GenBoundaryMask(GenBoundaryMask& rhs, tbb::split) - : mLeafManager(rhs.mLeafManager) - , mMaskTree(rhs.mMaskTree) - , mIdxTree(rhs.mIdxTree) - , mTree(false) - , mLeafBBox(rhs.mLeafBBox) -{ -} - - -template -void -GenBoundaryMask::run(bool threaded) -{ - if (threaded) { - tbb::parallel_reduce(mLeafManager.getRange(), *this); - } else { - (*this)(mLeafManager.getRange()); - } -} - - -template -bool -GenBoundaryMask::neighboringLeaf(const Coord& ijk, const IntTreeAccessorT& acc) const -{ - if (acc.probeConstLeaf(ijk)) return true; - - const int dim = IntTreeT::LeafNodeType::DIM; - - // face adjacent neghbours - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1], ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1], ijk[2] - dim))) return true; - - // edge adjacent neighbors - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2]))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2] - dim))) return true; - - // corner adjacent neighbors - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2] - dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2] + dim))) return true; - if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2] - dim))) return true; - - return false; -} - - -template -void -GenBoundaryMask::operator()(const tbb::blocked_range& range) -{ - Coord ijk; - tree::ValueAccessor maskAcc(mMaskTree); - tree::ValueAccessor idxAcc(mIdxTree); - tree::ValueAccessor acc(mTree); - - typename SrcTreeT::LeafNodeType::ValueOnCIter iter; - - for (size_t n = range.begin(); n != range.end(); ++n) { - - const typename SrcTreeT::LeafNodeType& - leaf = mLeafManager.leaf(n); - - ijk = leaf.origin(); - - if (!mLeafBBox.isInside(ijk) || !neighboringLeaf(ijk, idxAcc)) continue; - - const typename BoolTreeT::LeafNodeType* - maskLeaf = maskAcc.probeConstLeaf(ijk); - - if (!maskLeaf || !leaf.hasSameTopology(maskLeaf)) { - acc.touchLeaf(ijk)->topologyUnion(leaf); - } - } -} - - -//////////////////////////////////////// - - -template -class GenTileMask -{ -public: - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - - typedef typename TreeT::ValueType ValueT; - - ////////// - - GenTileMask(const std::vector& tiles, const TreeT& distTree, ValueT iso); - - void run(bool threaded = true); - - BoolTreeT& tree() { return mTree; } - - ////////// - - GenTileMask(GenTileMask&, tbb::split); - void operator()(const tbb::blocked_range&); - void join(GenTileMask& rhs) { mTree.merge(rhs.mTree); } - -private: - - const std::vector& mTiles; - const TreeT& mDistTree; - ValueT mIsovalue; - - BoolTreeT mTree; -}; - - -template -GenTileMask::GenTileMask( - const std::vector& tiles, const TreeT& distTree, ValueT iso) - : mTiles(tiles) - , mDistTree(distTree) - , mIsovalue(iso) - , mTree(false) -{ -} - - -template -GenTileMask::GenTileMask(GenTileMask& rhs, tbb::split) - : mTiles(rhs.mTiles) - , mDistTree(rhs.mDistTree) - , mIsovalue(rhs.mIsovalue) - , mTree(false) -{ -} - - -template -void -GenTileMask::run(bool threaded) -{ - if (threaded) tbb::parallel_reduce(tbb::blocked_range(0, mTiles.size()), *this); - else (*this)(tbb::blocked_range(0, mTiles.size())); -} - - -template -void -GenTileMask::operator()(const tbb::blocked_range& range) -{ - tree::ValueAccessor distAcc(mDistTree); - CoordBBox region, bbox; - Coord ijk, nijk; - bool processRegion = true; - ValueT value; - - - for (size_t n = range.begin(); n != range.end(); ++n) { - - const Vec4i& tile = mTiles[n]; - - bbox.min()[0] = tile[0]; - bbox.min()[1] = tile[1]; - bbox.min()[2] = tile[2]; - - bbox.max() = bbox.min(); - bbox.max().offset(tile[3]); - - const bool thisInside = (distAcc.getValue(bbox.min()) < mIsovalue); - const int thisDepth = distAcc.getValueDepth(bbox.min()); - - // eval x-edges - - ijk = bbox.max(); - nijk = ijk; - ++nijk[0]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(nijk)) { - processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue); - } - - - if (processRegion) { - region = bbox; - region.min()[0] = region.max()[0] = ijk[0]; - mTree.fill(region, true); - } - - - ijk = bbox.min(); - --ijk[0]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[0] = region.max()[0] = ijk[0]; - mTree.fill(region, true); - } - - - // eval y-edges - - ijk = bbox.max(); - nijk = ijk; - ++nijk[1]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(nijk)) { - processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[1] = region.max()[1] = ijk[1]; - mTree.fill(region, true); - } - - - ijk = bbox.min(); - --ijk[1]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[1] = region.max()[1] = ijk[1]; - mTree.fill(region, true); - } - - - // eval z-edges - - ijk = bbox.max(); - nijk = ijk; - ++nijk[2]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(nijk)) { - processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[2] = region.max()[2] = ijk[2]; - mTree.fill(region, true); - } - - ijk = bbox.min(); - --ijk[2]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[2] = region.max()[2] = ijk[2]; - mTree.fill(region, true); - } - - - ijk = bbox.min(); - --ijk[1]; - --ijk[2]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[1] = region.max()[1] = ijk[1]; - region.min()[2] = region.max()[2] = ijk[2]; - mTree.fill(region, true); - } - - - ijk = bbox.min(); - --ijk[0]; - --ijk[1]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[1] = region.max()[1] = ijk[1]; - region.min()[0] = region.max()[0] = ijk[0]; - mTree.fill(region, true); - } - - ijk = bbox.min(); - --ijk[0]; - --ijk[2]; - - processRegion = true; - if (thisDepth >= distAcc.getValueDepth(ijk)) { - processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue); - } - - if (processRegion) { - region = bbox; - region.min()[2] = region.max()[2] = ijk[2]; - region.min()[0] = region.max()[0] = ijk[0]; - mTree.fill(region, true); - } - } -} - - -//////////////////////////////////////// - - -template -inline void -tileData(const DistTreeT& distTree, SignTreeT& signTree, IdxTreeT& idxTree, double iso) -{ - typename DistTreeT::ValueOnCIter tileIter(distTree); - tileIter.setMaxDepth(DistTreeT::ValueOnCIter::LEAF_DEPTH - 1); - - if (!tileIter) return; // volume has no active tiles. - - size_t tileCount = 0; - for ( ; tileIter; ++tileIter) { - ++tileCount; - } - - std::vector tiles(tileCount); - - tileCount = 0; - tileIter = distTree.cbeginValueOn(); - tileIter.setMaxDepth(DistTreeT::ValueOnCIter::LEAF_DEPTH - 1); - - CoordBBox bbox; - for (; tileIter; ++tileIter) { - Vec4i& tile = tiles[tileCount++]; - tileIter.getBoundingBox(bbox); - tile[0] = bbox.min()[0]; - tile[1] = bbox.min()[1]; - tile[2] = bbox.min()[2]; - tile[3] = bbox.max()[0] - bbox.min()[0]; - } - - typename DistTreeT::ValueType isovalue = typename DistTreeT::ValueType(iso); - - GenTileMask tileMask(tiles, distTree, isovalue); - tileMask.run(); - - typedef typename DistTreeT::template ValueConverter::Type BoolTreeT; - typedef tree::LeafManager BoolLeafManagerT; - - BoolLeafManagerT leafs(tileMask.tree()); - - - internal::SignData op(distTree, leafs, isovalue); - op.run(); - - signTree.merge(*op.signTree()); - idxTree.merge(*op.idxTree()); -} - - -//////////////////////////////////////// - - -// Utility class for the volumeToMesh wrapper -class PointListCopy -{ -public: - PointListCopy(const PointList& pointsIn, std::vector& pointsOut) - : mPointsIn(pointsIn) , mPointsOut(pointsOut) - { - } - - void operator()(const tbb::blocked_range& range) const - { - for (size_t n = range.begin(); n < range.end(); ++n) { - mPointsOut[n] = mPointsIn[n]; - } - } - -private: - const PointList& mPointsIn; - std::vector& mPointsOut; -}; - - -// Checks if the isovalue is in proximity to the active voxel boundary. -template -inline bool -needsActiveVoxePadding(const LeafManagerT& leafs, double iso, double voxelSize) -{ - double interiorWidth = 0.0, exteriorWidth = 0.0; - { - typename LeafManagerT::TreeType::LeafNodeType::ValueOffCIter it; - bool foundInterior = false, foundExterior = false; - for (size_t n = 0, N = leafs.leafCount(); n < N; ++n) { - - for (it = leafs.leaf(n).cbeginValueOff(); it; ++it) { - double value = double(it.getValue()); - if (value < 0.0) { - interiorWidth = value; - foundInterior = true; - } else if (value > 0.0) { - exteriorWidth = value; - foundExterior = true; - } - - if (foundInterior && foundExterior) break; - } - - if (foundInterior && foundExterior) break; - } - - } - - double minDist = std::min(std::abs(interiorWidth - iso), std::abs(exteriorWidth - iso)); - return !(minDist > (2.0 * voxelSize)); -} - - -} // end namespace internal - - -//////////////////////////////////////// - - -inline -PolygonPool::PolygonPool() - : mNumQuads(0) - , mNumTriangles(0) - , mQuads(NULL) - , mTriangles(NULL) - , mQuadFlags(NULL) - , mTriangleFlags(NULL) -{ -} - - -inline -PolygonPool::PolygonPool(const size_t numQuads, const size_t numTriangles) - : mNumQuads(numQuads) - , mNumTriangles(numTriangles) - , mQuads(new openvdb::Vec4I[mNumQuads]) - , mTriangles(new openvdb::Vec3I[mNumTriangles]) - , mQuadFlags(new char[mNumQuads]) - , mTriangleFlags(new char[mNumTriangles]) -{ -} - - -inline void -PolygonPool::copy(const PolygonPool& rhs) -{ - resetQuads(rhs.numQuads()); - resetTriangles(rhs.numTriangles()); - - for (size_t i = 0; i < mNumQuads; ++i) { - mQuads[i] = rhs.mQuads[i]; - mQuadFlags[i] = rhs.mQuadFlags[i]; - } - - for (size_t i = 0; i < mNumTriangles; ++i) { - mTriangles[i] = rhs.mTriangles[i]; - mTriangleFlags[i] = rhs.mTriangleFlags[i]; - } -} - - -inline void -PolygonPool::resetQuads(size_t size) -{ - mNumQuads = size; - mQuads.reset(new openvdb::Vec4I[mNumQuads]); - mQuadFlags.reset(new char[mNumQuads]); -} - - -inline void -PolygonPool::clearQuads() -{ - mNumQuads = 0; - mQuads.reset(NULL); - mQuadFlags.reset(NULL); -} - - -inline void -PolygonPool::resetTriangles(size_t size) -{ - mNumTriangles = size; - mTriangles.reset(new openvdb::Vec3I[mNumTriangles]); - mTriangleFlags.reset(new char[mNumTriangles]); -} - - -inline void -PolygonPool::clearTriangles() -{ - mNumTriangles = 0; - mTriangles.reset(NULL); - mTriangleFlags.reset(NULL); -} - - -inline bool -PolygonPool::trimQuads(const size_t n, bool reallocate) -{ - if (!(n < mNumQuads)) return false; - - if (reallocate) { - - if (n == 0) { - mQuads.reset(NULL); - } else { - - boost::scoped_array quads(new openvdb::Vec4I[n]); - boost::scoped_array flags(new char[n]); - - for (size_t i = 0; i < n; ++i) { - quads[i] = mQuads[i]; - flags[i] = mQuadFlags[i]; - } - - mQuads.swap(quads); - mQuadFlags.swap(flags); - } - } - - mNumQuads = n; - return true; -} - - -inline bool -PolygonPool::trimTrinagles(const size_t n, bool reallocate) -{ - if (!(n < mNumTriangles)) return false; - - if (reallocate) { - - if (n == 0) { - mTriangles.reset(NULL); - } else { - - boost::scoped_array triangles(new openvdb::Vec3I[n]); - boost::scoped_array flags(new char[n]); - - for (size_t i = 0; i < n; ++i) { - triangles[i] = mTriangles[i]; - flags[i] = mTriangleFlags[i]; - } - - mTriangles.swap(triangles); - mTriangleFlags.swap(flags); - } - } - - mNumTriangles = n; - return true; -} - - -//////////////////////////////////////// - - -inline VolumeToMesh::VolumeToMesh(double isovalue, double adaptivity) - : mPoints(NULL) - , mPolygons() - , mPointListSize(0) - , mSeamPointListSize(0) - , mPolygonPoolListSize(0) - , mIsovalue(isovalue) - , mPrimAdaptivity(adaptivity) - , mSecAdaptivity(0.0) - , mRefGrid(GridBase::ConstPtr()) - , mSurfaceMaskGrid(GridBase::ConstPtr()) - , mAdaptivityGrid(GridBase::ConstPtr()) - , mAdaptivityMaskTree(TreeBase::ConstPtr()) - , mRefSignTree(TreeBase::Ptr()) - , mRefIdxTree(TreeBase::Ptr()) - , mInvertSurfaceMask(false) - , mPartitions(1) - , mActivePart(0) - , mQuantizedSeamPoints(NULL) - , mPointFlags(0) -{ -} - - -inline PointList& -VolumeToMesh::pointList() -{ - return mPoints; -} - - -inline const size_t& -VolumeToMesh::pointListSize() const -{ - return mPointListSize; -} - - -inline PolygonPoolList& -VolumeToMesh::polygonPoolList() -{ - return mPolygons; -} - - -inline const PolygonPoolList& -VolumeToMesh::polygonPoolList() const -{ - return mPolygons; -} - - -inline const size_t& -VolumeToMesh::polygonPoolListSize() const -{ - return mPolygonPoolListSize; -} - - -inline void -VolumeToMesh::setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity) -{ - mRefGrid = grid; - mSecAdaptivity = secAdaptivity; - - // Clear out old auxiliary data - mRefSignTree = TreeBase::Ptr(); - mRefIdxTree = TreeBase::Ptr(); - mSeamPointListSize = 0; - mQuantizedSeamPoints.reset(NULL); -} - - -inline void -VolumeToMesh::setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask) -{ - mSurfaceMaskGrid = mask; - mInvertSurfaceMask = invertMask; -} - - -inline void -VolumeToMesh::setSpatialAdaptivity(const GridBase::ConstPtr& grid) -{ - mAdaptivityGrid = grid; -} - - -inline void -VolumeToMesh::setAdaptivityMask(const TreeBase::ConstPtr& tree) -{ - mAdaptivityMaskTree = tree; -} - - -inline void -VolumeToMesh::partition(unsigned partitions, unsigned activePart) -{ - mPartitions = std::max(partitions, unsigned(1)); - mActivePart = std::min(activePart, mPartitions-1); -} - - -inline std::vector& -VolumeToMesh::pointFlags() -{ - return mPointFlags; -} - - -inline const std::vector& -VolumeToMesh::pointFlags() const -{ - return mPointFlags; -} - - -template -inline void -VolumeToMesh::operator()(const GridT& distGrid) -{ - typedef typename GridT::TreeType DistTreeT; - typedef tree::LeafManager DistLeafManagerT; - typedef typename DistTreeT::ValueType DistValueT; - - typedef typename DistTreeT::template ValueConverter::Type BoolTreeT; - typedef tree::LeafManager BoolLeafManagerT; - typedef Grid BoolGridT; - - typedef typename DistTreeT::template ValueConverter::Type Int16TreeT; - typedef tree::LeafManager Int16LeafManagerT; - - typedef typename DistTreeT::template ValueConverter::Type IntTreeT; - typedef typename DistTreeT::template ValueConverter::Type FloatTreeT; - typedef Grid FloatGridT; - - - const openvdb::math::Transform& transform = distGrid.transform(); - const DistTreeT& distTree = distGrid.tree(); - const DistValueT isovalue = DistValueT(mIsovalue); - - typename Int16TreeT::Ptr signTreePt; - typename IntTreeT::Ptr idxTreePt; - typename BoolTreeT::Ptr pointMask; - - BoolTreeT valueMask(false), seamMask(false); - const bool adaptive = mPrimAdaptivity > 1e-7 || mSecAdaptivity > 1e-7; - bool maskEdges = false; - - - const BoolGridT * surfaceMask = NULL; - if (mSurfaceMaskGrid && mSurfaceMaskGrid->type() == BoolGridT::gridType()) { - surfaceMask = static_cast(mSurfaceMaskGrid.get()); - } - - const FloatGridT * adaptivityField = NULL; - if (mAdaptivityGrid && mAdaptivityGrid->type() == FloatGridT::gridType()) { - adaptivityField = static_cast(mAdaptivityGrid.get()); - } - - if (mAdaptivityMaskTree && mAdaptivityMaskTree->type() == BoolTreeT::treeType()) { - const BoolTreeT *adaptivityMaskPt = - static_cast(mAdaptivityMaskTree.get()); - seamMask.topologyUnion(*adaptivityMaskPt); - } - - - // Collect auxiliary data - { - DistLeafManagerT distLeafs(distTree); - - // Check if the isovalue is in proximity to the active voxel boundary. - bool padActiveVoxels = false; - int padVoxels = 3; - - if (distGrid.getGridClass() != GRID_LEVEL_SET) { - padActiveVoxels = true; - } else { - padActiveVoxels = internal::needsActiveVoxePadding(distLeafs, - mIsovalue, transform.voxelSize()[0]); - } - - // always pad the active region for small volumes (the performance hit is neglectable). - if (!padActiveVoxels) { - Coord dim; - distTree.evalActiveVoxelDim(dim); - int maxDim = std::max(std::max(dim[0], dim[1]), dim[2]); - if (maxDim < 1000) { - padActiveVoxels = true; - padVoxels = 1; - } - } - - if (surfaceMask || mPartitions > 1) { - - maskEdges = true; - - if (surfaceMask) { - - { // Mask - internal::GenTopologyMask masking( - *surfaceMask, distLeafs, transform, mInvertSurfaceMask); - masking.run(); - valueMask.merge(masking.tree()); - } - - if (mPartitions > 1) { // Partition - tree::LeafManager leafs(valueMask); - leafs.foreach(internal::PartOp(leafs.leafCount() , mPartitions, mActivePart)); - tools::pruneInactive(valueMask); - } - - } else { // Partition - - internal::PartGen partitioner(distLeafs, mPartitions, mActivePart); - partitioner.run(); - valueMask.merge(partitioner.tree()); - } - - { - if (padActiveVoxels) tools::dilateVoxels(valueMask, padVoxels); - BoolLeafManagerT leafs(valueMask); - - internal::SignData - signDataOp(distTree, leafs, isovalue); - signDataOp.run(); - - signTreePt = signDataOp.signTree(); - idxTreePt = signDataOp.idxTree(); - } - - { - internal::GenBoundaryMask boundary(distLeafs, valueMask, *idxTreePt); - boundary.run(); - - BoolLeafManagerT bleafs(boundary.tree()); - - internal::SignData - signDataOp(distTree, bleafs, isovalue); - signDataOp.run(); - - signTreePt->merge(*signDataOp.signTree()); - idxTreePt->merge(*signDataOp.idxTree()); - } - - } else { - - // Collect voxel-sign configurations - if (padActiveVoxels) { - - BoolTreeT regionMask(false); - regionMask.topologyUnion(distTree); - tools::dilateVoxels(regionMask, padVoxels); - - BoolLeafManagerT leafs(regionMask); - - internal::SignData - signDataOp(distTree, leafs, isovalue); - signDataOp.run(); - - signTreePt = signDataOp.signTree(); - idxTreePt = signDataOp.idxTree(); - } else { - - internal::SignData - signDataOp(distTree, distLeafs, isovalue); - signDataOp.run(); - - signTreePt = signDataOp.signTree(); - idxTreePt = signDataOp.idxTree(); - } - } - - } - - - // Collect auxiliary data from active tiles - internal::tileData(distTree, *signTreePt, *idxTreePt, static_cast(isovalue)); - - // Optionally collect auxiliary data from a reference level set. - Int16TreeT *refSignTreePt = NULL; - IntTreeT *refIdxTreePt = NULL; - const DistTreeT *refDistTreePt = NULL; - - if (mRefGrid && mRefGrid->type() == GridT::gridType()) { - - const GridT* refGrid = static_cast(mRefGrid.get()); - refDistTreePt = &refGrid->tree(); - - // Collect and cache auxiliary data from the reference grid. - if (!mRefSignTree && !mRefIdxTree) { - - DistLeafManagerT refDistLeafs(*refDistTreePt); - internal::SignData - signDataOp(*refDistTreePt, refDistLeafs, isovalue); - - signDataOp.run(); - - mRefSignTree = signDataOp.signTree(); - mRefIdxTree = signDataOp.idxTree(); - } - - // Get cached auxiliary data - if (mRefSignTree && mRefIdxTree) { - refSignTreePt = static_cast(mRefSignTree.get()); - refIdxTreePt = static_cast(mRefIdxTree.get()); - } - } - - - // Process auxiliary data - Int16LeafManagerT signLeafs(*signTreePt); - - if (maskEdges) { - signLeafs.foreach(internal::MaskEdges(valueMask)); - valueMask.clear(); - } - - - // Generate the seamline mask - if (refSignTreePt) { - internal::GenSeamMask seamOp(signLeafs, *refSignTreePt); - seamOp.run(); - - tools::dilateVoxels(seamOp.mask(), 3); - signLeafs.foreach(internal::TagSeamEdges(seamOp.mask())); - - seamMask.merge(seamOp.mask()); - } - - - std::vector regions(signLeafs.leafCount(), 0); - if (regions.empty()) return; - - if (adaptive) { - - internal::MergeVoxelRegions merge( - signLeafs, *signTreePt, distTree, *idxTreePt, isovalue, DistValueT(mPrimAdaptivity)); - - if (adaptivityField) { - merge.setSpatialAdaptivity(transform, *adaptivityField); - } - - if (refSignTreePt || mAdaptivityMaskTree) { - merge.setAdaptivityMask(&seamMask); - } - - if (refSignTreePt) { - merge.setRefData(refSignTreePt, DistValueT(mSecAdaptivity)); - } - - merge.run(); - - signLeafs.foreach(internal::CountRegions(*idxTreePt, regions)); - - } else { - signLeafs.foreach(internal::CountPoints(regions)); - } - - - { - mPointListSize = 0; - size_t tmp = 0; - for (size_t n = 0, N = regions.size(); n < N; ++n) { - tmp = regions[n]; - regions[n] = mPointListSize; - mPointListSize += tmp; - } - } - - - // Generate the unique point list - mPoints.reset(new openvdb::Vec3s[mPointListSize]); - mPointFlags.clear(); - - // Generate seam line sample points - if (refSignTreePt && refIdxTreePt) { - - if (mSeamPointListSize == 0) { - - std::vector pointMap; - - { - Int16LeafManagerT refSignLeafs(*refSignTreePt); - pointMap.resize(refSignLeafs.leafCount(), 0); - - refSignLeafs.foreach(internal::CountPoints(pointMap)); - - size_t tmp = 0; - for (size_t n = 0, N = pointMap.size(); n < N; ++n) { - tmp = pointMap[n]; - pointMap[n] = mSeamPointListSize; - mSeamPointListSize += tmp; - } - } - - if (!pointMap.empty() && mSeamPointListSize != 0) { - - mQuantizedSeamPoints.reset(new uint32_t[mSeamPointListSize]); - memset(mQuantizedSeamPoints.get(), 0, sizeof(uint32_t) * mSeamPointListSize); - - typedef tree::LeafManager IntLeafManagerT; - - IntLeafManagerT refIdxLeafs(*refIdxTreePt); - refIdxLeafs.foreach(internal::MapPoints(pointMap, *refSignTreePt)); - } - } - - if (mSeamPointListSize != 0) { - signLeafs.foreach(internal::SeamWeights( - distTree, *refSignTreePt, *refIdxTreePt, mQuantizedSeamPoints, mIsovalue)); - } - } - - - internal::GenPoints - pointOp(signLeafs, distTree, *idxTreePt, mPoints, regions, transform, mIsovalue); - - - if (mSeamPointListSize != 0) { - mPointFlags.resize(mPointListSize); - pointOp.setRefData(refSignTreePt, refDistTreePt, refIdxTreePt, - &mQuantizedSeamPoints, &mPointFlags); - } - - pointOp.run(); - - - mPolygonPoolListSize = signLeafs.leafCount(); - mPolygons.reset(new PolygonPool[mPolygonPoolListSize]); - - - if (adaptive) { - - internal::GenPolygons - mesher(signLeafs, *signTreePt, *idxTreePt, mPolygons, Index32(mPointListSize)); - - mesher.setRefSignTree(refSignTreePt); - mesher.run(); - - } else { - - internal::GenPolygons - mesher(signLeafs, *signTreePt, *idxTreePt, mPolygons, Index32(mPointListSize)); - - mesher.setRefSignTree(refSignTreePt); - mesher.run(); - } - - // Clean up unused points, only necessary if masking and/or - // automatic mesh partitioning is enabled. - if ((surfaceMask || mPartitions > 1) && mPointListSize > 0) { - - // Flag used points - std::vector usedPointMask(mPointListSize, 0); - - internal::FlagUsedPoints flagPoints(mPolygons, mPolygonPoolListSize, usedPointMask); - flagPoints.run(); - - // Create index map - std::vector indexMap(mPointListSize); - size_t usedPointCount = 0; - for (size_t p = 0; p < mPointListSize; ++p) { - if (usedPointMask[p]) indexMap[p] = static_cast(usedPointCount++); - } - - if (usedPointCount < mPointListSize) { - - // move points - internal::UniquePtr::type - newPointList(new openvdb::Vec3s[usedPointCount]); - - internal::MovePoints movePoints(newPointList, mPoints, indexMap, usedPointMask); - movePoints.run(); - - mPointListSize = usedPointCount; - mPoints.reset(newPointList.release()); - - // update primitives - internal::RemapIndices remap(mPolygons, mPolygonPoolListSize, indexMap); - remap.run(); - } - } - - - // Subdivide nonplanar quads near the seamline edges - // todo: thread and clean up - if (refSignTreePt || refIdxTreePt || refDistTreePt) { - std::vector newPoints; - - for (size_t n = 0; n < mPolygonPoolListSize; ++n) { - - PolygonPool& polygons = mPolygons[n]; - - std::vector nonPlanarQuads; - nonPlanarQuads.reserve(polygons.numQuads()); - - for (size_t i = 0; i < polygons.numQuads(); ++i) { - - char& flags = polygons.quadFlags(i); - - if ((flags & POLYFLAG_FRACTURE_SEAM) && !(flags & POLYFLAG_EXTERIOR)) { - - openvdb::Vec4I& quad = polygons.quad(i); - - const bool edgePoly = mPointFlags[quad[0]] || mPointFlags[quad[1]] - || mPointFlags[quad[2]] || mPointFlags[quad[3]]; - - if (!edgePoly) continue; - - const Vec3s& p0 = mPoints[quad[0]]; - const Vec3s& p1 = mPoints[quad[1]]; - const Vec3s& p2 = mPoints[quad[2]]; - const Vec3s& p3 = mPoints[quad[3]]; - - if (!internal::isPlanarQuad(p0, p1, p2, p3, 1e-6f)) { - nonPlanarQuads.push_back(i); - } - } - } - - - if (!nonPlanarQuads.empty()) { - - PolygonPool tmpPolygons; - - tmpPolygons.resetQuads(polygons.numQuads() - nonPlanarQuads.size()); - tmpPolygons.resetTriangles(polygons.numTriangles() + 4 * nonPlanarQuads.size()); - - size_t triangleIdx = 0; - for (size_t i = 0; i < nonPlanarQuads.size(); ++i) { - - size_t& quadIdx = nonPlanarQuads[i]; - - openvdb::Vec4I& quad = polygons.quad(quadIdx); - char& quadFlags = polygons.quadFlags(quadIdx); - //quadFlags |= POLYFLAG_SUBDIVIDED; - - Vec3s centroid = (mPoints[quad[0]] + mPoints[quad[1]] + - mPoints[quad[2]] + mPoints[quad[3]]) * 0.25; - - size_t pointIdx = newPoints.size() + mPointListSize; - - newPoints.push_back(centroid); - - - { - Vec3I& triangle = tmpPolygons.triangle(triangleIdx); - - triangle[0] = quad[0]; - triangle[1] = static_cast(pointIdx); - triangle[2] = quad[3]; - - tmpPolygons.triangleFlags(triangleIdx) = quadFlags; - - if (mPointFlags[triangle[0]] || mPointFlags[triangle[2]]) { - tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED; - } - } - - ++triangleIdx; - - { - Vec3I& triangle = tmpPolygons.triangle(triangleIdx); - - triangle[0] = quad[0]; - triangle[1] = quad[1]; - triangle[2] = static_cast(pointIdx); - - tmpPolygons.triangleFlags(triangleIdx) = quadFlags; - - if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) { - tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED; - } - } - - ++triangleIdx; - - { - Vec3I& triangle = tmpPolygons.triangle(triangleIdx); - - triangle[0] = quad[1]; - triangle[1] = quad[2]; - triangle[2] = static_cast(pointIdx); - - tmpPolygons.triangleFlags(triangleIdx) = quadFlags; - - if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) { - tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED; - } - } - - - ++triangleIdx; - - { - Vec3I& triangle = tmpPolygons.triangle(triangleIdx); - - triangle[0] = quad[2]; - triangle[1] = quad[3]; - triangle[2] = static_cast(pointIdx); - - tmpPolygons.triangleFlags(triangleIdx) = quadFlags; - - if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) { - tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED; - } - } - - ++triangleIdx; - - quad[0] = util::INVALID_IDX; - } - - - for (size_t i = 0; i < polygons.numTriangles(); ++i) { - tmpPolygons.triangle(triangleIdx) = polygons.triangle(i); - tmpPolygons.triangleFlags(triangleIdx) = polygons.triangleFlags(i); - ++triangleIdx; - } - - - size_t quadIdx = 0; - for (size_t i = 0; i < polygons.numQuads(); ++i) { - openvdb::Vec4I& quad = polygons.quad(i); - - if (quad[0] != util::INVALID_IDX) { - tmpPolygons.quad(quadIdx) = quad; - tmpPolygons.quadFlags(quadIdx) = polygons.quadFlags(i); - ++quadIdx; - } - } - - - polygons.copy(tmpPolygons); - } - - } - - - if (!newPoints.empty()) { - - size_t newPointCount = newPoints.size() + mPointListSize; - - internal::UniquePtr::type - newPointList(new openvdb::Vec3s[newPointCount]); - - for (size_t i = 0; i < mPointListSize; ++i) { - newPointList.get()[i] = mPoints[i]; - } - - for (size_t i = mPointListSize; i < newPointCount; ++i) { - newPointList.get()[i] = newPoints[i - mPointListSize]; - } - - mPointListSize = newPointCount; - mPoints.reset(newPointList.release()); - mPointFlags.resize(mPointListSize, 0); - } - } -} - - -//////////////////////////////////////// - - -/// @internal This overload is enabled only for grids with a scalar ValueType. -template -inline typename boost::enable_if, void>::type -doVolumeToMesh( - const GridType& grid, - std::vector& points, - std::vector& triangles, - std::vector& quads, - double isovalue, - double adaptivity) -{ - VolumeToMesh mesher(isovalue, adaptivity); - mesher(grid); - - // Preallocate the point list - points.clear(); - points.resize(mesher.pointListSize()); - - { // Copy points - internal::PointListCopy ptnCpy(mesher.pointList(), points); - tbb::parallel_for(tbb::blocked_range(0, points.size()), ptnCpy); - mesher.pointList().reset(NULL); - } - - PolygonPoolList& polygonPoolList = mesher.polygonPoolList(); - - { // Preallocate primitive lists - size_t numQuads = 0, numTriangles = 0; - for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) { - openvdb::tools::PolygonPool& polygons = polygonPoolList[n]; - numTriangles += polygons.numTriangles(); - numQuads += polygons.numQuads(); - } - - triangles.clear(); - triangles.resize(numTriangles); - quads.clear(); - quads.resize(numQuads); - } - - // Copy primitives - size_t qIdx = 0, tIdx = 0; - for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) { - openvdb::tools::PolygonPool& polygons = polygonPoolList[n]; - - for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) { - quads[qIdx++] = polygons.quad(i); - } - - for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) { - triangles[tIdx++] = polygons.triangle(i); - } - } -} - -/// @internal This overload is enabled only for grids that do not have a scalar ValueType. -template -inline typename boost::disable_if, void>::type -doVolumeToMesh( - const GridType&, - std::vector&, - std::vector&, - std::vector&, - double, - double) -{ - OPENVDB_THROW(TypeError, "volume to mesh conversion is supported only for scalar grids"); -} - - -template -inline void -volumeToMesh( - const GridType& grid, - std::vector& points, - std::vector& triangles, - std::vector& quads, - double isovalue, - double adaptivity) -{ - doVolumeToMesh(grid, points, triangles, quads, isovalue, adaptivity); -} - - -template -inline void -volumeToMesh( - const GridType& grid, - std::vector& points, - std::vector& quads, - double isovalue) -{ - std::vector triangles; - doVolumeToMesh(grid, points, triangles, quads, isovalue, 0.0); -} - - -//////////////////////////////////////// - - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tools/VolumeToSpheres.h b/openvdb_3_0_0_library/tools/VolumeToSpheres.h deleted file mode 100755 index 1fefb65..0000000 --- a/openvdb_3_0_0_library/tools/VolumeToSpheres.h +++ /dev/null @@ -1,1039 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED -#define OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED - -#include -#include -#include // for erodeVoxels() - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include // std::numeric_limits - -////////// - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tools { - - -/// @brief Threaded method to fill a closed level set or fog volume -/// with adaptively sized spheres. -/// -/// @param grid a scalar gird to fill with spheres. -/// -/// @param spheres a @c Vec4 array representing the spheres that returned by this -/// method. The first three components specify the sphere center -/// and the fourth is the radius. The spheres in this array are -/// ordered by radius, biggest to smallest. -/// -/// @param maxSphereCount no more than this number of spheres are generated. -/// -/// @param overlapping toggle to allow spheres to overlap/intersect -/// -/// @param minRadius determines the smallest sphere size in voxel units. -/// -/// @param maxRadius determines the largest sphere size in voxel units. -/// -/// @param isovalue the crossing point of the volume values that is considered -/// the surface. The zero default value works for signed distance -/// fields while fog volumes require a larger positive value, -/// 0.5 is a good initial guess. -/// -/// @param instanceCount how many interior points to consider for the sphere placement, -/// increasing this count increases the chances of finding optimal -/// sphere sizes. -/// -/// @param interrupter a pointer adhering to the util::NullInterrupter interface -/// -template -inline void -fillWithSpheres( - const GridT& grid, - std::vector& spheres, - int maxSphereCount, - bool overlapping = false, - float minRadius = 1.0, - float maxRadius = std::numeric_limits::max(), - float isovalue = 0.0, - int instanceCount = 10000, - InterrupterT* interrupter = NULL); - - -/// @brief @c fillWithSpheres method variant that automatically infers -/// the util::NullInterrupter. -template -inline void -fillWithSpheres( - const GridT& grid, - std::vector& spheres, - int maxSphereCount, - bool overlapping = false, - float minRadius = 1.0, - float maxRadius = std::numeric_limits::max(), - float isovalue = 0.0, - int instanceCount = 10000) -{ - fillWithSpheres(grid, spheres, - maxSphereCount, overlapping, minRadius, maxRadius, isovalue, instanceCount); -} - - -//////////////////////////////////////// - - -/// @brief Accelerated closest surface point queries for narrow band level sets. -/// Supports queries that originate at arbitrary worldspace locations, is -/// not confined to the narrow band region of the input volume geometry. -template -class ClosestSurfacePoint -{ -public: - typedef typename GridT::TreeType TreeT; - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef typename TreeT::template ValueConverter::Type Int16TreeT; - - - ClosestSurfacePoint(); - - - /// @brief Extracts the surface points and constructs a spatial acceleration structure. - /// - /// @param grid a scalar gird, level set or fog volume. - /// - /// @param isovalue the crossing point of the volume values that is considered - /// the surface. The zero default value works for signed distance - /// fields while fog volumes require a larger positive value, - /// 0.5 is a good initial guess. - /// - /// @param interrupter a pointer adhering to the util::NullInterrupter interface. - /// - template - void initialize(const GridT& grid, float isovalue = 0.0, InterrupterT* interrupter = NULL); - - - /// @brief @c initialize method variant that automatically infers - /// the util::NullInterrupter. - void initialize(const GridT& grid, float isovalue = 0.0); - - - - /// @brief Computes distance to closest surface. - /// - /// @param points search locations in world space. - /// - /// @param distances list of closest surface point distances, populated by this method. - /// - bool search(const std::vector& points, std::vector& distances); - - - /// @brief Performs closest point searches. - /// - /// @param points search locations in world space to be replaced by their closest - /// surface point. - /// - /// @param distances list of closest surface point distances, populated by this method. - /// - bool searchAndReplace(std::vector& points, std::vector& distances); - - - /// @{ - /// @brief Tree accessors - const IntTreeT& indexTree() const { return *mIdxTreePt; } - const Int16TreeT& signTree() const { return *mSignTreePt; } - /// @} - -private: - typedef typename IntTreeT::LeafNodeType IntLeafT; - typedef std::pair IndexRange; - - bool mIsInitialized; - std::vector mLeafBoundingSpheres, mNodeBoundingSpheres; - std::vector mLeafRanges; - std::vector mLeafNodes; - PointList mSurfacePointList; - size_t mPointListSize, mMaxNodeLeafs; - float mMaxRadiusSqr; - typename IntTreeT::Ptr mIdxTreePt; - typename Int16TreeT::Ptr mSignTreePt; - - bool search(std::vector&, std::vector&, bool transformPoints); -}; - - -//////////////////////////////////////// - - - - -// Internal utility methods - - -namespace internal { - -struct PointAccessor -{ - PointAccessor(std::vector& points) - : mPoints(points) - { - } - - void add(const Vec3R &pos) - { - mPoints.push_back(pos); - } -private: - std::vector& mPoints; -}; - - -template -class LeafBS -{ -public: - - LeafBS(std::vector& leafBoundingSpheres, - const std::vector& leafNodes, - const math::Transform& transform, - const PointList& surfacePointList); - - void run(bool threaded = true); - - - void operator()(const tbb::blocked_range&) const; - -private: - std::vector& mLeafBoundingSpheres; - const std::vector& mLeafNodes; - const math::Transform& mTransform; - const PointList& mSurfacePointList; -}; - -template -LeafBS::LeafBS( - std::vector& leafBoundingSpheres, - const std::vector& leafNodes, - const math::Transform& transform, - const PointList& surfacePointList) - : mLeafBoundingSpheres(leafBoundingSpheres) - , mLeafNodes(leafNodes) - , mTransform(transform) - , mSurfacePointList(surfacePointList) -{ -} - -template -void -LeafBS::run(bool threaded) -{ - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mLeafNodes.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mLeafNodes.size())); - } -} - -template -void -LeafBS::operator()(const tbb::blocked_range& range) const -{ - typename IntLeafT::ValueOnCIter iter; - Vec3s avg; - - for (size_t n = range.begin(); n != range.end(); ++n) { - - avg[0] = 0.0; - avg[1] = 0.0; - avg[2] = 0.0; - - int count = 0; - for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) { - avg += mSurfacePointList[iter.getValue()]; - ++count; - } - - if (count > 1) avg *= float(1.0 / double(count)); - - float maxDist = 0.0; - - for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) { - float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr(); - if (tmpDist > maxDist) maxDist = tmpDist; - } - - Vec4R& sphere = mLeafBoundingSpheres[n]; - - sphere[0] = avg[0]; - sphere[1] = avg[1]; - sphere[2] = avg[2]; - sphere[3] = maxDist * 2.0; // padded radius - } -} - - -class NodeBS -{ -public: - typedef std::pair IndexRange; - - NodeBS(std::vector& nodeBoundingSpheres, - const std::vector& leafRanges, - const std::vector& leafBoundingSpheres); - - inline void run(bool threaded = true); - - inline void operator()(const tbb::blocked_range&) const; - -private: - std::vector& mNodeBoundingSpheres; - const std::vector& mLeafRanges; - const std::vector& mLeafBoundingSpheres; -}; - -inline -NodeBS::NodeBS(std::vector& nodeBoundingSpheres, - const std::vector& leafRanges, - const std::vector& leafBoundingSpheres) - : mNodeBoundingSpheres(nodeBoundingSpheres) - , mLeafRanges(leafRanges) - , mLeafBoundingSpheres(leafBoundingSpheres) -{ -} - -inline void -NodeBS::run(bool threaded) -{ - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mLeafRanges.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mLeafRanges.size())); - } -} - -inline void -NodeBS::operator()(const tbb::blocked_range& range) const -{ - Vec3d avg, pos; - - for (size_t n = range.begin(); n != range.end(); ++n) { - - avg[0] = 0.0; - avg[1] = 0.0; - avg[2] = 0.0; - - int count = int(mLeafRanges[n].second) - int(mLeafRanges[n].first); - - for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) { - avg[0] += mLeafBoundingSpheres[i][0]; - avg[1] += mLeafBoundingSpheres[i][1]; - avg[2] += mLeafBoundingSpheres[i][2]; - } - - if (count > 1) avg *= float(1.0 / double(count)); - - - double maxDist = 0.0; - - for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) { - pos[0] = mLeafBoundingSpheres[i][0]; - pos[1] = mLeafBoundingSpheres[i][1]; - pos[2] = mLeafBoundingSpheres[i][2]; - - double tmpDist = (pos - avg).lengthSqr() + mLeafBoundingSpheres[i][3]; - if (tmpDist > maxDist) maxDist = tmpDist; - } - - Vec4R& sphere = mNodeBoundingSpheres[n]; - - sphere[0] = avg[0]; - sphere[1] = avg[1]; - sphere[2] = avg[2]; - sphere[3] = maxDist * 2.0; // padded radius - } -} - - - -//////////////////////////////////////// - - -template -class ClosestPointDist -{ -public: - typedef std::pair IndexRange; - - ClosestPointDist( - std::vector& instancePoints, - std::vector& instanceDistances, - const PointList& surfacePointList, - const std::vector& leafNodes, - const std::vector& leafRanges, - const std::vector& leafBoundingSpheres, - const std::vector& nodeBoundingSpheres, - size_t maxNodeLeafs, - bool transformPoints = false); - - - void run(bool threaded = true); - - - void operator()(const tbb::blocked_range&) const; - -private: - - void evalLeaf(size_t index, const IntLeafT& leaf) const; - void evalNode(size_t pointIndex, size_t nodeIndex) const; - - - std::vector& mInstancePoints; - std::vector& mInstanceDistances; - - const PointList& mSurfacePointList; - - const std::vector& mLeafNodes; - const std::vector& mLeafRanges; - const std::vector& mLeafBoundingSpheres; - const std::vector& mNodeBoundingSpheres; - - std::vector mLeafDistances, mNodeDistances; - - const bool mTransformPoints; - size_t mClosestPointIndex; -}; - - -template -ClosestPointDist::ClosestPointDist( - std::vector& instancePoints, - std::vector& instanceDistances, - const PointList& surfacePointList, - const std::vector& leafNodes, - const std::vector& leafRanges, - const std::vector& leafBoundingSpheres, - const std::vector& nodeBoundingSpheres, - size_t maxNodeLeafs, - bool transformPoints) - : mInstancePoints(instancePoints) - , mInstanceDistances(instanceDistances) - , mSurfacePointList(surfacePointList) - , mLeafNodes(leafNodes) - , mLeafRanges(leafRanges) - , mLeafBoundingSpheres(leafBoundingSpheres) - , mNodeBoundingSpheres(nodeBoundingSpheres) - , mLeafDistances(maxNodeLeafs, 0.0) - , mNodeDistances(leafRanges.size(), 0.0) - , mTransformPoints(transformPoints) - , mClosestPointIndex(0) -{ -} - - -template -void -ClosestPointDist::run(bool threaded) -{ - if (threaded) { - tbb::parallel_for(tbb::blocked_range(0, mInstancePoints.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mInstancePoints.size())); - } -} - -template -void -ClosestPointDist::evalLeaf(size_t index, const IntLeafT& leaf) const -{ - typename IntLeafT::ValueOnCIter iter; - const Vec3s center = mInstancePoints[index]; - size_t& closestPointIndex = const_cast(mClosestPointIndex); - - for (iter = leaf.cbeginValueOn(); iter; ++iter) { - - const Vec3s& point = mSurfacePointList[iter.getValue()]; - float tmpDist = (point - center).lengthSqr(); - - if (tmpDist < mInstanceDistances[index]) { - mInstanceDistances[index] = tmpDist; - closestPointIndex = iter.getValue(); - } - } -} - - -template -void -ClosestPointDist::evalNode(size_t pointIndex, size_t nodeIndex) const -{ - const Vec3R& pos = mInstancePoints[pointIndex]; - float minDist = mInstanceDistances[pointIndex]; - size_t minDistIdx = 0; - Vec3R center; - bool updatedDist = false; - - for (size_t i = mLeafRanges[nodeIndex].first, n = 0; - i < mLeafRanges[nodeIndex].second; ++i, ++n) - { - float& distToLeaf = const_cast(mLeafDistances[n]); - - center[0] = mLeafBoundingSpheres[i][0]; - center[1] = mLeafBoundingSpheres[i][1]; - center[2] = mLeafBoundingSpheres[i][2]; - - distToLeaf = float((pos - center).lengthSqr() - mLeafBoundingSpheres[i][3]); - - if (distToLeaf < minDist) { - minDist = distToLeaf; - minDistIdx = i; - updatedDist = true; - } - } - - if (!updatedDist) return; - - evalLeaf(pointIndex, *mLeafNodes[minDistIdx]); - - for (size_t i = mLeafRanges[nodeIndex].first, n = 0; - i < mLeafRanges[nodeIndex].second; ++i, ++n) - { - if (mLeafDistances[n] < mInstanceDistances[pointIndex] && i != minDistIdx) { - evalLeaf(pointIndex, *mLeafNodes[i]); - } - } -} - - -template -void -ClosestPointDist::operator()(const tbb::blocked_range& range) const -{ - Vec3R center; - for (size_t n = range.begin(); n != range.end(); ++n) { - - const Vec3R& pos = mInstancePoints[n]; - float minDist = mInstanceDistances[n]; - size_t minDistIdx = 0; - - for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) { - float& distToNode = const_cast(mNodeDistances[i]); - - center[0] = mNodeBoundingSpheres[i][0]; - center[1] = mNodeBoundingSpheres[i][1]; - center[2] = mNodeBoundingSpheres[i][2]; - - distToNode = float((pos - center).lengthSqr() - mNodeBoundingSpheres[i][3]); - - if (distToNode < minDist) { - minDist = distToNode; - minDistIdx = i; - } - } - - evalNode(n, minDistIdx); - - for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) { - if (mNodeDistances[i] < mInstanceDistances[n] && i != minDistIdx) { - evalNode(n, i); - } - } - - mInstanceDistances[n] = std::sqrt(mInstanceDistances[n]); - - if (mTransformPoints) mInstancePoints[n] = mSurfacePointList[mClosestPointIndex]; - } -} - - -class UpdatePoints -{ -public: - UpdatePoints( - const Vec4s& sphere, - const std::vector& points, - std::vector& distances, - std::vector& mask, - bool overlapping); - - float radius() const { return mRadius; } - int index() const { return mIndex; }; - - inline void run(bool threaded = true); - - - UpdatePoints(UpdatePoints&, tbb::split); - inline void operator()(const tbb::blocked_range& range); - void join(const UpdatePoints& rhs) - { - if (rhs.mRadius > mRadius) { - mRadius = rhs.mRadius; - mIndex = rhs.mIndex; - } - } - -private: - - const Vec4s& mSphere; - const std::vector& mPoints; - - std::vector& mDistances; - std::vector& mMask; - - bool mOverlapping; - float mRadius; - int mIndex; -}; - -inline -UpdatePoints::UpdatePoints( - const Vec4s& sphere, - const std::vector& points, - std::vector& distances, - std::vector& mask, - bool overlapping) - : mSphere(sphere) - , mPoints(points) - , mDistances(distances) - , mMask(mask) - , mOverlapping(overlapping) - , mRadius(0.0) - , mIndex(0) -{ -} - -inline -UpdatePoints::UpdatePoints(UpdatePoints& rhs, tbb::split) - : mSphere(rhs.mSphere) - , mPoints(rhs.mPoints) - , mDistances(rhs.mDistances) - , mMask(rhs.mMask) - , mOverlapping(rhs.mOverlapping) - , mRadius(rhs.mRadius) - , mIndex(rhs.mIndex) -{ -} - -inline void -UpdatePoints::run(bool threaded) -{ - if (threaded) { - tbb::parallel_reduce(tbb::blocked_range(0, mPoints.size()), *this); - } else { - (*this)(tbb::blocked_range(0, mPoints.size())); - } -} - -inline void -UpdatePoints::operator()(const tbb::blocked_range& range) -{ - Vec3s pos; - for (size_t n = range.begin(); n != range.end(); ++n) { - if (mMask[n]) continue; - - pos.x() = float(mPoints[n].x()) - mSphere[0]; - pos.y() = float(mPoints[n].y()) - mSphere[1]; - pos.z() = float(mPoints[n].z()) - mSphere[2]; - - float dist = pos.length(); - - if (dist < mSphere[3]) { - mMask[n] = 1; - continue; - } - - if (!mOverlapping) { - mDistances[n] = std::min(mDistances[n], (dist - mSphere[3])); - } - - if (mDistances[n] > mRadius) { - mRadius = mDistances[n]; - mIndex = int(n); - } - } -} - - -} // namespace internal - - -//////////////////////////////////////// - - -template -inline void -fillWithSpheres( - const GridT& grid, - std::vector& spheres, - int maxSphereCount, - bool overlapping, - float minRadius, - float maxRadius, - float isovalue, - int instanceCount, - InterrupterT* interrupter) -{ - spheres.clear(); - spheres.reserve(maxSphereCount); - - const bool addNBPoints = grid.activeVoxelCount() < 10000; - int instances = std::max(instanceCount, maxSphereCount); - - typedef typename GridT::TreeType TreeT; - typedef typename GridT::ValueType ValueT; - - typedef typename TreeT::template ValueConverter::Type BoolTreeT; - typedef typename TreeT::template ValueConverter::Type IntTreeT; - typedef typename TreeT::template ValueConverter::Type Int16TreeT; - - typedef tree::LeafManager LeafManagerT; - typedef tree::LeafManager IntLeafManagerT; - typedef tree::LeafManager Int16LeafManagerT; - - - typedef boost::mt11213b RandGen; - RandGen mtRand(/*seed=*/0); - - const TreeT& tree = grid.tree(); - const math::Transform& transform = grid.transform(); - - std::vector instancePoints; - - { // Scatter candidate sphere centroids (instancePoints) - typename Grid::Ptr interiorMaskPtr; - - if (grid.getGridClass() == GRID_LEVEL_SET) { - interiorMaskPtr = sdfInteriorMask(grid, ValueT(isovalue)); - } else { - interiorMaskPtr = typename Grid::Ptr(Grid::create(false)); - interiorMaskPtr->setTransform(transform.copy()); - interiorMaskPtr->tree().topologyUnion(tree); - } - - if (interrupter && interrupter->wasInterrupted()) return; - - erodeVoxels(interiorMaskPtr->tree(), 1); - - instancePoints.reserve(instances); - internal::PointAccessor ptnAcc(instancePoints); - - UniformPointScatter scatter( - ptnAcc, Index64(addNBPoints ? (instances / 2) : instances), mtRand, interrupter); - - scatter(*interiorMaskPtr); - } - - if (interrupter && interrupter->wasInterrupted()) return; - - std::vector instanceRadius; - - ClosestSurfacePoint csp; - csp.initialize(grid, isovalue, interrupter); - - // add extra instance points in the interior narrow band. - if (instancePoints.size() < size_t(instances)) { - const Int16TreeT& signTree = csp.signTree(); - typename Int16TreeT::LeafNodeType::ValueOnCIter it; - typename Int16TreeT::LeafCIter leafIt = signTree.cbeginLeaf(); - - for (; leafIt; ++leafIt) { - for (it = leafIt->cbeginValueOn(); it; ++it) { - const int flags = it.getValue(); - if (!(0xE00 & flags) && (flags & 0x100)) { - instancePoints.push_back(transform.indexToWorld(it.getCoord())); - } - - if (instancePoints.size() == size_t(instances)) break; - } - if (instancePoints.size() == size_t(instances)) break; - } - } - - - if (interrupter && interrupter->wasInterrupted()) return; - - if (!csp.search(instancePoints, instanceRadius)) return; - - std::vector instanceMask(instancePoints.size(), 0); - float largestRadius = 0.0; - int largestRadiusIdx = 0; - - for (size_t n = 0, N = instancePoints.size(); n < N; ++n) { - if (instanceRadius[n] > largestRadius) { - largestRadius = instanceRadius[n]; - largestRadiusIdx = int(n); - } - } - - Vec3s pos; - Vec4s sphere; - minRadius = float(minRadius * transform.voxelSize()[0]); - maxRadius = float(maxRadius * transform.voxelSize()[0]); - - for (size_t s = 0, S = std::min(size_t(maxSphereCount), instancePoints.size()); s < S; ++s) { - - if (interrupter && interrupter->wasInterrupted()) return; - - largestRadius = std::min(maxRadius, largestRadius); - - if (s != 0 && largestRadius < minRadius) break; - - sphere[0] = float(instancePoints[largestRadiusIdx].x()); - sphere[1] = float(instancePoints[largestRadiusIdx].y()); - sphere[2] = float(instancePoints[largestRadiusIdx].z()); - sphere[3] = largestRadius; - - spheres.push_back(sphere); - instanceMask[largestRadiusIdx] = 1; - - internal::UpdatePoints op( - sphere, instancePoints, instanceRadius, instanceMask, overlapping); - op.run(); - - largestRadius = op.radius(); - largestRadiusIdx = op.index(); - } -} - -//////////////////////////////////////// - - -template -ClosestSurfacePoint::ClosestSurfacePoint() - : mIsInitialized(false) - , mLeafBoundingSpheres(0) - , mNodeBoundingSpheres(0) - , mLeafRanges(0) - , mLeafNodes(0) - , mSurfacePointList() - , mPointListSize(0) - , mMaxNodeLeafs(0) - , mMaxRadiusSqr(0.0) - , mIdxTreePt() -{ -} - -template -void -ClosestSurfacePoint::initialize(const GridT& grid, float isovalue) -{ - initialize(grid, isovalue, NULL); -} - - -template -template -void -ClosestSurfacePoint::initialize( - const GridT& grid, float isovalue, InterrupterT* interrupter) -{ - mIsInitialized = false; - typedef tree::LeafManager LeafManagerT; - typedef tree::LeafManager IntLeafManagerT; - typedef tree::LeafManager Int16LeafManagerT; - typedef typename GridT::ValueType ValueT; - - const TreeT& tree = grid.tree(); - const math::Transform& transform = grid.transform(); - - { // Extract surface point cloud - - { - LeafManagerT leafs(tree); - internal::SignData - signDataOp(tree, leafs, ValueT(isovalue)); - - signDataOp.run(); - - mSignTreePt = signDataOp.signTree(); - mIdxTreePt = signDataOp.idxTree(); - } - - if (interrupter && interrupter->wasInterrupted()) return; - - Int16LeafManagerT signLeafs(*mSignTreePt); - - std::vector regions(signLeafs.leafCount(), 0); - signLeafs.foreach(internal::CountPoints(regions)); - - mPointListSize = 0; - for (size_t tmp = 0, n = 0, N = regions.size(); n < N; ++n) { - tmp = regions[n]; - regions[n] = mPointListSize; - mPointListSize += tmp; - } - - if (mPointListSize == 0) return; - - mSurfacePointList.reset(new Vec3s[mPointListSize]); - - internal::GenPoints - pointOp(signLeafs, tree, *mIdxTreePt, mSurfacePointList, regions, transform, isovalue); - - pointOp.run(); - - mIdxTreePt->topologyUnion(*mSignTreePt); - } - - if (interrupter && interrupter->wasInterrupted()) return; - - // estimate max sphere radius (sqr dist) - CoordBBox bbox = grid.evalActiveVoxelBoundingBox(); - - Vec3s dim = transform.indexToWorld(bbox.min()) - - transform.indexToWorld(bbox.max()); - - dim[0] = std::abs(dim[0]); - dim[1] = std::abs(dim[1]); - dim[2] = std::abs(dim[2]); - - mMaxRadiusSqr = std::min(std::min(dim[0], dim[1]), dim[2]); - mMaxRadiusSqr *= 0.51f; - mMaxRadiusSqr *= mMaxRadiusSqr; - - - IntLeafManagerT idxLeafs(*mIdxTreePt); - - - typedef typename IntTreeT::RootNodeType IntRootNodeT; - typedef typename IntRootNodeT::NodeChainType IntNodeChainT; - BOOST_STATIC_ASSERT(boost::mpl::size::value > 1); - typedef typename boost::mpl::at >::type IntInternalNodeT; - - - typename IntTreeT::NodeCIter nIt = mIdxTreePt->cbeginNode(); - nIt.setMinDepth(IntTreeT::NodeCIter::LEAF_DEPTH - 1); - nIt.setMaxDepth(IntTreeT::NodeCIter::LEAF_DEPTH - 1); - - std::vector internalNodes; - - const IntInternalNodeT* node = NULL; - for (; nIt; ++nIt) { - nIt.getNode(node); - if (node) internalNodes.push_back(node); - } - - std::vector().swap(mLeafRanges); - mLeafRanges.resize(internalNodes.size()); - - std::vector().swap(mLeafNodes); - mLeafNodes.reserve(idxLeafs.leafCount()); - - typename IntInternalNodeT::ChildOnCIter leafIt; - mMaxNodeLeafs = 0; - for (size_t n = 0, N = internalNodes.size(); n < N; ++n) { - - mLeafRanges[n].first = mLeafNodes.size(); - - size_t leafCount = 0; - for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) { - mLeafNodes.push_back(&(*leafIt)); - ++leafCount; - } - - mMaxNodeLeafs = std::max(leafCount, mMaxNodeLeafs); - - mLeafRanges[n].second = mLeafNodes.size(); - } - - std::vector().swap(mLeafBoundingSpheres); - mLeafBoundingSpheres.resize(mLeafNodes.size()); - - internal::LeafBS leafBS( - mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList); - leafBS.run(); - - - std::vector().swap(mNodeBoundingSpheres); - mNodeBoundingSpheres.resize(internalNodes.size()); - - internal::NodeBS nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres); - nodeBS.run(); - mIsInitialized = true; -} - - -template -bool -ClosestSurfacePoint::search(std::vector& points, - std::vector& distances, bool transformPoints) -{ - if (!mIsInitialized) return false; - - distances.clear(); - distances.resize(points.size(), mMaxRadiusSqr); - - internal::ClosestPointDist cpd(points, distances, mSurfacePointList, - mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres, - mMaxNodeLeafs, transformPoints); - - cpd.run(); - - return true; -} - - -template -bool -ClosestSurfacePoint::search(const std::vector& points, std::vector& distances) -{ - return search(const_cast& >(points), distances, false); -} - - -template -bool -ClosestSurfacePoint::searchAndReplace(std::vector& points, - std::vector& distances) -{ - return search(points, distances, true); -} - - -} // namespace tools -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/InternalNode.h b/openvdb_3_0_0_library/tree/InternalNode.h deleted file mode 100755 index eb07213..0000000 --- a/openvdb_3_0_0_library/tree/InternalNode.h +++ /dev/null @@ -1,2981 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file InternalNode.h -/// -/// @brief Internal table nodes for OpenVDB trees - -#ifndef OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for io::readData(), etc. -#include // for Abs(), isExactlyEqual() -#include -#include -#include "Iterator.h" -#include "NodeUnion.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -template struct SameInternalConfig; // forward declaration - - -template -class InternalNode -{ -public: - typedef _ChildNodeType ChildNodeType; - typedef typename ChildNodeType::LeafNodeType LeafNodeType; - typedef typename ChildNodeType::ValueType ValueType; - typedef NodeUnion UnionType; - typedef util::NodeMask NodeMaskType; - - static const Index - LOG2DIM = Log2Dim, - TOTAL = Log2Dim + ChildNodeType::TOTAL, - DIM = 1 << TOTAL, - NUM_VALUES = 1 << (3 * Log2Dim), - LEVEL = 1 + ChildNodeType::LEVEL; // level 0 = leaf - static const Index64 - NUM_VOXELS = uint64_t(1) << (3 * TOTAL); // total # of voxels represented by this node - - /// @brief ValueConverter::Type is the type of an InternalNode having the same - /// child hierarchy and dimensions as this node but a different value type, T. - template - struct ValueConverter { - typedef InternalNode::Type, Log2Dim> Type; - }; - - /// @brief SameConfiguration::value is @c true if and only if OtherNodeType - /// is the type of an InternalNode with the same dimensions as this node and whose - /// ChildNodeType has the same configuration as this node's ChildNodeType. - template - struct SameConfiguration { - static const bool value = - SameInternalConfig::value; - }; - - - InternalNode() {} - - explicit InternalNode(const ValueType& offValue); - - InternalNode(const Coord&, const ValueType& fillValue, bool active = false); - -#ifndef OPENVDB_2_ABI_COMPATIBLE - InternalNode(PartialCreate, const Coord&, const ValueType& fillValue, bool active = false); -#endif - - /// Deep copy constructor - InternalNode(const InternalNode&); - - /// Value conversion copy constructor - template - explicit InternalNode(const InternalNode& other); - - /// Topology copy constructor - template - InternalNode(const InternalNode& other, - const ValueType& background, TopologyCopy); - - /// Topology copy constructor - template - InternalNode(const InternalNode& other, - const ValueType& offValue, const ValueType& onValue, TopologyCopy); - - virtual ~InternalNode(); - -protected: - typedef typename NodeMaskType::OnIterator MaskOnIterator; - typedef typename NodeMaskType::OffIterator MaskOffIterator; - typedef typename NodeMaskType::DenseIterator MaskDenseIterator; - - // Type tags to disambiguate template instantiations - struct ValueOn {}; struct ValueOff {}; struct ValueAll {}; - struct ChildOn {}; struct ChildOff {}; struct ChildAll {}; - - // The following class templates implement the iterator interfaces specified in Iterator.h - // by providing getItem(), setItem() and/or modifyItem() methods. - - template - struct ChildIter: public SparseIteratorBase< - MaskIterT, ChildIter, NodeT, ChildT> - { - ChildIter() {} - ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase< - MaskIterT, ChildIter, NodeT, ChildT>(iter, parent) {} - - ChildT& getItem(Index pos) const - { - assert(this->parent().isChildMaskOn(pos)); - return *(this->parent().getChildNode(pos)); - } - - // Note: setItem() can't be called on const iterators. - void setItem(Index pos, const ChildT& c) const { this->parent().resetChildNode(pos, &c); } - - // Note: modifyItem() isn't implemented, since it's not useful for child node pointers. - };// ChildIter - - template - struct ValueIter: public SparseIteratorBase< - MaskIterT, ValueIter, NodeT, ValueT> - { - ValueIter() {} - ValueIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase< - MaskIterT, ValueIter, NodeT, ValueT>(iter, parent) {} - - const ValueT& getItem(Index pos) const { return this->parent().mNodes[pos].getValue(); } - - // Note: setItem() can't be called on const iterators. - void setItem(Index pos, const ValueT& v) const { this->parent().mNodes[pos].setValue(v); } - - // Note: modifyItem() can't be called on const iterators. - template - void modifyItem(Index pos, const ModifyOp& op) const - { - op(this->parent().mNodes[pos].getValue()); - } - };// ValueIter - - template - struct DenseIter: public DenseIteratorBase< - MaskDenseIterator, DenseIter, NodeT, ChildT, ValueT> - { - typedef DenseIteratorBase BaseT; - typedef typename BaseT::NonConstValueType NonConstValueT; - - DenseIter() {} - DenseIter(const MaskDenseIterator& iter, NodeT* parent): - DenseIteratorBase(iter, parent) {} - - bool getItem(Index pos, ChildT*& child, NonConstValueT& value) const - { - if (this->parent().isChildMaskOn(pos)) { - child = this->parent().getChildNode(pos); - return true; - } - child = NULL; - value = this->parent().mNodes[pos].getValue(); - return false; - } - - // Note: setItem() can't be called on const iterators. - void setItem(Index pos, ChildT* child) const - { - this->parent().resetChildNode(pos, child); - } - - // Note: unsetItem() can't be called on const iterators. - void unsetItem(Index pos, const ValueT& value) const - { - this->parent().unsetChildNode(pos, value); - } - };// DenseIter - -public: - // Iterators (see Iterator.h for usage) - typedef ChildIter ChildOnIter; - typedef ChildIter ChildOnCIter; - typedef ValueIter ChildOffIter; - typedef ValueIter ChildOffCIter; - typedef DenseIter ChildAllIter; - typedef DenseIter ChildAllCIter; - - typedef ValueIter ValueOnIter; - typedef ValueIter ValueOnCIter; - typedef ValueIter ValueOffIter; - typedef ValueIter ValueOffCIter; - typedef ValueIter ValueAllIter; - typedef ValueIter ValueAllCIter; - - ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mChildMask.beginOn(), this); } - ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mChildMask.beginOff(), this); } - ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mChildMask.beginDense(), this); } - ChildOnCIter beginChildOn() const { return cbeginChildOn(); } - ChildOffCIter beginChildOff() const { return cbeginChildOff(); } - ChildAllCIter beginChildAll() const { return cbeginChildAll(); } - ChildOnIter beginChildOn() { return ChildOnIter(mChildMask.beginOn(), this); } - ChildOffIter beginChildOff() { return ChildOffIter(mChildMask.beginOff(), this); } - ChildAllIter beginChildAll() { return ChildAllIter(mChildMask.beginDense(), this); } - - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); } - /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them! - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mChildMask.beginOff(), this); } - ValueOnCIter beginValueOn() const { return cbeginValueOn(); } - /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them! - ValueOffCIter beginValueOff() const { return cbeginValueOff(); } - ValueAllCIter beginValueAll() const { return cbeginValueAll(); } - ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); } - /// @warning This iterator will also visit child nodes so use isChildMaskOn to skip them! - ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); } - ValueAllIter beginValueAll() { return ValueAllIter(mChildMask.beginOff(), this); } - - - static Index dim() { return DIM; } - static Index getLevel() { return LEVEL; } - static void getNodeLog2Dims(std::vector& dims); - static Index getChildDim() { return ChildNodeType::DIM; } - - /// Return the linear table offset of the given global or local coordinates. - static Index coordToOffset(const Coord& xyz); - /// @brief Return the local coordinates for a linear table offset, - /// where offset 0 has coordinates (0, 0, 0). - static void offsetToLocalCoord(Index n, Coord& xyz); - /// Return the global coordinates for a linear table offset. - Coord offsetToGlobalCoord(Index n) const; - - /// Return the grid index coordinates of this node's local origin. - const Coord& origin() const { return mOrigin; } - /// Set the grid index coordinates of this node's local origin. - void setOrigin(const Coord& origin) { mOrigin = origin; } - - Index32 leafCount() const; - Index32 nonLeafCount() const; - Index64 onVoxelCount() const; - Index64 offVoxelCount() const; - Index64 onLeafVoxelCount() const; - Index64 offLeafVoxelCount() const; - Index64 onTileCount() const; - - /// Return the total amount of memory in bytes occupied by this node and its children. - Index64 memUsage() const; - - /// @brief Expand the specified bounding box so that it includes the active tiles - /// of this internal node as well as all the active values in its child nodes. - /// If visitVoxels is false LeafNodes will be approximated as dense, i.e. with all - /// voxels active. Else the individual active voxels are visited to produce a tight bbox. - void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const; - - /// @brief Return the bounding box of this node, i.e., the full index space - /// spanned by the node regardless of its content. - CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); } - - bool isEmpty() const { return mChildMask.isOff(); } - - /// Return @c true if all of this node's table entries have the same active state - /// and the same constant value to within the given tolerance, - /// and return that value in @a constValue and the active state in @a state. - bool isConstant(ValueType& constValue, bool& state, - const ValueType& tolerance = zeroVal()) const; - /// Return @c true if this node has no children and only contains inactive values. - bool isInactive() const { return this->isChildMaskOff() && this->isValueMaskOff(); } - - /// Return @c true if the voxel at the given coordinates is active. - bool isValueOn(const Coord& xyz) const; - /// Return @c true if the voxel at the given offset is active. - bool isValueOn(Index offset) const { return mValueMask.isOn(offset); } - - /// Return @c true if this node or any of its child nodes have any active tiles. - bool hasActiveTiles() const; - - const ValueType& getValue(const Coord& xyz) const; - bool probeValue(const Coord& xyz, ValueType& value) const; - - /// @brief Return the level of the tree (0 = leaf) at which the value - /// at the given coordinates resides. - Index getValueLevel(const Coord& xyz) const; - - /// @brief If the first entry in this node's table is a tile, return the tile's value. - /// Otherwise, return the result of calling getFirstValue() on the child. - const ValueType& getFirstValue() const; - /// @brief If the last entry in this node's table is a tile, return the tile's value. - /// Otherwise, return the result of calling getLastValue() on the child. - const ValueType& getLastValue() const; - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on); - /// Set the value of the voxel at the given coordinates but don't change its active state. - void setValueOnly(const Coord& xyz, const ValueType& value); - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz); - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValueOn(const Coord& xyz, const ValueType& value); - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz); - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value); - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - template - void modifyValue(const Coord& xyz, const ModifyOp& op); - /// Apply a functor to the voxel at the given coordinates. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op); - - /// Return the value of the voxel at the given coordinates and, if necessary, update - /// the accessor with pointers to the nodes along the path from the root node to - /// the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const; - - /// Return @c true if the voxel at the given coordinates is active and, if necessary, - /// update the accessor with pointers to the nodes along the path from the root node - /// to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - bool isValueOnAndCache(const Coord& xyz, AccessorT&) const; - - /// Change the value of the voxel at the given coordinates and mark it as active. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// Set the value of the voxel at the given coordinate but preserves its active state. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&); - - /// Apply a functor to the voxel at the given coordinates. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&); - - /// Change the value of the voxel at the given coordinates and mark it as inactive. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// Set the active state of the voxel at the given coordinates without changing its value. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&); - - /// Return, in @a value, the value of the voxel at the given coordinates and, - /// if necessary, update the accessor with pointers to the nodes along - /// the path from the root node to the node containing the voxel. - /// @return @c true if the voxel at the given coordinates is active - /// @note Used internally by ValueAccessor. - template - bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const; - - /// @brief Return the level of the tree (0 = leaf) at which the value - /// at the given coordinates resides. - /// - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - Index getValueLevelAndCache(const Coord& xyz, AccessorT&) const; - - /// Mark all values (both tiles and voxels) as active. - void setValuesOn(); - - // - // I/O - // - void writeTopology(std::ostream&, bool toHalf = false) const; - void readTopology(std::istream&, bool fromHalf = false); - void writeBuffers(std::ostream&, bool toHalf = false) const; - void readBuffers(std::istream&, bool fromHalf = false); - void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false); - - - // - // Aux methods - // - /// @brief Set all voxels within an axis-aligned box to a constant value. - /// (The min and max coordinates are inclusive.) - void fill(const CoordBBox& bbox, const ValueType&, bool active = true); - - /// Change the sign of all the values represented in this node and - /// its child nodes. - void negate(); - - /// Densify active tiles, i.e., replace them with leaf-level active voxels. - void voxelizeActiveTiles(); - - /// @brief Copy into a dense grid the values of the voxels that lie within - /// a given bounding box. - /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - /// @note @a bbox is assumed to be identical to or contained in the coordinate domains - /// of both the dense grid and this node, i.e., no bounds checking is performed. - template - void copyToDense(const CoordBBox& bbox, DenseT& dense) const; - - /// @brief Efficiently merge another tree into this tree using one of several schemes. - /// @warning This operation cannibalizes the other tree. - template - void merge(InternalNode& other, const ValueType& background, const ValueType& otherBackground); - - /// @brief Merge, using one of several schemes, this node (and its descendants) - /// with a tile of the same dimensions and the given value and active state. - template void merge(const ValueType& tileValue, bool tileActive); - - /// @brief Union this branch's set of active values with the other branch's - /// active values. The value type of the other branch can be different. - /// @details The resulting state of a value is active if the corresponding value - /// was already active OR if it is active in the other tree. Also, a resulting - /// value maps to a voxel if the corresponding value already mapped to a voxel - /// OR if it is a voxel in the other tree. Thus, a resulting value can only - /// map to a tile if the corresponding value already mapped to a tile - /// AND if it is a tile value in other tree. - /// - /// Specifically, active tiles and voxels in this branch are not changed, and - /// tiles or voxels that were inactive in this branch but active in the other branch - /// are marked as active in this branch but left with their original values. - template - void topologyUnion(const InternalNode& other); - - /// @brief Intersects this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. - /// @details The resulting state of a value is active only if the corresponding - /// value was already active AND if it is active in the other tree. Also, a - /// resulting value maps to a voxel if the corresponding value - /// already mapped to an active voxel in either of the two grids - /// and it maps to an active tile or voxel in the other grid. - /// - /// @note This operation can delete branches in this grid if they - /// overlap with inactive tiles in the other grid. Likewise active - /// voxels can be turned into unactive voxels resulting in leaf - /// nodes with no active values. Thus, it is recommended to - /// subsequently call prune. - template - void topologyIntersection(const InternalNode& other, - const ValueType& background); - - /// @brief Difference this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active only if the original voxel is - /// active in this node and inactive in the other node. - /// - /// @details The last dummy argument is required to match the signature - /// for InternalNode::topologyDifference. - /// - /// @note This operation modifies only active states, not - /// values. Also note that this operation can result in all voxels - /// being inactive so consider subsequnetly calling prune. - template - void topologyDifference(const InternalNode& other, - const ValueType& background); - - template - void combine(InternalNode& other, CombineOp&); - template - void combine(const ValueType& value, bool valueIsActive, CombineOp&); - - template - void combine2(const InternalNode& other0, const OtherNodeType& other1, CombineOp&); - template - void combine2(const ValueType& value, const OtherNodeType& other, bool valIsActive, CombineOp&); - template - void combine2(const InternalNode& other, const OtherValueType&, bool valIsActive, CombineOp&); - - /// @brief Calls the templated functor BBoxOp with bounding box - /// information for all active tiles and leaf nodes in this node. - /// An additional level argument is provided for each callback. - /// - /// @note The bounding boxes are guarenteed to be non-overlapping. - template void visitActiveBBox(BBoxOp&) const; - - template void visit(VisitorOp&); - template void visit(VisitorOp&) const; - - template - void visit2Node(OtherNodeType& other, VisitorOp&); - template - void visit2Node(OtherNodeType& other, VisitorOp&) const; - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false); - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const; - - /// Set all voxels that lie outside the given axis-aligned box to the background. - void clip(const CoordBBox&, const ValueType& background); - - /// @brief Reduce the memory footprint of this tree by replacing with tiles - /// any nodes whose values are all the same (optionally to within a tolerance) - /// and have the same active state. - void prune(const ValueType& tolerance = zeroVal()); - - /// @brief Add the specified leaf to this node, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeType* leaf); - - /// @brief Same as addLeaf() except, if necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - void addLeafAndCache(LeafNodeType* leaf, AccessorT&); - - /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z) - /// and replace it with a tile of the specified value and state. - /// If no such node exists, leave the tree unchanged and return @c NULL. - /// - /// @note The caller takes ownership of the node and is responsible for deleting it. - /// - /// @warning Since this method potentially removes nodes and branches of the tree, - /// it is important to clear the caches of all ValueAccessors associated with this tree. - template - NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state); - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly creating a parent branch or deleting a child branch in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state); - - /// @brief Delete any existing child branch at the specified offset and add a tile. - void addTile(Index offset, const ValueType& value, bool state); - - /// @brief Same as addTile() except, if necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing (x, y, z). - template - void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&); - - //@{ - /// @brief Return a pointer to the node that contains voxel (x, y, z). - /// If no such node exists, return NULL. - template NodeType* probeNode(const Coord& xyz); - template const NodeType* probeConstNode(const Coord& xyz) const; - //@} - - //@{ - /// @brief Same as probeNode() except, if necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing (x, y, z). - template - NodeType* probeNodeAndCache(const Coord& xyz, AccessorT&); - template - const NodeType* probeConstNodeAndCache(const Coord& xyz, AccessorT&) const; - //@} - - //@{ - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, return NULL. - LeafNodeType* probeLeaf(const Coord& xyz); - const LeafNodeType* probeConstLeaf(const Coord& xyz) const; - const LeafNodeType* probeLeaf(const Coord& xyz) const; - //@} - - //@{ - /// @brief Same as probeLeaf() except, if necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing (x, y, z). - template - LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc); - template - const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const; - template - const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const; - //@} - - /// @brief Return the leaf node that contains voxel (x, y, z). - /// If no such node exists, create one, but preserve the values and - /// active states of all voxels. - /// - /// @details Use this method to preallocate a static tree topology - /// over which to safely perform multithreaded processing. - LeafNodeType* touchLeaf(const Coord& xyz); - - /// @brief Same as touchLeaf() except, if necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT&); - - //@{ - /// @brief Adds all nodes of a certain type to a container with the following API: - /// @code - /// struct ArrayT { - /// typedef value_type;// defines the type of nodes to be added to the array - /// void push_back(value_type nodePtr);// method that add nodes to the array - /// }; - /// @endcode - /// @details An example of a wrapper around a c-style array is: - /// @code - /// struct MyArray { - /// typedef LeafType* value_type; - /// value_type* ptr; - /// MyArray(value_type* array) : ptr(array) {} - /// void push_back(value_type leaf) { *ptr++ = leaf; } - ///}; - /// @endcode - /// @details An example that constructs a list of pointer to all leaf nodes is: - /// @code - /// std::vector array;//most std contains have the required API - /// array.reserve(tree.leafCount());//this is a fast preallocation. - /// tree.getNodes(array); - /// @endcode - template void getNodes(ArrayT& array); - template void getNodes(ArrayT& array) const; - //@} - - /// @brief Change inactive tiles or voxels with value oldBackground to newBackground - /// or -oldBackground to -newBackground. Active values are unchanged. - void resetBackground(const ValueType& oldBackground, const ValueType& newBackground); - - /// @brief Return @c true if the given tree branch has the same node and active value - /// topology as this tree branch (but possibly a different @c ValueType). - template - bool hasSameTopology(const InternalNode* other) const; - -protected: - //@{ - /// Allow iterators to call mask accessor methods (setValueMask(), setChildMask(), etc.). - /// @todo Make mask accessors public? - friend class IteratorBase; - friend class IteratorBase; - friend class IteratorBase; - //@} - - /// @brief During topology-only construction, access is needed - /// to protected/private members of other template instances. - template friend class InternalNode; - - // Mask accessors -public: - bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); } - bool isValueMaskOn() const { return mValueMask.isOn(); } - bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); } - bool isValueMaskOff() const { return mValueMask.isOff(); } - bool isChildMaskOn(Index n) const { return mChildMask.isOn(n); } - bool isChildMaskOff(Index n) const { return mChildMask.isOff(n); } - bool isChildMaskOff() const { return mChildMask.isOff(); } - const NodeMaskType& getValueMask() const { return mValueMask; } - const NodeMaskType& getChildMask() const { return mChildMask; } - NodeMaskType getValueOffMask() const - { - NodeMaskType mask = mValueMask; - mask |= mChildMask; - mask.toggle(); - return mask; - } - const UnionType* getTable() const { return mNodes; } -protected: - //@{ - /// Use a mask accessor to ensure consistency between the child and value masks; - /// i.e., the value mask should always be off wherever the child mask is on. - void setValueMask(Index n, bool on) { mValueMask.set(n, mChildMask.isOn(n) ? false : on); } - //@} - - void makeChildNodeEmpty(Index n, const ValueType& value); - void setChildNode( Index i, ChildNodeType* child);//assumes a tile - void resetChildNode(Index i, ChildNodeType* child);//checks for an existing child - ChildNodeType* unsetChildNode(Index i, const ValueType& value); - - template - static inline void doVisit(NodeT&, VisitorOp&); - - template - static inline void doVisit2Node(NodeT&, OtherNodeT&, VisitorOp&); - - template - static inline void doVisit2(NodeT&, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS); - - ///@{ - /// @brief Returns a pointer to the child node at the linear offset n. - /// @warning This protected method assumes that a child node exists at - /// the specified linear offset! - ChildNodeType* getChildNode(Index n); - const ChildNodeType* getChildNode(Index n) const; - ///@} - - - UnionType mNodes[NUM_VALUES]; - NodeMaskType mChildMask, mValueMask; - /// Global grid index coordinates (x,y,z) of the local origin of this node - Coord mOrigin; -}; // class InternalNode - - -//////////////////////////////////////// - - -//@{ -/// Helper metafunction used to implement InternalNode::SameConfiguration -/// (which, as an inner class, can't be independently specialized) -template -struct SameInternalConfig { - static const bool value = false; -}; - -template -struct SameInternalConfig > { - static const bool value = ChildT1::template SameConfiguration::value; -}; -//@} - - -//////////////////////////////////////// - - -template -inline -InternalNode::InternalNode(const ValueType& background) -{ - for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(background); -} - - -template -inline -InternalNode::InternalNode(const Coord& origin, const ValueType& val, bool active): - mOrigin(origin[0] & ~(DIM - 1), // zero out the low-order bits - origin[1] & ~(DIM - 1), - origin[2] & ~(DIM - 1)) -{ - if (active) mValueMask.setOn(); - for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -// For InternalNodes, the PartialCreate constructor is identical to its -// non-PartialCreate counterpart. -template -inline -InternalNode::InternalNode(PartialCreate, - const Coord& origin, const ValueType& val, bool active) - : mOrigin(origin[0] & ~(DIM-1), origin[1] & ~(DIM-1), origin[2] & ~(DIM-1)) -{ - if (active) mValueMask.setOn(); - for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(val); -} -#endif - - -template -inline -InternalNode::InternalNode(const InternalNode& other): - mChildMask(other.mChildMask), - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ - for (Index i = 0; i < NUM_VALUES; ++i) { - if (isChildMaskOn(i)) { - mNodes[i].setChild(new ChildNodeType(*(other.mNodes[i].getChild()))); - } else { - mNodes[i].setValue(other.mNodes[i].getValue()); - } - } -} - - -// Copy-construct from a node with the same configuration but a different ValueType. -template -template -inline -InternalNode::InternalNode(const InternalNode& other) - : mChildMask(other.mChildMask) - , mValueMask(other.mValueMask) - , mOrigin(other.mOrigin) -{ - struct Local { - /// @todo Consider using a value conversion functor passed as an argument instead. - static inline ValueType - convertValue(const typename OtherChildNodeType::ValueType& val) { return ValueType(val); } - }; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (other.mChildMask.isOff(i)) { - mNodes[i].setValue(Local::convertValue(other.mNodes[i].getValue())); - } else { - mNodes[i].setChild(new ChildNodeType(*(other.mNodes[i].getChild()))); - } - } -} - - -template -template -inline -InternalNode::InternalNode(const InternalNode& other, - const ValueType& offValue, const ValueType& onValue, TopologyCopy): - mChildMask(other.mChildMask), - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ - for (Index i = 0; i < NUM_VALUES; ++i) { - if (isChildMaskOn(i)) { - mNodes[i].setChild(new ChildNodeType(*(other.mNodes[i].getChild()), - offValue, onValue, TopologyCopy())); - } else { - mNodes[i].setValue(isValueMaskOn(i) ? onValue : offValue); - } - } -} - -template -template -inline -InternalNode::InternalNode(const InternalNode& other, - const ValueType& background, TopologyCopy): - mChildMask(other.mChildMask), - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ - for (Index i = 0; i < NUM_VALUES; ++i) mNodes[i].setValue(background); - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - mNodes[iter.pos()].setChild(new ChildNodeType(*(other.mNodes[iter.pos()].getChild()), - background, TopologyCopy())); - } -} - - -template -inline -InternalNode::~InternalNode() -{ - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - delete mNodes[iter.pos()].getChild(); - } -} - - -//////////////////////////////////////// - - -template -inline Index32 -InternalNode::leafCount() const -{ - if (ChildNodeType::getLevel() == 0) return mChildMask.countOn(); - Index32 sum = 0; - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - sum += iter->leafCount(); - } - return sum; -} - - -template -inline Index32 -InternalNode::nonLeafCount() const -{ - Index32 sum = 1; - if (ChildNodeType::getLevel() == 0) return sum; - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - sum += iter->nonLeafCount(); - } - return sum; -} - - -template -inline Index64 -InternalNode::onVoxelCount() const -{ - Index64 sum = ChildT::NUM_VOXELS * mValueMask.countOn(); - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - sum += iter->onVoxelCount(); - } - return sum; -} - - -template -inline Index64 -InternalNode::offVoxelCount() const -{ - Index64 sum = ChildT::NUM_VOXELS * (NUM_VALUES-mValueMask.countOn()-mChildMask.countOn()); - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - sum += iter->offVoxelCount(); - } - return sum; -} - - -template -inline Index64 -InternalNode::onLeafVoxelCount() const -{ - Index64 sum = 0; - for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) { - sum += mNodes[iter.pos()].getChild()->onLeafVoxelCount(); - } - return sum; -} - - -template -inline Index64 -InternalNode::offLeafVoxelCount() const -{ - Index64 sum = 0; - for (ChildOnCIter iter = this->beginChildOn(); iter; ++iter) { - sum += mNodes[iter.pos()].getChild()->offLeafVoxelCount(); - } - return sum; -} - -template -inline Index64 -InternalNode::onTileCount() const -{ - Index64 sum = mValueMask.countOn(); - for (ChildOnCIter iter = this->cbeginChildOn(); LEVEL>1 && iter; ++iter) { - sum += iter->onTileCount(); - } - return sum; -} - -template -inline Index64 -InternalNode::memUsage() const -{ - Index64 sum = NUM_VALUES * sizeof(UnionType) + mChildMask.memUsage() - + mValueMask.memUsage() + sizeof(mOrigin); - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - sum += iter->memUsage(); - } - return sum; -} - - -template -inline void -InternalNode::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const -{ - if (bbox.isInside(this->getNodeBoundingBox())) return; - - for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) { - bbox.expand(i.getCoord(), ChildT::DIM); - } - for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) { - i->evalActiveBoundingBox(bbox, visitVoxels); - } -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::prune(const ValueType& tolerance) -{ - bool state = false; - ValueType value = zeroVal(); - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - const Index i = iter.pos(); - ChildT* child = mNodes[i].getChild(); - child->prune(tolerance); - if (child->isConstant(value, state, tolerance)) { - delete child; - mChildMask.setOff(i); - mValueMask.set(i, state); - mNodes[i].setValue(value); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline NodeT* -InternalNode::stealNode(const Coord& xyz, const ValueType& value, bool state) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) return NULL; - ChildT* child = mNodes[n].getChild(); - if (boost::is_same::value) { - mChildMask.setOff(n); - mValueMask.set(n, state); - mNodes[n].setValue(value); - } - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template stealNode(xyz, value, state); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -template -inline NodeT* -InternalNode::probeNode(const Coord& xyz) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) return NULL; - ChildT* child = mNodes[n].getChild(); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline NodeT* -InternalNode::probeNodeAndCache(const Coord& xyz, AccessorT& acc) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) return NULL; - ChildT* child = mNodes[n].getChild(); - acc.insert(xyz, child); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeNodeAndCache(xyz, acc); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline const NodeT* -InternalNode::probeConstNode(const Coord& xyz) const -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) return NULL; - const ChildT* child = mNodes[n].getChild(); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeConstNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline const NodeT* -InternalNode::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) return NULL; - const ChildT* child = mNodes[n].getChild(); - acc.insert(xyz, child); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeConstNodeAndCache(xyz, acc); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -inline typename ChildT::LeafNodeType* -InternalNode::probeLeaf(const Coord& xyz) -{ - return this->template probeNode(xyz); -} - - -template -template -inline typename ChildT::LeafNodeType* -InternalNode::probeLeafAndCache(const Coord& xyz, AccessorT& acc) -{ - return this->template probeNodeAndCache(xyz, acc); -} - - -template -template -inline const typename ChildT::LeafNodeType* -InternalNode::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const -{ - return this->probeConstLeafAndCache(xyz, acc); -} - - -template -inline const typename ChildT::LeafNodeType* -InternalNode::probeConstLeaf(const Coord& xyz) const -{ - return this->template probeConstNode(xyz); -} - - -template -template -inline const typename ChildT::LeafNodeType* -InternalNode::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const -{ - return this->template probeConstNodeAndCache(xyz, acc); -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::addLeaf(LeafNodeType* leaf) -{ - assert(leaf != NULL); - const Coord& xyz = leaf->origin(); - const Index n = this->coordToOffset(xyz); - ChildT* child = NULL; - if (mChildMask.isOff(n)) { - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n)); - } else { - child = reinterpret_cast(leaf); - } - this->setChildNode(n, child); - } else { - if (ChildT::LEVEL>0) { - child = mNodes[n].getChild(); - } else { - delete mNodes[n].getChild(); - child = reinterpret_cast(leaf); - mNodes[n].setChild(child); - } - } - child->addLeaf(leaf); -} - - -template -template -inline void -InternalNode::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc) -{ - assert(leaf != NULL); - const Coord& xyz = leaf->origin(); - const Index n = this->coordToOffset(xyz); - ChildT* child = NULL; - if (mChildMask.isOff(n)) { - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n)); - acc.insert(xyz, child);//we only cache internal nodes - } else { - child = reinterpret_cast(leaf); - } - this->setChildNode(n, child); - } else { - if (ChildT::LEVEL>0) { - child = mNodes[n].getChild(); - acc.insert(xyz, child);//we only cache internal nodes - } else { - delete mNodes[n].getChild(); - child = reinterpret_cast(leaf); - mNodes[n].setChild(child); - } - } - child->addLeafAndCache(leaf, acc); -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::addTile(Index n, const ValueType& value, bool state) -{ - assert(n < NUM_VALUES); - this->makeChildNodeEmpty(n, value); - mValueMask.set(n, state); -} - - -template -inline void -InternalNode::addTile(Index level, const Coord& xyz, - const ValueType& value, bool state) -{ - if (LEVEL >= level) { - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) {// tile case - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n)); - this->setChildNode(n, child); - child->addTile(level, xyz, value, state); - } else { - mValueMask.set(n, state); - mNodes[n].setValue(value); - } - } else {// child branch case - ChildT* child = mNodes[n].getChild(); - if (LEVEL > level) { - child->addTile(level, xyz, value, state); - } else { - delete child; - mChildMask.setOff(n); - mValueMask.set(n, state); - mNodes[n].setValue(value); - } - } - } -} - - -template -template -inline void -InternalNode::addTileAndCache(Index level, const Coord& xyz, - const ValueType& value, bool state, AccessorT& acc) -{ - if (LEVEL >= level) { - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) {// tile case - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n)); - this->setChildNode(n, child); - acc.insert(xyz, child); - child->addTileAndCache(level, xyz, value, state, acc); - } else { - mValueMask.set(n, state); - mNodes[n].setValue(value); - } - } else {// child branch case - ChildT* child = mNodes[n].getChild(); - if (LEVEL > level) { - acc.insert(xyz, child); - child->addTileAndCache(level, xyz, value, state, acc); - } else { - delete child; - mChildMask.setOff(n); - mValueMask.set(n, state); - mNodes[n].setValue(value); - } - } - } -} - - -//////////////////////////////////////// - - -template -inline typename ChildT::LeafNodeType* -InternalNode::touchLeaf(const Coord& xyz) -{ - const Index n = this->coordToOffset(xyz); - ChildT* child = NULL; - if (mChildMask.isOff(n)) { - child = new ChildT(xyz, mNodes[n].getValue(), mValueMask.isOn(n)); - this->setChildNode(n, child); - } else { - child = mNodes[n].getChild(); - } - return child->touchLeaf(xyz); -} - - -template -template -inline typename ChildT::LeafNodeType* -InternalNode::touchLeafAndCache(const Coord& xyz, AccessorT& acc) -{ - const Index n = this->coordToOffset(xyz); - if (mChildMask.isOff(n)) { - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), mValueMask.isOn(n))); - } - acc.insert(xyz, mNodes[n].getChild()); - return mNodes[n].getChild()->touchLeafAndCache(xyz, acc); -} - - -//////////////////////////////////////// - - -template -inline bool -InternalNode::isConstant(ValueType& constValue, bool& state, - const ValueType& tolerance) const -{ - bool allEqual = true, firstValue = true, valueState = true; - ValueType value = zeroVal(); - for (Index i = 0; allEqual && i < NUM_VALUES; ++i) { - if (this->isChildMaskOff(i)) { - // If entry i is a value, check if it is within tolerance - // and whether its active state matches the other entries. - if (firstValue) { - firstValue = false; - valueState = isValueMaskOn(i); - value = mNodes[i].getValue(); - } else { - allEqual = (isValueMaskOn(i) == valueState) - && math::isApproxEqual(mNodes[i].getValue(), value, tolerance); - } - } else { - // If entry i is a child, check if the child is constant and within tolerance - // and whether its active state matches the other entries. - ValueType childValue = zeroVal(); - bool isChildOn = false; - if (mNodes[i].getChild()->isConstant(childValue, isChildOn, tolerance)) { - if (firstValue) { - firstValue = false; - valueState = isChildOn; - value = childValue; - } else { - allEqual = (isChildOn == valueState) - && math::isApproxEqual(childValue, value, tolerance); - } - } else { // child is not constant - allEqual = false; - } - } - } - if (allEqual) { - constValue = value; - state = valueState; - } - return allEqual; -} - - -//////////////////////////////////////// - - -template -inline bool -InternalNode::hasActiveTiles() const -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - const bool anyActiveTiles = !mValueMask.isOff(); - if (LEVEL==1 || anyActiveTiles) return anyActiveTiles; - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - if (iter->hasActiveTiles()) return true; - } - return false; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -inline bool -InternalNode::isValueOn(const Coord& xyz) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOff(n)) return this->isValueMaskOn(n); - return mNodes[n].getChild()->isValueOn(xyz); -} - -template -template -inline bool -InternalNode::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOff(n)) return this->isValueMaskOn(n); - acc.insert(xyz, mNodes[n].getChild()); - return mNodes[n].getChild()->isValueOnAndCache(xyz, acc); -} - - -template -inline const typename ChildT::ValueType& -InternalNode::getValue(const Coord& xyz) const -{ - const Index n = this->coordToOffset(xyz); - return this->isChildMaskOff(n) ? mNodes[n].getValue() - : mNodes[n].getChild()->getValue(xyz); -} - -template -template -inline const typename ChildT::ValueType& -InternalNode::getValueAndCache(const Coord& xyz, AccessorT& acc) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOn(n)) { - acc.insert(xyz, mNodes[n].getChild()); - return mNodes[n].getChild()->getValueAndCache(xyz, acc); - } - return mNodes[n].getValue(); -} - - -template -inline Index -InternalNode::getValueLevel(const Coord& xyz) const -{ - const Index n = this->coordToOffset(xyz); - return this->isChildMaskOff(n) ? LEVEL : mNodes[n].getChild()->getValueLevel(xyz); -} - -template -template -inline Index -InternalNode::getValueLevelAndCache(const Coord& xyz, AccessorT& acc) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOn(n)) { - acc.insert(xyz, mNodes[n].getChild()); - return mNodes[n].getChild()->getValueLevelAndCache(xyz, acc); - } - return LEVEL; -} - - -template -inline bool -InternalNode::probeValue(const Coord& xyz, ValueType& value) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOff(n)) { - value = mNodes[n].getValue(); - return this->isValueMaskOn(n); - } - return mNodes[n].getChild()->probeValue(xyz, value); -} - -template -template -inline bool -InternalNode::probeValueAndCache(const Coord& xyz, - ValueType& value, AccessorT& acc) const -{ - const Index n = this->coordToOffset(xyz); - if (this->isChildMaskOn(n)) { - acc.insert(xyz, mNodes[n].getChild()); - return mNodes[n].getChild()->probeValueAndCache(xyz, value, acc); - } - value = mNodes[n].getValue(); - return this->isValueMaskOn(n); -} - - -template -inline void -InternalNode::setValueOff(const Coord& xyz) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild && this->isValueMaskOn(n)) { - // If the voxel belongs to a constant tile that is active, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/true)); - } - if (hasChild) mNodes[n].getChild()->setValueOff(xyz); -} - - -template -inline void -InternalNode::setValueOn(const Coord& xyz) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild && !this->isValueMaskOn(n)) { - // If the voxel belongs to a constant tile that is inactive, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), /*active=*/false)); - } - if (hasChild) mNodes[n].getChild()->setValueOn(xyz); -} - - -template -inline void -InternalNode::setValueOff(const Coord& xyz, const ValueType& value) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool active = this->isValueMaskOn(n); - if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel belongs to a tile that is either active or that - // has a constant value that is different from the one provided, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) mNodes[n].getChild()->setValueOff(xyz, value); -} - -template -template -inline void -InternalNode::setValueOffAndCache(const Coord& xyz, - const ValueType& value, AccessorT& acc) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool active = this->isValueMaskOn(n); - if (active || !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel belongs to a tile that is either active or that - // has a constant value that is different from the one provided, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) { - ChildT* child = mNodes[n].getChild(); - acc.insert(xyz, child); - child->setValueOffAndCache(xyz, value, acc); - } -} - - -template -inline void -InternalNode::setValueOn(const Coord& xyz, const ValueType& value) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool active = this->isValueMaskOn(n); // tile's active state - if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel belongs to a tile that is either inactive or that - // has a constant value that is different from the one provided, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) mNodes[n].getChild()->setValueOn(xyz, value); -} - -template -template -inline void -InternalNode::setValueAndCache(const Coord& xyz, - const ValueType& value, AccessorT& acc) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool active = this->isValueMaskOn(n); - if (!active || !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel belongs to a tile that is either inactive or that - // has a constant value that is different from the one provided, - // a child subtree must be constructed. - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) { - acc.insert(xyz, mNodes[n].getChild()); - mNodes[n].getChild()->setValueAndCache(xyz, value, acc); - } -} - - -template -inline void -InternalNode::setValueOnly(const Coord& xyz, const ValueType& value) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel has a tile value that is different from the one provided, - // a child subtree must be constructed. - const bool active = this->isValueMaskOn(n); - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - if (hasChild) mNodes[n].getChild()->setValueOnly(xyz, value); -} - -template -template -inline void -InternalNode::setValueOnlyAndCache(const Coord& xyz, - const ValueType& value, AccessorT& acc) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild && !math::isExactlyEqual(mNodes[n].getValue(), value)) { - // If the voxel has a tile value that is different from the one provided, - // a child subtree must be constructed. - const bool active = this->isValueMaskOn(n); - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - if (hasChild) { - acc.insert(xyz, mNodes[n].getChild()); - mNodes[n].getChild()->setValueOnlyAndCache(xyz, value, acc); - } -} - - -template -inline void -InternalNode::setActiveState(const Coord& xyz, bool on) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - if (on != this->isValueMaskOn(n)) { - // If the voxel belongs to a tile with the wrong active state, - // then a child subtree must be constructed. - // 'on' is the voxel's new state, therefore '!on' is the tile's current state - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on)); - } - } - if (hasChild) mNodes[n].getChild()->setActiveState(xyz, on); -} - -template -template -inline void -InternalNode::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc) -{ - const Index n = this->coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - if (on != this->isValueMaskOn(n)) { - // If the voxel belongs to a tile with the wrong active state, - // then a child subtree must be constructed. - // 'on' is the voxel's new state, therefore '!on' is the tile's current state - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), !on)); - } - } - if (hasChild) { - ChildT* child = mNodes[n].getChild(); - acc.insert(xyz, child); - child->setActiveStateAndCache(xyz, on, acc); - } -} - - -template -inline void -InternalNode::setValuesOn() -{ - mValueMask = !mChildMask; - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - mNodes[iter.pos()].getChild()->setValuesOn(); - } -} - - -template -template -inline void -InternalNode::modifyValue(const Coord& xyz, const ModifyOp& op) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - // Need to create a child if the tile is inactive, - // in order to activate voxel (x, y, z). - const bool active = this->isValueMaskOn(n); - bool createChild = !active; - if (!createChild) { - // Need to create a child if applying the functor - // to the tile value produces a different value. - const ValueType& tileVal = mNodes[n].getValue(); - ValueType modifiedVal = tileVal; - op(modifiedVal); - createChild = !math::isExactlyEqual(tileVal, modifiedVal); - } - if (createChild) { - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) mNodes[n].getChild()->modifyValue(xyz, op); -} - -template -template -inline void -InternalNode::modifyValueAndCache(const Coord& xyz, const ModifyOp& op, - AccessorT& acc) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - // Need to create a child if the tile is inactive, - // in order to activate voxel (x, y, z). - const bool active = this->isValueMaskOn(n); - bool createChild = !active; - if (!createChild) { - // Need to create a child if applying the functor - // to the tile value produces a different value. - const ValueType& tileVal = mNodes[n].getValue(); - ValueType modifiedVal = tileVal; - op(modifiedVal); - createChild = !math::isExactlyEqual(tileVal, modifiedVal); - } - if (createChild) { - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, mNodes[n].getValue(), active)); - } - } - if (hasChild) { - ChildNodeType* child = mNodes[n].getChild(); - acc.insert(xyz, child); - child->modifyValueAndCache(xyz, op, acc); - } -} - - -template -template -inline void -InternalNode::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool tileState = this->isValueMaskOn(n); - const ValueType& tileVal = mNodes[n].getValue(); - bool modifiedState = !tileState; - ValueType modifiedVal = tileVal; - op(modifiedVal, modifiedState); - // Need to create a child if applying the functor to the tile - // produces a different value or active state. - if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) { - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState)); - } - } - if (hasChild) mNodes[n].getChild()->modifyValueAndActiveState(xyz, op); -} - -template -template -inline void -InternalNode::modifyValueAndActiveStateAndCache( - const Coord& xyz, const ModifyOp& op, AccessorT& acc) -{ - const Index n = InternalNode::coordToOffset(xyz); - bool hasChild = this->isChildMaskOn(n); - if (!hasChild) { - const bool tileState = this->isValueMaskOn(n); - const ValueType& tileVal = mNodes[n].getValue(); - bool modifiedState = !tileState; - ValueType modifiedVal = tileVal; - op(modifiedVal, modifiedState); - // Need to create a child if applying the functor to the tile - // produces a different value or active state. - if (modifiedState != tileState || !math::isExactlyEqual(modifiedVal, tileVal)) { - hasChild = true; - this->setChildNode(n, new ChildNodeType(xyz, tileVal, tileState)); - } - } - if (hasChild) { - ChildNodeType* child = mNodes[n].getChild(); - acc.insert(xyz, child); - child->modifyValueAndActiveStateAndCache(xyz, op, acc); - } -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::clip(const CoordBBox& clipBBox, const ValueType& background) -{ - CoordBBox nodeBBox = this->getNodeBoundingBox(); - if (!clipBBox.hasOverlap(nodeBBox)) { - // This node lies completely outside the clipping region. Fill it with background tiles. - this->fill(nodeBBox, background, /*active=*/false); - } else if (clipBBox.isInside(nodeBBox)) { - // This node lies completely inside the clipping region. Leave it intact. - return; - } - - // This node isn't completely contained inside the clipping region. - // Clip tiles and children, and replace any that lie outside the region - // with background tiles. - - for (Index pos = 0; pos < NUM_VALUES; ++pos) { - const Coord xyz = this->offsetToGlobalCoord(pos); // tile or child origin - CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds - if (!clipBBox.hasOverlap(tileBBox)) { - // This table entry lies completely outside the clipping region. - // Replace it with a background tile. - this->makeChildNodeEmpty(pos, background); - mValueMask.setOff(pos); - } else if (!clipBBox.isInside(tileBBox)) { - // This table entry does not lie completely inside the clipping region - // and must be clipped. - if (this->isChildMaskOn(pos)) { - mNodes[pos].getChild()->clip(clipBBox, background); - } else { - // Replace this tile with a background tile, then fill the clip region - // with the tile's original value. (This might create a child branch.) - tileBBox.intersect(clipBBox); - const ValueType val = mNodes[pos].getValue(); - const bool on = this->isValueMaskOn(pos); - mNodes[pos].setValue(background); - mValueMask.setOff(pos); - this->fill(tileBBox, val, on); - } - } else { - // This table entry lies completely inside the clipping region. Leave it intact. - } - } -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::fill(const CoordBBox& bbox, const ValueType& value, bool active) -{ - Coord xyz, tileMin, tileMax; - for (int x = bbox.min().x(); x <= bbox.max().x(); x = tileMax.x() + 1) { - xyz.setX(x); - for (int y = bbox.min().y(); y <= bbox.max().y(); y = tileMax.y() + 1) { - xyz.setY(y); - for (int z = bbox.min().z(); z <= bbox.max().z(); z = tileMax.z() + 1) { - xyz.setZ(z); - - // Get the bounds of the tile that contains voxel (x, y, z). - const Index n = this->coordToOffset(xyz); - tileMin = this->offsetToGlobalCoord(n); - tileMax = tileMin.offsetBy(ChildT::DIM - 1); - - if (xyz != tileMin || Coord::lessThan(bbox.max(), tileMax)) { - // If the box defined by (xyz, bbox.max()) doesn't completely enclose - // the tile to which xyz belongs, create a child node (or retrieve - // the existing one). - ChildT* child = NULL; - if (this->isChildMaskOff(n)) { - // Replace the tile with a newly-created child that is initialized - // with the tile's value and active state. - child = new ChildT(xyz, mNodes[n].getValue(), this->isValueMaskOn(n)); - this->setChildNode(n, child); - } else { - child = mNodes[n].getChild(); - } - - // Forward the fill request to the child. - if (child) { - child->fill(CoordBBox(xyz, Coord::minComponent(bbox.max(), tileMax)), - value, active); - } - - } else { - // If the box given by (xyz, bbox.max()) completely encloses - // the tile to which xyz belongs, create the tile (if it - // doesn't already exist) and give it the fill value. - this->makeChildNodeEmpty(n, value); - mValueMask.set(n, active); - } - } - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::copyToDense(const CoordBBox& bbox, DenseT& dense) const -{ - typedef typename DenseT::ValueType DenseValueType; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - for (Coord xyz = bbox.min(), max; xyz[0] <= bbox.max()[0]; xyz[0] = max[0] + 1) { - for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = max[1] + 1) { - for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = max[2] + 1) { - const Index n = this->coordToOffset(xyz); - // Get max coordinates of the child node that contains voxel xyz. - max = this->offsetToGlobalCoord(n).offsetBy(ChildT::DIM-1); - - // Get the bbox of the interection of bbox and the child node - CoordBBox sub(xyz, Coord::minComponent(bbox.max(), max)); - - if (this->isChildMaskOn(n)) {//is a child - mNodes[n].getChild()->copyToDense(sub, dense); - } else {//a tile value - const ValueType value = mNodes[n].getValue(); - sub.translate(-min); - DenseValueType* a0 = dense.data() + zStride*sub.min()[2]; - for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x -inline void -InternalNode::writeTopology(std::ostream& os, bool toHalf) const -{ - mChildMask.save(os); - mValueMask.save(os); - - { - // Copy all of this node's values into an array. - boost::shared_array values(new ValueType[NUM_VALUES]); - const ValueType zero = zeroVal(); - for (Index i = 0; i < NUM_VALUES; ++i) { - values[i] = (mChildMask.isOff(i) ? mNodes[i].getValue() : zero); - } - // Compress (optionally) and write out the contents of the array. - io::writeCompressedValues(os, values.get(), NUM_VALUES, mValueMask, mChildMask, toHalf); - } - // Write out the child nodes in order. - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - iter->writeTopology(os, toHalf); - } -} - - -template -inline void -InternalNode::readTopology(std::istream& is, bool fromHalf) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - const ValueType background = (!io::getGridBackgroundValuePtr(is) ? zeroVal() - : *static_cast(io::getGridBackgroundValuePtr(is))); -#endif - - mChildMask.load(is); - mValueMask.load(is); - - if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_INTERNALNODE_COMPRESSION) { - for (Index i = 0; i < NUM_VALUES; ++i) { - if (this->isChildMaskOn(i)) { - ChildNodeType* child = -#ifdef OPENVDB_2_ABI_COMPATIBLE - new ChildNodeType(offsetToGlobalCoord(i), zeroVal()); -#else - new ChildNodeType(PartialCreate(), offsetToGlobalCoord(i), background); -#endif - mNodes[i].setChild(child); - child->readTopology(is); - } else { - ValueType value; - is.read(reinterpret_cast(&value), sizeof(ValueType)); - mNodes[i].setValue(value); - } - } - } else { - const bool oldVersion = - (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION); - const Index numValues = (oldVersion ? mChildMask.countOff() : NUM_VALUES); - { - // Read in (and uncompress, if necessary) all of this node's values - // into a contiguous array. - boost::shared_array values(new ValueType[numValues]); - io::readCompressedValues(is, values.get(), numValues, mValueMask, fromHalf); - - // Copy values from the array into this node's table. - if (oldVersion) { - Index n = 0; - for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) { - mNodes[iter.pos()].setValue(values[n++]); - } - assert(n == numValues); - } else { - for (ValueAllIter iter = this->beginValueAll(); iter; ++iter) { - mNodes[iter.pos()].setValue(values[iter.pos()]); - } - } - } - // Read in all child nodes and insert them into the table at their proper locations. - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { -#ifdef OPENVDB_2_ABI_COMPATIBLE - ChildNodeType* child = new ChildNodeType(iter.getCoord(), zeroVal()); -#else - ChildNodeType* child = new ChildNodeType(PartialCreate(), iter.getCoord(), background); -#endif - mNodes[iter.pos()].setChild(child); - child->readTopology(is, fromHalf); - } - } -} - - -//////////////////////////////////////// - - -template -inline const typename ChildT::ValueType& -InternalNode::getFirstValue() const -{ - return (this->isChildMaskOn(0) ? mNodes[0].getChild()->getFirstValue() : mNodes[0].getValue()); -} - - -template -inline const typename ChildT::ValueType& -InternalNode::getLastValue() const -{ - const Index n = NUM_VALUES - 1; - return (this->isChildMaskOn(n) ? mNodes[n].getChild()->getLastValue() : mNodes[n].getValue()); -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::negate() -{ - for (Index i = 0; i < NUM_VALUES; ++i) { - if (this->isChildMaskOn(i)) { - mNodes[i].getChild()->negate(); - } else { - mNodes[i].setValue(math::negative(mNodes[i].getValue())); - } - } - -} - - -template -inline void -InternalNode::voxelizeActiveTiles() -{ - for (ValueOnIter iter = this->beginValueOn(); iter; ++iter) { - this->setChildNode(iter.pos(), new ChildNodeType(iter.getCoord(), iter.getValue(), true)); - } - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) iter->voxelizeActiveTiles(); -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::merge(InternalNode& other, - const ValueType& background, const ValueType& otherBackground) -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - - switch (Policy) { - - case MERGE_ACTIVE_STATES: - default: - { - for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mChildMask.isOn(n)) { - // Merge this node's child with the other node's child. - mNodes[n].getChild()->template merge(*iter, - background, otherBackground); - } else if (mValueMask.isOff(n)) { - // Replace this node's inactive tile with the other node's child - // and replace the other node's child with a tile of undefined value - // (which is okay since the other tree is assumed to be cannibalized - // in the process of merging). - ChildNodeType* child = other.mNodes[n].getChild(); - other.mChildMask.setOff(n); - child->resetBackground(otherBackground, background); - this->setChildNode(n, child); - } - } - - // Copy active tile values. - for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mValueMask.isOff(n)) { - // Replace this node's child or inactive tile with the other node's active tile. - this->makeChildNodeEmpty(n, iter.getValue()); - mValueMask.setOn(n); - } - } - break; - } - - case MERGE_NODES: - { - for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mChildMask.isOn(n)) { - // Merge this node's child with the other node's child. - mNodes[n].getChild()->template merge(*iter, background, otherBackground); - } else { - // Replace this node's tile (regardless of its active state) with - // the other node's child and replace the other node's child with - // a tile of undefined value (which is okay since the other tree - // is assumed to be cannibalized in the process of merging). - ChildNodeType* child = other.mNodes[n].getChild(); - other.mChildMask.setOff(n); - child->resetBackground(otherBackground, background); - this->setChildNode(n, child); - } - } - break; - } - - case MERGE_ACTIVE_STATES_AND_NODES: - { - // Transfer children from the other tree to this tree. - for (ChildOnIter iter = other.beginChildOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mChildMask.isOn(n)) { - // Merge this node's child with the other node's child. - mNodes[n].getChild()->template merge(*iter, background, otherBackground); - } else { - // Replace this node's tile with the other node's child, leaving the other - // node with an inactive tile of undefined value (which is okay since - // the other tree is assumed to be cannibalized in the process of merging). - ChildNodeType* child = other.mNodes[n].getChild(); - other.mChildMask.setOff(n); - child->resetBackground(otherBackground, background); - if (mValueMask.isOn(n)) { - // Merge the child with this node's active tile. - child->template merge(mNodes[n].getValue(), /*on=*/true); - mValueMask.setOff(n); - } - mChildMask.setOn(n); - mNodes[n].setChild(child); - } - } - - // Merge active tiles into this tree. - for (ValueOnCIter iter = other.cbeginValueOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mChildMask.isOn(n)) { - // Merge the other node's active tile into this node's child. - mNodes[n].getChild()->template merge(iter.getValue(), /*on=*/true); - } else if (mValueMask.isOff(n)) { - // Replace this node's inactive tile with the other node's active tile. - mNodes[n].setValue(iter.getValue()); - mValueMask.setOn(n); - } - } - break; - } - - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline void -InternalNode::merge(const ValueType& tileValue, bool tileActive) -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - - if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return; - - // For MERGE_ACTIVE_STATES_AND_NODES, inactive tiles in the other tree are ignored. - if (!tileActive) return; - - // Iterate over this node's children and inactive tiles. - for (ValueOffIter iter = this->beginValueOff(); iter; ++iter) { - const Index n = iter.pos(); - if (mChildMask.isOn(n)) { - // Merge the other node's active tile into this node's child. - mNodes[n].getChild()->template merge(tileValue, /*on=*/true); - } else { - // Replace this node's inactive tile with the other node's active tile. - iter.setValue(tileValue); - mValueMask.setOn(n); - } - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::topologyUnion(const InternalNode& other) -{ - typedef typename InternalNode::ChildOnCIter OtherChildIter; - typedef typename InternalNode::ValueOnCIter OtherValueIter; - - // Loop over other node's child nodes - for (OtherChildIter iter = other.cbeginChildOn(); iter; ++iter) { - const Index i = iter.pos(); - if (mChildMask.isOn(i)) {//this has a child node - mNodes[i].getChild()->topologyUnion(*iter); - } else {// this is a tile so replace it with a child branch with identical topology - ChildNodeType* child = new ChildNodeType(*iter, mNodes[i].getValue(), TopologyCopy()); - if (mValueMask.isOn(i)) { - mValueMask.isOff(i);//we're replacing the active tile with a child branch - child->setValuesOn();//activate all values since it was an active tile - } - mChildMask.setOn(i); - mNodes[i].setChild(child); - } - } - // Loop over other node's active tiles - for (OtherValueIter iter = other.cbeginValueOn(); iter; ++iter) { - const Index i = iter.pos(); - if (mChildMask.isOn(i)) { - mNodes[i].getChild()->setValuesOn(); - } else if (mValueMask.isOff(i)) { //inactive tile - mValueMask.setOn(i); - } - } -} - -template -template -inline void -InternalNode::topologyIntersection(const InternalNode& other, - const ValueType& background) -{ - // Loop over this node's child nodes - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - const Index i = iter.pos(); - if (other.mChildMask.isOn(i)) {//other also has a child node - iter->topologyIntersection(*(other.mNodes[i].getChild()), background); - } else if (other.mValueMask.isOff(i)) {//other is an inactive tile - delete mNodes[i].getChild();//convert child to an inactive tile - mNodes[i].setValue(background); - mChildMask.setOff(i); - mValueMask.setOff(i); - } - } - - // Loop over this node's active tiles - for (ValueOnCIter iter = this->cbeginValueOn(); iter; ++iter) { - const Index i = iter.pos(); - if (other.mChildMask.isOn(i)) {//other has a child node - ChildNodeType* child = new ChildNodeType(*(other.mNodes[i].getChild()), - *iter, TopologyCopy()); - this->setChildNode(i, child);//replace the active tile with a child branch - } else if (other.mValueMask.isOff(i)) {//other is an inactive tile - mValueMask.setOff(i);//convert active tile to an inactive tile - } - } -} - -template -template -inline void -InternalNode::topologyDifference(const InternalNode& other, - const ValueType& background) -{ - typedef typename InternalNode::ChildOnCIter OtherChildIter; - typedef typename InternalNode::ValueOnCIter OtherValueIter; - - // Loop over other node's child nodes - for (OtherChildIter iter = other.cbeginChildOn(); iter; ++iter) { - const Index i = iter.pos(); - if (mChildMask.isOn(i)) {//this has a child node - mNodes[i].getChild()->topologyDifference(*iter, background); - } else if (mValueMask.isOn(i)) {// this is an active tile - ChildNodeType* child = new ChildNodeType(iter.getCoord(), mNodes[i].getValue(), true); - child->topologyDifference(*iter, background); - this->setChildNode(i, child);//we're replacing the active tile with a child branch - } - } - - // Loop over other node's active tiles - for (OtherValueIter iter = other.cbeginValueOn(); iter; ++iter) { - const Index i = iter.pos(); - if (mChildMask.isOn(i)) {//this has a child node - delete mNodes[i].getChild();//convert child to an inactive tile - mNodes[i].setValue(background); - mChildMask.setOff(i); - mValueMask.setOff(i); - } else if (mValueMask.isOn(i)) {//this is an active tile - mValueMask.setOff(i);//convert active tile to an inactive tile - } - } -} - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::combine(InternalNode& other, CombineOp& op) -{ - const ValueType zero = zeroVal(); - - CombineArgs args; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (this->isChildMaskOff(i) && other.isChildMaskOff(i)) { - // Both this node and the other node have constant values (tiles). - // Combine the two values and store the result as this node's new tile value. - op(args.setARef(mNodes[i].getValue()) - .setAIsActive(isValueMaskOn(i)) - .setBRef(other.mNodes[i].getValue()) - .setBIsActive(other.isValueMaskOn(i))); - mNodes[i].setValue(args.result()); - mValueMask.set(i, args.resultIsActive()); - } else if (this->isChildMaskOn(i) && other.isChildMaskOff(i)) { - // Combine this node's child with the other node's constant value. - ChildNodeType* child = mNodes[i].getChild(); - assert(child); - if (child) { - child->combine(other.mNodes[i].getValue(), other.isValueMaskOn(i), op); - } - } else if (this->isChildMaskOff(i) && other.isChildMaskOn(i)) { - // Combine this node's constant value with the other node's child. - ChildNodeType* child = other.mNodes[i].getChild(); - assert(child); - if (child) { - // Combine this node's constant value with the other node's child, - // but use a new functor in which the A and B values are swapped, - // since the constant value is the A value, not the B value. - SwappedCombineOp swappedOp(op); - child->combine(mNodes[i].getValue(), isValueMaskOn(i), swappedOp); - - // Steal the other node's child. - other.mChildMask.setOff(i); - other.mNodes[i].setValue(zero); - this->setChildNode(i, child); - } - - } else /*if (isChildMaskOn(i) && other.isChildMaskOn(i))*/ { - // Combine this node's child with the other node's child. - ChildNodeType - *child = mNodes[i].getChild(), - *otherChild = other.mNodes[i].getChild(); - assert(child); - assert(otherChild); - if (child && otherChild) { - child->combine(*otherChild, op); - } - } - } -} - - -template -template -inline void -InternalNode::combine(const ValueType& value, bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (this->isChildMaskOff(i)) { - // Combine this node's constant value with the given constant value. - op(args.setARef(mNodes[i].getValue()) - .setAIsActive(isValueMaskOn(i)) - .setBRef(value) - .setBIsActive(valueIsActive)); - mNodes[i].setValue(args.result()); - mValueMask.set(i, args.resultIsActive()); - } else /*if (isChildMaskOn(i))*/ { - // Combine this node's child with the given constant value. - ChildNodeType* child = mNodes[i].getChild(); - assert(child); - if (child) child->combine(value, valueIsActive, op); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::combine2(const InternalNode& other0, const OtherNodeType& other1, - CombineOp& op) -{ - CombineArgs args; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (other0.isChildMaskOff(i) && other1.isChildMaskOff(i)) { - op(args.setARef(other0.mNodes[i].getValue()) - .setAIsActive(other0.isValueMaskOn(i)) - .setBRef(other1.mNodes[i].getValue()) - .setBIsActive(other1.isValueMaskOn(i))); - // Replace child i with a constant value. - this->makeChildNodeEmpty(i, args.result()); - mValueMask.set(i, args.resultIsActive()); - } else { - if (this->isChildMaskOff(i)) { - // Add a new child with the same coordinates, etc. as the other node's child. - const Coord& childOrigin = other0.isChildMaskOn(i) - ? other0.mNodes[i].getChild()->origin() - : other1.mNodes[i].getChild()->origin(); - this->setChildNode(i, new ChildNodeType(childOrigin, mNodes[i].getValue())); - } - - if (other0.isChildMaskOff(i)) { - // Combine node1's child with node0's constant value - // and write the result into child i. - mNodes[i].getChild()->combine2(other0.mNodes[i].getValue(), - *other1.mNodes[i].getChild(), other0.isValueMaskOn(i), op); - } else if (other1.isChildMaskOff(i)) { - // Combine node0's child with node1's constant value - // and write the result into child i. - mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(), - other1.mNodes[i].getValue(), other1.isValueMaskOn(i), op); - } else { - // Combine node0's child with node1's child - // and write the result into child i. - mNodes[i].getChild()->combine2(*other0.mNodes[i].getChild(), - *other1.mNodes[i].getChild(), op); - } - } - } -} - - -template -template -inline void -InternalNode::combine2(const ValueType& value, const OtherNodeType& other, - bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (other.isChildMaskOff(i)) { - op(args.setARef(value) - .setAIsActive(valueIsActive) - .setBRef(other.mNodes[i].getValue()) - .setBIsActive(other.isValueMaskOn(i))); - // Replace child i with a constant value. - this->makeChildNodeEmpty(i, args.result()); - mValueMask.set(i, args.resultIsActive()); - } else { - typename OtherNodeType::ChildNodeType* otherChild = other.mNodes[i].getChild(); - assert(otherChild); - if (this->isChildMaskOff(i)) { - // Add a new child with the same coordinates, etc. - // as the other node's child. - this->setChildNode(i, new ChildNodeType(*otherChild)); - } - // Combine the other node's child with a constant value - // and write the result into child i. - mNodes[i].getChild()->combine2(value, *otherChild, valueIsActive, op); - } - } -} - - -template -template -inline void -InternalNode::combine2(const InternalNode& other, const OtherValueType& value, - bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - - for (Index i = 0; i < NUM_VALUES; ++i) { - if (other.isChildMaskOff(i)) { - op(args.setARef(other.mNodes[i].getValue()) - .setAIsActive(other.isValueMaskOn(i)) - .setBRef(value) - .setBIsActive(valueIsActive)); - // Replace child i with a constant value. - this->makeChildNodeEmpty(i, args.result()); - mValueMask.set(i, args.resultIsActive()); - } else { - ChildNodeType* otherChild = other.mNodes[i].getChild(); - assert(otherChild); - if (this->isChildMaskOff(i)) { - // Add a new child with the same coordinates, etc. as the other node's child. - this->setChildNode(i, - new ChildNodeType(otherChild->origin(), mNodes[i].getValue())); - } - // Combine the other node's child with a constant value - // and write the result into child i. - mNodes[i].getChild()->combine2(*otherChild, value, valueIsActive, op); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::visitActiveBBox(BBoxOp& op) const -{ - for (ValueOnCIter i = this->cbeginValueOn(); i; ++i) { -#ifdef _MSC_VER - op.operator()(CoordBBox::createCube(i.getCoord(), ChildNodeType::DIM)); -#else - op.template operator()(CoordBBox::createCube(i.getCoord(), ChildNodeType::DIM)); -#endif - } - if (op.template descent()) { - for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) i->visitActiveBBox(op); - } else { - for (ChildOnCIter i = this->cbeginChildOn(); i; ++i) { -#ifdef _MSC_VER - op.operator()(i->getNodeBoundingBox()); -#else - op.template operator()(i->getNodeBoundingBox()); -#endif - } - } -} - - -template -template -inline void -InternalNode::visit(VisitorOp& op) -{ - doVisit(*this, op); -} - - -template -template -inline void -InternalNode::visit(VisitorOp& op) const -{ - doVisit(*this, op); -} - - -template -template -inline void -InternalNode::doVisit(NodeT& self, VisitorOp& op) -{ - typename NodeT::ValueType val; - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - if (op(iter)) continue; - if (typename ChildAllIterT::ChildNodeType* child = iter.probeChild(val)) { - child->visit(op); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::visit2Node(OtherNodeType& other, VisitorOp& op) -{ - doVisit2Node(*this, other, op); -} - - -template -template -inline void -InternalNode::visit2Node(OtherNodeType& other, VisitorOp& op) const -{ - doVisit2Node(*this, other, op); -} - - -template -template< - typename NodeT, - typename OtherNodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -InternalNode::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op) -{ - // Allow the two nodes to have different ValueTypes, but not different dimensions. - BOOST_STATIC_ASSERT(OtherNodeT::NUM_VALUES == NodeT::NUM_VALUES); - BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL); - - typename NodeT::ValueType val; - typename OtherNodeT::ValueType otherVal; - - ChildAllIterT iter = self.beginChildAll(); - OtherChildAllIterT otherIter = other.beginChildAll(); - - for ( ; iter && otherIter; ++iter, ++otherIter) - { - const size_t skipBranch = static_cast(op(iter, otherIter)); - - typename ChildAllIterT::ChildNodeType* child = - (skipBranch & 1U) ? NULL : iter.probeChild(val); - typename OtherChildAllIterT::ChildNodeType* otherChild = - (skipBranch & 2U) ? NULL : otherIter.probeChild(otherVal); - - if (child != NULL && otherChild != NULL) { - child->visit2Node(*otherChild, op); - } else if (child != NULL) { - child->visit2(otherIter, op); - } else if (otherChild != NULL) { - otherChild->visit2(iter, op, /*otherIsLHS=*/true); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -InternalNode::visit2(OtherChildAllIterType& otherIter, - VisitorOp& op, bool otherIsLHS) -{ - doVisit2( - *this, otherIter, op, otherIsLHS); -} - - -template -template -inline void -InternalNode::visit2(OtherChildAllIterType& otherIter, - VisitorOp& op, bool otherIsLHS) const -{ - doVisit2( - *this, otherIter, op, otherIsLHS); -} - - -template -template -inline void -InternalNode::doVisit2(NodeT& self, OtherChildAllIterT& otherIter, - VisitorOp& op, bool otherIsLHS) -{ - if (!otherIter) return; - - const size_t skipBitMask = (otherIsLHS ? 2U : 1U); - - typename NodeT::ValueType val; - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - const size_t skipBranch = static_cast( - otherIsLHS ? op(otherIter, iter) : op(iter, otherIter)); - - typename ChildAllIterT::ChildNodeType* child = - (skipBranch & skipBitMask) ? NULL : iter.probeChild(val); - - if (child != NULL) child->visit2(otherIter, op, otherIsLHS); - } -} - - -//////////////////////////////////////// - - -template -inline void -InternalNode::writeBuffers(std::ostream& os, bool toHalf) const -{ - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - iter->writeBuffers(os, toHalf); - } -} - - -template -inline void -InternalNode::readBuffers(std::istream& is, bool fromHalf) -{ - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - iter->readBuffers(is, fromHalf); - } -} - - -template -inline void -InternalNode::readBuffers(std::istream& is, - const CoordBBox& clipBBox, bool fromHalf) -{ - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - // Stream in the branch rooted at this child. - // (We can't skip over children that lie outside the clipping region, - // because buffers are serialized in depth-first order and need to be - // unserialized in the same order.) - iter->readBuffers(is, clipBBox, fromHalf); - } - - // Get this tree's background value. - ValueType background = zeroVal(); - if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) { - background = *static_cast(bgPtr); - } - this->clip(clipBBox, background); -} - - -//////////////////////////////////////// - - -template -void -InternalNode::getNodeLog2Dims(std::vector& dims) -{ - dims.push_back(Log2Dim); - ChildNodeType::getNodeLog2Dims(dims); -} - - -template -inline void -InternalNode::offsetToLocalCoord(Index n, Coord &xyz) -{ - assert(n<(1<<3*Log2Dim)); - xyz.setX(n >> 2*Log2Dim); - n &= ((1<<2*Log2Dim)-1); - xyz.setY(n >> Log2Dim); - xyz.setZ(n & ((1< -inline Index -InternalNode::coordToOffset(const Coord& xyz) -{ - return (((xyz[0] & (DIM-1u)) >> ChildNodeType::TOTAL) << 2*Log2Dim) - + (((xyz[1] & (DIM-1u)) >> ChildNodeType::TOTAL) << Log2Dim) - + ((xyz[2] & (DIM-1u)) >> ChildNodeType::TOTAL); -} - - -template -inline Coord -InternalNode::offsetToGlobalCoord(Index n) const -{ - Coord local; - this->offsetToLocalCoord(n, local); - local <<= ChildT::TOTAL; - return local + this->origin(); -} - -//////////////////////////////////////// - -template -template -inline void -InternalNode::getNodes(ArrayT& array) -{ - typedef typename ArrayT::value_type T; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - typedef typename boost::mpl::if_::type>, - const ChildT, ChildT>::type ArrayChildT; - for (ChildOnIter iter = this->beginChildOn(); iter; ++iter) { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.push_back(reinterpret_cast(mNodes[iter.pos()].getChild())); - } else { - iter->getNodes(array);//descent - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } -} - -template -template -inline void -InternalNode::getNodes(ArrayT& array) const -{ - typedef typename ArrayT::value_type T; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - BOOST_STATIC_ASSERT(boost::is_const::type>::value); - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.push_back(reinterpret_cast(mNodes[iter.pos()].getChild())); - } else { - iter->getNodes(array);//descent - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } -} - -//////////////////////////////////////// - - -template -inline void -InternalNode::resetBackground(const ValueType& oldBackground, - const ValueType& newBackground) -{ - if (math::isExactlyEqual(oldBackground, newBackground)) return; - for (Index i = 0; i < NUM_VALUES; ++i) { - if (this->isChildMaskOn(i)) { - mNodes[i].getChild()->resetBackground(oldBackground, newBackground); - } else if (this->isValueMaskOff(i)) { - if (math::isApproxEqual(mNodes[i].getValue(), oldBackground)) { - mNodes[i].setValue(newBackground); - } else if (math::isApproxEqual(mNodes[i].getValue(), math::negative(oldBackground))) { - mNodes[i].setValue(math::negative(newBackground)); - } - } - } -} - -template -template -inline bool -InternalNode::hasSameTopology( - const InternalNode* other) const -{ - if (Log2Dim != OtherLog2Dim || mChildMask != other->mChildMask || - mValueMask != other->mValueMask) return false; - for (ChildOnCIter iter = this->cbeginChildOn(); iter; ++iter) { - if (!iter->hasSameTopology(other->mNodes[iter.pos()].getChild())) return false; - } - return true; -} - - -template -inline void -InternalNode::resetChildNode(Index i, ChildNodeType* child) -{ - assert(child); - if (this->isChildMaskOn(i)) { - delete mNodes[i].getChild(); - } else { - mChildMask.setOn(i); - mValueMask.setOff(i); - } - mNodes[i].setChild(child); -} - -template -inline void -InternalNode::setChildNode(Index i, ChildNodeType* child) -{ - assert(child); - assert(mChildMask.isOff(i)); - mChildMask.setOn(i); - mValueMask.setOff(i); - mNodes[i].setChild(child); -} - - -template -inline ChildT* -InternalNode::unsetChildNode(Index i, const ValueType& value) -{ - if (this->isChildMaskOff(i)) { - mNodes[i].setValue(value); - return NULL; - } - ChildNodeType* child = mNodes[i].getChild(); - mChildMask.setOff(i); - mNodes[i].setValue(value); - return child; -} - - -template -inline void -InternalNode::makeChildNodeEmpty(Index n, const ValueType& value) -{ - delete this->unsetChildNode(n, value); -} - -template -inline ChildT* -InternalNode::getChildNode(Index n) -{ - assert(this->isChildMaskOn(n)); - return mNodes[n].getChild(); -} - - -template -inline const ChildT* -InternalNode::getChildNode(Index n) const -{ - assert(this->isChildMaskOn(n)); - return mNodes[n].getChild(); -} - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_INTERNALNODE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/Iterator.h b/openvdb_3_0_0_library/tree/Iterator.h deleted file mode 100755 index ca88ded..0000000 --- a/openvdb_3_0_0_library/tree/Iterator.h +++ /dev/null @@ -1,290 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Iterator.h -/// -/// @author Peter Cucka and Ken Museth - -#ifndef OPENVDB_TREE_ITERATOR_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_ITERATOR_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -/// @brief Base class for iterators over internal and leaf nodes -/// -/// This class is typically not instantiated directly, since it doesn't provide methods -/// to dereference the iterator. Those methods (@vdblink::tree::SparseIteratorBase::operator*() -/// operator*()@endlink, @vdblink::tree::SparseIteratorBase::setValue() setValue()@endlink, etc.) -/// are implemented in the @vdblink::tree::SparseIteratorBase sparse@endlink and -/// @vdblink::tree::DenseIteratorBase dense@endlink iterator subclasses. -template -class IteratorBase -{ -public: - IteratorBase(): mParentNode(NULL) {} - IteratorBase(const MaskIterT& iter, NodeT* parent): - mParentNode(parent), mMaskIter(iter) {} - - void operator=(const IteratorBase& other) - { - mParentNode = other.mParentNode; - mMaskIter = other.mMaskIter; - } - - bool operator==(const IteratorBase& other) const - { - return (mParentNode == other.mParentNode) && (mMaskIter == other.mMaskIter); - } - bool operator!=(const IteratorBase& other) const - { - return !(*this == other); - } - - /// Return a pointer to the node (if any) over which this iterator is iterating. - NodeT* getParentNode() const { return mParentNode; } - /// @brief Return a reference to the node over which this iterator is iterating. - /// @throw ValueError if there is no parent node. - NodeT& parent() const - { - if (!mParentNode) OPENVDB_THROW(ValueError, "iterator references a null node"); - return *mParentNode; - } - - /// Return this iterator's position as an index into the parent node's table. - Index offset() const { return mMaskIter.offset(); } - - /// Identical to offset - Index pos() const { return mMaskIter.offset(); } - - /// Return @c true if this iterator is not yet exhausted. - bool test() const { return mMaskIter.test(); } - /// Return @c true if this iterator is not yet exhausted. - operator bool() const { return this->test(); } - - /// Advance to the next item in the parent node's table. - bool next() { return mMaskIter.next(); } - /// Advance to the next item in the parent node's table. - void increment() { mMaskIter.increment(); } - /// Advance to the next item in the parent node's table. - IteratorBase& operator++() { this->increment(); return *this; } - /// Advance @a n items in the parent node's table. - void increment(Index n) { mMaskIter.increment(n); } - - /// @brief Return @c true if this iterator is pointing to an active value. - /// Return @c false if it is pointing to either an inactive value or a child node. - bool isValueOn() const { return parent().isValueMaskOn(this->pos()); } - /// @brief If this iterator is pointing to a value, set the value's active state. - /// Otherwise, do nothing. - void setValueOn(bool on = true) const { parent().setValueMask(this->pos(), on); } - /// @brief If this iterator is pointing to a value, mark the value as inactive. - /// @details If this iterator is pointing to a child node, then the current item - /// in the parent node's table is required to be inactive. In that case, - /// this method has no effect. - void setValueOff() const { parent().mValueMask.setOff(this->pos()); } - - /// Return the coordinates of the item to which this iterator is pointing. - Coord getCoord() const { return parent().offsetToGlobalCoord(this->pos()); } - /// Return in @a xyz the coordinates of the item to which this iterator is pointing. - void getCoord(Coord& xyz) const { xyz = this->getCoord(); } - -private: - /// @note This parent node pointer is mutable, because setValueOn() and - /// setValueOff(), though const, need to call non-const methods on the parent. - /// There is a distinction between a const iterator (e.g., const ValueOnIter), - /// which is an iterator that can't be incremented, and an iterator over - /// a const node (e.g., ValueOnCIter), which might be const or non-const itself - /// but can't call non-const methods like setValue() on the node. - mutable NodeT* mParentNode; - MaskIterT mMaskIter; -}; // class IteratorBase - - -//////////////////////////////////////// - - -/// @brief Base class for sparse iterators over internal and leaf nodes -template< - typename MaskIterT, // mask iterator type (OnIterator, OffIterator, etc.) - typename IterT, // SparseIteratorBase subclass (the "Curiously Recurring Template Pattern") - typename NodeT, // type of node over which to iterate - typename ItemT> // type of value to which this iterator points -struct SparseIteratorBase: public IteratorBase -{ - typedef NodeT NodeType; - typedef ItemT ValueType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::remove_const::type NonConstValueType; - static const bool IsSparseIterator = true, IsDenseIterator = false; - - SparseIteratorBase() {} - SparseIteratorBase(const MaskIterT& iter, NodeT* parent): - IteratorBase(iter, parent) {} - - /// @brief Return the item at the given index in the parent node's table. - /// @note All subclasses must implement this accessor. - ItemT& getItem(Index) const; - /// @brief Set the value of the item at the given index in the parent node's table. - /// @note All non-const iterator subclasses must implement this accessor. - void setItem(Index, const ItemT&) const; - - /// Return a reference to the item to which this iterator is pointing. - ItemT& operator*() const { return this->getValue(); } - /// Return a pointer to the item to which this iterator is pointing. - ItemT* operator->() const { return &(this->operator*()); } - - /// Return the item to which this iterator is pointing. - ItemT& getValue() const - { - return static_cast(this)->getItem(this->pos()); // static polymorphism - } - /// @brief Set the value of the item to which this iterator is pointing. - /// (Not valid for const iterators.) - void setValue(const ItemT& value) const - { - BOOST_STATIC_ASSERT(!boost::is_const::value); - static_cast(this)->setItem(this->pos(), value); // static polymorphism - } - /// @brief Apply a functor to the item to which this iterator is pointing. - /// (Not valid for const iterators.) - /// @param op a functor of the form void op(ValueType&) const that modifies - /// its argument in place - /// @see Tree::modifyValue() - template - void modifyValue(const ModifyOp& op) const - { - BOOST_STATIC_ASSERT(!boost::is_const::value); - static_cast(this)->modifyItem(this->pos(), op); // static polymorphism - } -}; // class SparseIteratorBase - - -//////////////////////////////////////// - - -/// @brief Base class for dense iterators over internal and leaf nodes -/// @note Dense iterators have no @c %operator*() or @c %operator->(), -/// because their return type would have to vary depending on whether -/// the iterator is pointing to a value or a child node. -template< - typename MaskIterT, // mask iterator type (typically a DenseIterator) - typename IterT, // DenseIteratorBase subclass (the "Curiously Recurring Template Pattern") - typename NodeT, // type of node over which to iterate - typename SetItemT, // type of set value (ChildNodeType, for non-leaf nodes) - typename UnsetItemT> // type of unset value (ValueType, usually) -struct DenseIteratorBase: public IteratorBase -{ - typedef NodeT NodeType; - typedef UnsetItemT ValueType; - typedef SetItemT ChildNodeType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::remove_const::type NonConstValueType; - typedef typename boost::remove_const::type NonConstChildNodeType; - static const bool IsSparseIterator = false, IsDenseIterator = true; - - DenseIteratorBase() {} - DenseIteratorBase(const MaskIterT& iter, NodeT* parent): - IteratorBase(iter, parent) {} - - /// @brief Return @c true if the item at the given index in the parent node's table - /// is a set value and return either the set value in @a child or the unset value - /// in @a value. - /// @note All subclasses must implement this accessor. - bool getItem(Index, SetItemT*& child, NonConstValueType& value) const; - /// @brief Set the value of the item at the given index in the parent node's table. - /// @note All non-const iterator subclasses must implement this accessor. - void setItem(Index, SetItemT*) const; - /// @brief "Unset" the value of the item at the given index in the parent node's table. - /// @note All non-const iterator subclasses must implement this accessor. - void unsetItem(Index, const UnsetItemT&) const; - - /// Return @c true if this iterator is pointing to a child node. - bool isChildNode() const { return this->parent().isChildMaskOn(this->pos()); } - - /// @brief If this iterator is pointing to a child node, return a pointer to the node. - /// Otherwise, return NULL and, in @a value, the value to which this iterator is pointing. - SetItemT* probeChild(NonConstValueType& value) const - { - SetItemT* child = NULL; - static_cast(this)->getItem(this->pos(), child, value); // static polymorphism - return child; - } - /// @brief If this iterator is pointing to a child node, return @c true and return - /// a pointer to the child node in @a child. Otherwise, return @c false and return - /// the value to which this iterator is pointing in @a value. - bool probeChild(SetItemT*& child, NonConstValueType& value) const - { - child = probeChild(value); - return (child != NULL); - } - - /// @brief Return @c true if this iterator is pointing to a value and return - /// the value in @a value. Otherwise, return @c false. - bool probeValue(NonConstValueType& value) const - { - SetItemT* child = NULL; - const bool isChild = static_cast(this)-> // static polymorphism - getItem(this->pos(), child, value); - return !isChild; - } - - /// @brief Replace with the given child node the item in the parent node's table - /// to which this iterator is pointing. - void setChild(SetItemT* child) const - { - static_cast(this)->setItem(this->pos(), child); // static polymorphism - } - - /// @brief Replace with the given value the item in the parent node's table - /// to which this iterator is pointing. - void setValue(const UnsetItemT& value) const - { - static_cast(this)->unsetItem(this->pos(), value); // static polymorphism - } -}; // struct DenseIteratorBase - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_ITERATOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/LeafManager.h b/openvdb_3_0_0_library/tree/LeafManager.h deleted file mode 100755 index 1f9f6e1..0000000 --- a/openvdb_3_0_0_library/tree/LeafManager.h +++ /dev/null @@ -1,670 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file LeafManager.h -/// -/// A LeafManager manages a linear array of pointers to a given tree's -/// leaf nodes, as well as optional auxiliary buffers (one or more per leaf) -/// that can be swapped with the leaf nodes' voxel data buffers. -/// The leaf array is useful for multithreaded computations over -/// leaf voxels in a tree with static topology but varying voxel values. -/// The auxiliary buffers are convenient for temporal integration. -/// Efficient methods are provided for multithreaded swapping and synching -/// (i.e., copying the contents) of these buffers. - -#ifndef OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include "TreeIterator.h" // for CopyConstness - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -namespace leafmgr { - -//@{ -/// Useful traits for Tree types -template struct TreeTraits { - static const bool IsConstTree = false; - typedef typename TreeT::LeafIter LeafIterType; -}; -template struct TreeTraits { - static const bool IsConstTree = true; - typedef typename TreeT::LeafCIter LeafIterType; -}; -//@} - -} // namespace leafmgr - - -/// This helper class implements LeafManager methods that need to be -/// specialized for const vs. non-const trees. -template -struct LeafManagerImpl -{ - typedef typename ManagerT::RangeType RangeT; - typedef typename ManagerT::LeafType LeafT; - typedef typename ManagerT::BufferType BufT; - - static inline void doSwapLeafBuffer(const RangeT& r, size_t auxBufferIdx, - LeafT** leafs, BufT* bufs, size_t bufsPerLeaf) - { - for (size_t n = r.begin(), m = r.end(), N = bufsPerLeaf; n != m; ++n) { - leafs[n]->swap(bufs[n * N + auxBufferIdx]); - } - } -}; - - -//////////////////////////////////////// - - -/// @brief This class manages a linear array of pointers to a given tree's -/// leaf nodes, as well as optional auxiliary buffers (one or more per leaf) -/// that can be swapped with the leaf nodes' voxel data buffers. -/// @details The leaf array is useful for multithreaded computations over -/// leaf voxels in a tree with static topology but varying voxel values. -/// The auxiliary buffers are convenient for temporal integration. -/// Efficient methods are provided for multithreaded swapping and sync'ing -/// (i.e., copying the contents) of these buffers. -/// -/// @note Buffer index 0 denotes a leaf node's internal voxel data buffer. -/// Any auxiliary buffers are indexed starting from one. -template -class LeafManager -{ -public: - typedef TreeT TreeType; - typedef typename TreeT::ValueType ValueType; - typedef typename TreeT::RootNodeType RootNodeType; - typedef typename TreeType::LeafNodeType NonConstLeafType; - typedef typename CopyConstness::Type LeafType; - typedef LeafType LeafNodeType; - typedef typename leafmgr::TreeTraits::LeafIterType LeafIterType; - typedef typename LeafType::Buffer NonConstBufferType; - typedef typename CopyConstness::Type BufferType; - typedef tbb::blocked_range RangeType;//leaf index range - static const Index DEPTH = 2;//root + leafs - - static const bool IsConstTree = leafmgr::TreeTraits::IsConstTree; - - class LeafRange - { - public: - class Iterator - { - public: - Iterator(const LeafRange& range, size_t pos): mRange(range), mPos(pos) - { - assert(this->isValid()); - } - Iterator& operator=(const Iterator& other) - { - mRange = other.mRange; mPos = other.mPos; return *this; - } - /// Advance to the next leaf node. - Iterator& operator++() { ++mPos; return *this; } - /// Return a reference to the leaf node to which this iterator is pointing. - LeafType& operator*() const { return mRange.mLeafManager.leaf(mPos); } - /// Return a pointer to the leaf node to which this iterator is pointing. - LeafType* operator->() const { return &(this->operator*()); } - /// @brief Return the nth buffer for the leaf node to which this iterator is pointing, - /// where n = @a bufferIdx and n = 0 corresponds to the leaf node's own buffer. - BufferType& buffer(size_t bufferIdx) - { - return mRange.mLeafManager.getBuffer(mPos, bufferIdx); - } - /// Return the index into the leaf array of the current leaf node. - size_t pos() const { return mPos; } - bool isValid() const { return mPos>=mRange.mBegin && mPos<=mRange.mEnd; } - /// Return @c true if this iterator is not yet exhausted. - bool test() const { return mPos < mRange.mEnd; } - /// Return @c true if this iterator is not yet exhausted. - operator bool() const { return this->test(); } - /// Return @c true if this iterator is exhausted. - bool empty() const { return !this->test(); } - bool operator!=(const Iterator& other) const - { - return (mPos != other.mPos) || (&mRange != &other.mRange); - } - bool operator==(const Iterator& other) const { return !(*this != other); } - const LeafRange& leafRange() const { return mRange; } - - private: - const LeafRange& mRange; - size_t mPos; - };// end Iterator - - LeafRange(size_t begin, size_t end, const LeafManager& leafManager, size_t grainSize=1): - mEnd(end), mBegin(begin), mGrainSize(grainSize), mLeafManager(leafManager) {} - - Iterator begin() const {return Iterator(*this, mBegin);} - - Iterator end() const {return Iterator(*this, mEnd);} - - size_t size() const { return mEnd - mBegin; } - - size_t grainsize() const { return mGrainSize; } - - const LeafManager& leafManager() const { return mLeafManager; } - - bool empty() const {return !(mBegin < mEnd);} - - bool is_divisible() const {return mGrainSize < this->size();} - - LeafRange(LeafRange& r, tbb::split): - mEnd(r.mEnd), mBegin(doSplit(r)), mGrainSize(r.mGrainSize), - mLeafManager(r.mLeafManager) {} - - private: - size_t mEnd, mBegin, mGrainSize; - const LeafManager& mLeafManager; - - static size_t doSplit(LeafRange& r) - { - assert(r.is_divisible()); - size_t middle = r.mBegin + (r.mEnd - r.mBegin) / 2u; - r.mEnd = middle; - return middle; - } - };// end of LeafRange - - /// @brief Constructor from a tree reference and an auxiliary buffer count - /// (default is no auxiliary buffers) - LeafManager(TreeType& tree, size_t auxBuffersPerLeaf=0, bool serial=false): - mTree(&tree), - mLeafCount(0), - mAuxBufferCount(0), - mAuxBuffersPerLeaf(auxBuffersPerLeaf), - mLeafs(NULL), - mAuxBuffers(NULL), - mTask(0), - mIsMaster(true) - { - this->rebuild(serial); - } - - /// Shallow copy constructor called by tbb::parallel_for() threads - /// - /// @note This should never get called directly - LeafManager(const LeafManager& other): - mTree(other.mTree), - mLeafCount(other.mLeafCount), - mAuxBufferCount(other.mAuxBufferCount), - mAuxBuffersPerLeaf(other.mAuxBuffersPerLeaf), - mLeafs(other.mLeafs), - mAuxBuffers(other.mAuxBuffers), - mTask(other.mTask), - mIsMaster(false) - { - } - - virtual ~LeafManager() - { - if (mIsMaster) { - delete [] mLeafs; - delete [] mAuxBuffers; - } - } - - /// @brief (Re)initialize by resizing (if necessary) and repopulating the leaf array - /// and by deleting existing auxiliary buffers and allocating new ones. - /// @details Call this method if the tree's topology, and therefore the number - /// of leaf nodes, changes. New auxiliary buffers are initialized with copies - /// of corresponding leaf node buffers. - void rebuild(bool serial=false) - { - this->initLeafArray(); - this->initAuxBuffers(serial); - } - //@{ - /// Repopulate the leaf array and delete and reallocate auxiliary buffers. - void rebuild(size_t auxBuffersPerLeaf, bool serial=false) - { - mAuxBuffersPerLeaf = auxBuffersPerLeaf; - this->rebuild(serial); - } - void rebuild(TreeType& tree, bool serial=false) - { - mTree = &tree; - this->rebuild(serial); - } - void rebuild(TreeType& tree, size_t auxBuffersPerLeaf, bool serial=false) - { - mTree = &tree; - mAuxBuffersPerLeaf = auxBuffersPerLeaf; - this->rebuild(serial); - } - //@} - /// @brief Change the number of auxiliary buffers. - /// @details If auxBuffersPerLeaf is 0, all existing auxiliary buffers are deleted. - /// New auxiliary buffers are initialized with copies of corresponding leaf node buffers. - /// This method does not rebuild the leaf array. - void rebuildAuxBuffers(size_t auxBuffersPerLeaf, bool serial=false) - { - mAuxBuffersPerLeaf = auxBuffersPerLeaf; - this->initAuxBuffers(serial); - } - /// @brief Remove the auxiliary buffers, but don't rebuild the leaf array. - void removeAuxBuffers() { this->rebuildAuxBuffers(0); } - - /// @brief Remove the auxiliary buffers and rebuild the leaf array. - void rebuildLeafArray() - { - this->removeAuxBuffers(); - this->initLeafArray(); - } - - /// Return the total number of allocated auxiliary buffers. - size_t auxBufferCount() const { return mAuxBufferCount; } - /// Return the number of auxiliary buffers per leaf node. - size_t auxBuffersPerLeaf() const { return mAuxBuffersPerLeaf; } - - /// Return the number of leaf nodes. - size_t leafCount() const { return mLeafCount; } - - /// Return a const reference to tree associated with this manager. - const TreeType& tree() const { return *mTree; } - - /// Return a reference to the tree associated with this manager. - TreeType& tree() { return *mTree; } - - /// Return a const reference to root node associated with this manager. - const RootNodeType& root() const { return mTree->root(); } - - /// Return a reference to the root node associated with this manager. - RootNodeType& root() { return mTree->root(); } - - /// Return @c true if the tree associated with this manager is immutable. - bool isConstTree() const { return this->IsConstTree; } - - /// @brief Return a pointer to the leaf node at index @a leafIdx in the array. - /// @note For performance reasons no range check is performed (other than an assertion)! - LeafType& leaf(size_t leafIdx) const { assert(leafIdx 0), - /// but it is not safe to modify the leaf buffer (@a bufferIdx = 0). - BufferType& getBuffer(size_t leafIdx, size_t bufferIdx) const - { - assert(leafIdx < mLeafCount); - assert(bufferIdx == 0 || bufferIdx - 1 < mAuxBuffersPerLeaf); - return bufferIdx == 0 ? mLeafs[leafIdx]->buffer() - : mAuxBuffers[leafIdx * mAuxBuffersPerLeaf + bufferIdx - 1]; - } - - /// @brief Return a @c tbb::blocked_range of leaf array indices. - /// - /// @note Consider using leafRange() instead, which provides access methods - /// to leaf nodes and buffers. - RangeType getRange(size_t grainsize = 1) const { return RangeType(0, mLeafCount, grainsize); } - - /// Return a TBB-compatible LeafRange. - LeafRange leafRange(size_t grainsize = 1) const - { - return LeafRange(0, mLeafCount, *this, grainsize); - } - - /// @brief Swap each leaf node's buffer with the nth corresponding auxiliary buffer, - /// where n = @a bufferIdx. - /// @return @c true if the swap was successful - /// @param bufferIdx index of the buffer that will be swapped with - /// the corresponding leaf node buffer - /// @param serial if false, swap buffers in parallel using multiple threads. - /// @note Recall that the indexing of auxiliary buffers is 1-based, since - /// buffer index 0 denotes the leaf node buffer. So buffer index 1 denotes - /// the first auxiliary buffer. - bool swapLeafBuffer(size_t bufferIdx, bool serial = false) - { - if (bufferIdx == 0 || bufferIdx > mAuxBuffersPerLeaf || this->isConstTree()) return false; - mTask = boost::bind(&LeafManager::doSwapLeafBuffer, _1, _2, bufferIdx - 1); - this->cook(serial ? 0 : 512); - return true;//success - } - /// @brief Swap any two buffers for each leaf node. - /// @note Recall that the indexing of auxiliary buffers is 1-based, since - /// buffer index 0 denotes the leaf node buffer. So buffer index 1 denotes - /// the first auxiliary buffer. - bool swapBuffer(size_t bufferIdx1, size_t bufferIdx2, bool serial = false) - { - const size_t b1 = std::min(bufferIdx1, bufferIdx2); - const size_t b2 = std::max(bufferIdx1, bufferIdx2); - if (b1 == b2 || b2 > mAuxBuffersPerLeaf) return false; - if (b1 == 0) { - if (this->isConstTree()) return false; - mTask = boost::bind(&LeafManager::doSwapLeafBuffer, _1, _2, b2-1); - } else { - mTask = boost::bind(&LeafManager::doSwapAuxBuffer, _1, _2, b1-1, b2-1); - } - this->cook(serial ? 0 : 512); - return true;//success - } - - /// @brief Sync up the specified auxiliary buffer with the corresponding leaf node buffer. - /// @return @c true if the sync was successful - /// @param bufferIdx index of the buffer that will contain a - /// copy of the corresponding leaf node buffer - /// @param serial if false, sync buffers in parallel using multiple threads. - /// @note Recall that the indexing of auxiliary buffers is 1-based, since - /// buffer index 0 denotes the leaf node buffer. So buffer index 1 denotes - /// the first auxiliary buffer. - bool syncAuxBuffer(size_t bufferIdx, bool serial = false) - { - if (bufferIdx == 0 || bufferIdx > mAuxBuffersPerLeaf) return false; - mTask = boost::bind(&LeafManager::doSyncAuxBuffer, _1, _2, bufferIdx - 1); - this->cook(serial ? 0 : 64); - return true;//success - } - - /// @brief Sync up all auxiliary buffers with their corresponding leaf node buffers. - /// @return true if the sync was successful - /// @param serial if false, sync buffers in parallel using multiple threads. - bool syncAllBuffers(bool serial = false) - { - switch (mAuxBuffersPerLeaf) { - case 0: return false;//nothing to do - case 1: mTask = boost::bind(&LeafManager::doSyncAllBuffers1, _1, _2); break; - case 2: mTask = boost::bind(&LeafManager::doSyncAllBuffers2, _1, _2); break; - default: mTask = boost::bind(&LeafManager::doSyncAllBuffersN, _1, _2); break; - } - this->cook(serial ? 0 : 64); - return true;//success - } - - /// @brief Threaded method that applies a user-supplied functor - /// to each leaf node in the LeafManager - /// - /// @param op user-supplied functor, see examples for interface details. - /// @param threaded optional toggle to disable threading, on by default. - /// @param grainSize optional parameter to specify the grainsize - /// for threading, one by default. - /// - /// @warning The functor object is deep-copied to create TBB tasks. - /// - /// @par Example: - /// @code - /// // Functor to offset a tree's voxel values with values from another tree. - /// template - /// struct OffsetOp - /// { - /// typedef tree::ValueAccessor Accessor; - /// - /// OffsetOp(const TreeType& tree): mRhsTreeAcc(tree) {} - /// - /// template - /// void operator()(LeafNodeType &lhsLeaf, size_t) const - /// { - /// const LeafNodeType * rhsLeaf = mRhsTreeAcc.probeConstLeaf(lhsLeaf.origin()); - /// if (rhsLeaf) { - /// typename LeafNodeType::ValueOnIter iter = lhsLeaf.beginValueOn(); - /// for (; iter; ++iter) { - /// iter.setValue(iter.getValue() + rhsLeaf->getValue(iter.pos())); - /// } - /// } - /// } - /// private: - /// Accessor mRhsTreeAcc; - /// }; - /// - /// // usage: - /// tree::LeafManager leafNodes(lhsTree); - /// leafNodes.foreach(OffsetOp(rhsTree)); - /// - /// // A functor that performs a min operation between different auxiliary buffers. - /// template - /// struct MinOp - /// { - /// typedef typename LeafManagerType::BufferType BufferType; - /// - /// MinOp(LeafManagerType& leafNodes): mLeafs(leafNodes) {} - /// - /// template - /// void operator()(LeafNodeType &leaf, size_t leafIndex) const - /// { - /// // get the first buffer - /// BufferType& buffer = mLeafs.getBuffer(leafIndex, 1); - /// - /// // min ... - /// } - /// private: - /// LeafManagerType& mLeafs; - /// }; - /// @endcode - template - void foreach(const LeafOp& op, bool threaded = true, size_t grainSize=1) - { - LeafTransformer transform(op); - transform.run(this->leafRange(grainSize), threaded); - } - - - template - void getNodes(ArrayT& array) - { - typedef typename ArrayT::value_type T; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - typedef typename boost::mpl::if_::type>, - const LeafType, LeafType>::type LeafT; - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.resize(mLeafCount); - for (size_t i=0; i(mLeafs[i]); - } else { - mTree->getNodes(array); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - template - void getNodes(ArrayT& array) const - { - typedef typename ArrayT::value_type T; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - BOOST_STATIC_ASSERT(boost::is_const::type>::value); - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.resize(mLeafCount); - for (size_t i=0; i(mLeafs[i]); - } else { - mTree->getNodes(array); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - //////////////////////////////////////////////////////////////////////////////////// - // All methods below are for internal use only and should never be called directly - - /// Used internally by tbb::parallel_for() - never call it directly! - void operator()(const RangeType& r) const - { - if (mTask) mTask(const_cast(this), r); - else OPENVDB_THROW(ValueError, "task is undefined"); - } - - - - private: - - // This a simple wrapper for a c-style array so it mimics the api - // of a std container, e.g. std::vector or std::deque, and can be - // passed to Tree::getNodes(). - struct MyArray { - typedef LeafType* value_type;//required by Tree::getNodes - value_type* ptr; - MyArray(value_type* array) : ptr(array) {} - void push_back(value_type leaf) { *ptr++ = leaf; }//required by Tree::getNodes - }; - - void initLeafArray() - { - const size_t leafCount = mTree->leafCount(); - if (leafCount != mLeafCount) { - delete [] mLeafs; - mLeafs = (leafCount == 0) ? NULL : new LeafType*[leafCount]; - mLeafCount = leafCount; - } - MyArray a(mLeafs); - mTree->getNodes(a); - } - - void initAuxBuffers(bool serial) - { - const size_t auxBufferCount = mLeafCount * mAuxBuffersPerLeaf; - if (auxBufferCount != mAuxBufferCount) { - delete [] mAuxBuffers; - mAuxBuffers = (auxBufferCount == 0) ? NULL : new NonConstBufferType[auxBufferCount]; - mAuxBufferCount = auxBufferCount; - } - this->syncAllBuffers(serial); - } - - void cook(size_t grainsize) - { - if (grainsize>0) { - tbb::parallel_for(this->getRange(grainsize), *this); - } else { - (*this)(this->getRange()); - } - } - - void doSwapLeafBuffer(const RangeType& r, size_t auxBufferIdx) - { - LeafManagerImpl::doSwapLeafBuffer( - r, auxBufferIdx, mLeafs, mAuxBuffers, mAuxBuffersPerLeaf); - } - - void doSwapAuxBuffer(const RangeType& r, size_t auxBufferIdx1, size_t auxBufferIdx2) - { - for (size_t N = mAuxBuffersPerLeaf, n = N*r.begin(), m = N*r.end(); n != m; n+=N) { - mAuxBuffers[n + auxBufferIdx1].swap(mAuxBuffers[n + auxBufferIdx2]); - } - } - - void doSyncAuxBuffer(const RangeType& r, size_t auxBufferIdx) - { - for (size_t n = r.begin(), m = r.end(), N = mAuxBuffersPerLeaf; n != m; ++n) { - mAuxBuffers[n*N + auxBufferIdx] = mLeafs[n]->buffer(); - } - } - - void doSyncAllBuffers1(const RangeType& r) - { - for (size_t n = r.begin(), m = r.end(); n != m; ++n) { - mAuxBuffers[n] = mLeafs[n]->buffer(); - } - } - - void doSyncAllBuffers2(const RangeType& r) - { - for (size_t n = r.begin(), m = r.end(); n != m; ++n) { - const BufferType& leafBuffer = mLeafs[n]->buffer(); - mAuxBuffers[2*n ] = leafBuffer; - mAuxBuffers[2*n+1] = leafBuffer; - } - } - - void doSyncAllBuffersN(const RangeType& r) - { - for (size_t n = r.begin(), m = r.end(), N = mAuxBuffersPerLeaf; n != m; ++n) { - const BufferType& leafBuffer = mLeafs[n]->buffer(); - for (size_t i=n*N, j=i+N; i!=j; ++i) mAuxBuffers[i] = leafBuffer; - } - } - - /// @brief Private member class that applies a user-defined - /// functor to all the leaf nodes. - template - struct LeafTransformer - { - LeafTransformer(const LeafOp& leafOp) : mLeafOp(leafOp) {} - void run(const LeafRange& range, bool threaded = true) - { - threaded ? tbb::parallel_for(range, *this) : (*this)(range); - } - void operator()(const LeafRange& range) const - { - for (typename LeafRange::Iterator it = range.begin(); it; ++it) mLeafOp(*it, it.pos()); - } - const LeafOp mLeafOp; - }; - - typedef typename boost::function FuncType; - - TreeType* mTree; - size_t mLeafCount, mAuxBufferCount, mAuxBuffersPerLeaf; - LeafType** mLeafs;//array of LeafNode pointers - NonConstBufferType* mAuxBuffers;//array of auxiliary buffers - FuncType mTask; - const bool mIsMaster; -};//end of LeafManager class - - -// Partial specializations of LeafManager methods for const trees -template -struct LeafManagerImpl > -{ - typedef LeafManager ManagerT; - typedef typename ManagerT::RangeType RangeT; - typedef typename ManagerT::LeafType LeafT; - typedef typename ManagerT::BufferType BufT; - - static inline void doSwapLeafBuffer(const RangeT&, size_t /*auxBufferIdx*/, - LeafT**, BufT*, size_t /*bufsPerLeaf*/) - { - // Buffers can't be swapped into const trees. - } -}; - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_LEAFMANAGER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/LeafNode.h b/openvdb_3_0_0_library/tree/LeafNode.h deleted file mode 100755 index dd31ff1..0000000 --- a/openvdb_3_0_0_library/tree/LeafNode.h +++ /dev/null @@ -1,2139 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED - -#include -#include // for std::swap -#include // for std::memcpy() -#include -#include -#include -#include -#include -#include -#include -#include -#include // for io::readData(), etc. -#include "Iterator.h" - - -class TestLeaf; -template class TestLeafIO; - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -template struct SameLeafConfig; // forward declaration - - -/// @brief Templated block class to hold specific data types and a fixed -/// number of values determined by Log2Dim. The actual coordinate -/// dimension of the block is 2^Log2Dim, i.e. Log2Dim=3 corresponds to -/// a LeafNode that spans a 8^3 block. -template -class LeafNode -{ -public: - typedef T ValueType; - typedef LeafNode LeafNodeType; - typedef boost::shared_ptr Ptr; - typedef util::NodeMask NodeMaskType; - - static const Index - LOG2DIM = Log2Dim, // needed by parent nodes - TOTAL = Log2Dim, // needed by parent nodes - DIM = 1 << TOTAL, // dimension along one coordinate direction - NUM_VALUES = 1 << 3 * Log2Dim, - NUM_VOXELS = NUM_VALUES, // total number of voxels represented by this node - SIZE = NUM_VALUES, - LEVEL = 0; // level 0 = leaf - - /// @brief ValueConverter::Type is the type of a LeafNode having the same - /// dimensions as this node but a different value type, T. - template - struct ValueConverter { - typedef LeafNode Type; - }; - - /// @brief SameConfiguration::value is @c true if and only if - /// OtherNodeType is the type of a LeafNode with the same dimensions as this node. - template - struct SameConfiguration { - static const bool value = SameLeafConfig::value; - }; - -#ifndef OPENVDB_2_ABI_COMPATIBLE - struct FileInfo - { - FileInfo(): bufpos(0) , maskpos(0) {} - std::streamoff bufpos; - std::streamoff maskpos; - io::MappedFile::Ptr mapping; - boost::shared_ptr meta; - }; -#endif - - /// @brief Array of fixed size @f$2^{3 \times {\rm Log2Dim}}@f$ that stores - /// the voxel values of a LeafNode - class Buffer - { - public: -#ifdef OPENVDB_2_ABI_COMPATIBLE - /// Default constructor - Buffer(): mData(new ValueType[SIZE]) {} - /// Construct a buffer populated with the specified value. - explicit Buffer(const ValueType& val): mData(new ValueType[SIZE]) { this->fill(val); } - /// Copy constructor - Buffer(const Buffer& other): mData(new ValueType[SIZE]) { *this = other; } - /// Destructor - ~Buffer() { delete[] mData; } - - /// Return @c true if this buffer's values have not yet been read from disk. - bool isOutOfCore() const { return false; } - /// Return @c true if memory for this buffer has not yet been allocated. - bool empty() const { return (mData == NULL); } - /// Allocate memory for this buffer if it has not already been allocated. - bool allocate() { if (mData == NULL) mData = new ValueType[SIZE]; return !this->empty(); } -#else - /// Default constructor - Buffer(): mData(new ValueType[SIZE]), mOutOfCore(0) {} - /// Construct a buffer populated with the specified value. - explicit Buffer(const ValueType& val): mData(new ValueType[SIZE]), mOutOfCore(0) - { - this->fill(val); - } - /// Copy constructor - Buffer(const Buffer& other): mData(NULL), mOutOfCore(other.mOutOfCore) - { - if (other.isOutOfCore()) { - mFileInfo = new FileInfo(*other.mFileInfo); - } else { - this->allocate(); - ValueType* target = mData; - const ValueType* source = other.mData; - Index n = SIZE; - while (n--) *target++ = *source++; - } - } - /// Construct a buffer but don't allocate memory for the full array of values. - Buffer(PartialCreate, const ValueType&): mData(NULL), mOutOfCore(0) {} - /// Destructor - ~Buffer() - { - if (this->isOutOfCore()) { - this->detachFromFile(); - } else { - this->deallocate(); - } - } - - /// Return @c true if this buffer's values have not yet been read from disk. - bool isOutOfCore() const { return bool(mOutOfCore); } - /// Return @c true if memory for this buffer has not yet been allocated. - bool empty() const { return !mData || this->isOutOfCore(); } - /// Allocate memory for this buffer if it has not already been allocated. - bool allocate() { if (mData == NULL) mData = new ValueType[SIZE]; return !this->empty(); } -#endif - - /// Populate this buffer with a constant value. - void fill(const ValueType& val) - { - this->detachFromFile(); - if (mData != NULL) { - ValueType* target = mData; - Index n = SIZE; - while (n--) *target++ = val; - } - } - - /// Return a const reference to the i'th element of this buffer. - const ValueType& getValue(Index i) const { return this->at(i); } - /// Return a const reference to the i'th element of this buffer. - const ValueType& operator[](Index i) const { return this->at(i); } - /// Set the i'th value of this buffer to the specified value. - void setValue(Index i, const ValueType& val) - { - assert(i < SIZE); -#ifdef OPENVDB_2_ABI_COMPATIBLE - mData[i] = val; -#else - this->loadValues(); - if (mData) mData[i] = val; -#endif - } - - /// Copy the other buffer's values into this buffer. - Buffer& operator=(const Buffer& other) - { - if (&other != this) { -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (this->isOutOfCore()) { - this->detachFromFile(); - } else { - if (other.isOutOfCore()) this->deallocate(); - } - if (other.isOutOfCore()) { - mOutOfCore = other.mOutOfCore; - mFileInfo = new FileInfo(*other.mFileInfo); - } else { -#endif - this->allocate(); - ValueType* target = mData; - const ValueType* source = other.mData; - Index n = SIZE; - while (n--) *target++ = *source++; -#ifndef OPENVDB_2_ABI_COMPATIBLE - } -#endif - } - return *this; - } - - /// @brief Return @c true if the contents of the other buffer - /// exactly equal the contents of this buffer. - bool operator==(const Buffer& other) const - { - this->loadValues(); - other.loadValues(); - const ValueType *target = mData, *source = other.mData; - if (!target && !source) return true; - if (!target || !source) return false; - Index n = SIZE; - while (n && math::isExactlyEqual(*target++, *source++)) --n; - return n == 0; - } - /// @brief Return @c true if the contents of the other buffer - /// are not exactly equal to the contents of this buffer. - bool operator!=(const Buffer& other) const { return !(other == *this); } - - /// Exchange this buffer's values with the other buffer's values. - void swap(Buffer& other) - { - std::swap(mData, other.mData); -#ifndef OPENVDB_2_ABI_COMPATIBLE - std::swap(mOutOfCore, other.mOutOfCore); -#endif - } - - /// Return the memory footprint of this buffer in bytes. - Index memUsage() const - { - size_t n = sizeof(*this); -#ifdef OPENVDB_2_ABI_COMPATIBLE - if (mData) n += SIZE * sizeof(ValueType); -#else - if (this->isOutOfCore()) n += sizeof(FileInfo); - else if (mData) n += SIZE * sizeof(ValueType); -#endif - return static_cast(n); - } - /// Return the number of values contained in this buffer. - static Index size() { return SIZE; } - - private: - /// If this buffer is empty, return zero, otherwise return the value at index @ i. - const ValueType& at(Index i) const - { - assert(i < SIZE); -#ifdef OPENVDB_2_ABI_COMPATIBLE - return mData[i]; -#else - this->loadValues(); - // We can't use the ternary operator here, otherwise Visual C++ returns - // a reference to a temporary. - if (mData) return mData[i]; else return sZero; -#endif - } - - /// @brief Return a non-const reference to the value at index @a i. - /// @details This method is private since it makes assumptions about the - /// buffer's memory layout. Buffers associated with custom leaf node types - /// (e.g., a bool buffer implemented as a bitmask) might not be able to - /// return non-const references to their values. - ValueType& operator[](Index i) { return const_cast(this->at(i)); } - - bool deallocate() - { - if (mData != NULL && !this->isOutOfCore()) { - delete[] mData; - mData = NULL; - return true; - } - return false; - } - -#ifdef OPENVDB_2_ABI_COMPATIBLE - void setOutOfCore(bool) {} - void loadValues() const {} - void doLoad() const {} - bool detachFromFile() { return false; } -#else - inline void setOutOfCore(bool b) { mOutOfCore = b; } - // To facilitate inlining in the common case in which the buffer is in-core, - // the loading logic is split into a separate function, doLoad(). - inline void loadValues() const { if (this->isOutOfCore()) this->doLoad(); } - inline void doLoad() const; - inline bool detachFromFile() - { - if (this->isOutOfCore()) { - delete mFileInfo; - mFileInfo = NULL; - this->setOutOfCore(false); - return true; - } - return false; - } -#endif - - friend class ::TestLeaf; - // Allow the parent LeafNode to access this buffer's data pointer. - friend class LeafNode; - -#ifdef OPENVDB_2_ABI_COMPATIBLE - ValueType* mData; -#else - union { - ValueType* mData; - FileInfo* mFileInfo; - }; - Index32 mOutOfCore; // currently interpreted as bool; extra bits reserved for future use - tbb::spin_mutex mMutex; // 1 byte - //int8_t mReserved[3]; // padding for alignment - - static const ValueType sZero; -#endif - }; // class Buffer - - - /// Default constructor - LeafNode(); - - /// @brief Constructor - /// @param coords the grid index coordinates of a voxel - /// @param value a value with which to fill the buffer - /// @param active the active state to which to initialize all voxels - explicit LeafNode(const Coord& coords, - const ValueType& value = zeroVal(), - bool active = false); - - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief "Partial creation" constructor used during file input - /// @param coords the grid index coordinates of a voxel - /// @param value a value with which to fill the buffer - /// @param active the active state to which to initialize all voxels - /// @details This constructor does not allocate memory for voxel values. - LeafNode(PartialCreate, - const Coord& coords, - const ValueType& value = zeroVal(), - bool active = false); -#endif - - /// Deep copy constructor - LeafNode(const LeafNode&); - - /// Value conversion copy constructor - template - explicit LeafNode(const LeafNode& other); - - /// Topology copy constructor - template - LeafNode(const LeafNode& other, - const ValueType& offValue, const ValueType& onValue, TopologyCopy); - - /// Topology copy constructor - template - LeafNode(const LeafNode& other, - const ValueType& background, TopologyCopy); - - /// Destructor. - ~LeafNode(); - - // - // Statistics - // - /// Return log2 of the dimension of this LeafNode, e.g. 3 if dimensions are 8^3 - static Index log2dim() { return Log2Dim; } - /// Return the number of voxels in each coordinate dimension. - static Index dim() { return DIM; } - /// Return the total number of voxels represented by this LeafNode - static Index size() { return SIZE; } - /// Return the total number of voxels represented by this LeafNode - static Index numValues() { return SIZE; } - /// Return the level of this node, which by definition is zero for LeafNodes - static Index getLevel() { return LEVEL; } - /// Append the Log2Dim of this LeafNode to the specified vector - static void getNodeLog2Dims(std::vector& dims) { dims.push_back(Log2Dim); } - /// Return the dimension of child nodes of this LeafNode, which is one for voxels. - static Index getChildDim() { return 1; } - /// Return the leaf count for this node, which is one. - static Index32 leafCount() { return 1; } - /// Return the non-leaf count for this node, which is zero. - static Index32 nonLeafCount() { return 0; } - - /// Return the number of voxels marked On. - Index64 onVoxelCount() const { return mValueMask.countOn(); } - /// Return the number of voxels marked Off. - Index64 offVoxelCount() const { return mValueMask.countOff(); } - Index64 onLeafVoxelCount() const { return onVoxelCount(); } - Index64 offLeafVoxelCount() const { return offVoxelCount(); } - static Index64 onTileCount() { return 0; } - static Index64 offTileCount() { return 0; } - /// Return @c true if this node has no active voxels. - bool isEmpty() const { return mValueMask.isOff(); } - /// Return @c true if this node contains only active voxels. - bool isDense() const { return mValueMask.isOn(); } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Return @c true if memory for this node's buffer has been allocated. - bool isAllocated() const { return !mBuffer.isOutOfCore() && !mBuffer.empty(); } - /// Allocate memory for this node's buffer if it has not already been allocated. - bool allocate() { return mBuffer.allocate(); } -#endif - - /// Return the memory in bytes occupied by this node. - Index64 memUsage() const; - - /// Expand the given bounding box so that it includes this leaf node's active voxels. - /// If visitVoxels is false this LeafNode will be approximated as dense, i.e. with all - /// voxels active. Else the individual active voxels are visited to produce a tight bbox. - void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const; - - /// @brief Return the bounding box of this node, i.e., the full index space - /// spanned by this leaf node. - CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); } - - /// Set the grid index coordinates of this node's local origin. - void setOrigin(const Coord& origin) { mOrigin = origin; } - //@{ - /// Return the grid index coordinates of this node's local origin. - const Coord& origin() const { return mOrigin; } - void getOrigin(Coord& origin) const { origin = mOrigin; } - void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); } - //@} - - /// Return the linear table offset of the given global or local coordinates. - static Index coordToOffset(const Coord& xyz); - /// @brief Return the local coordinates for a linear table offset, - /// where offset 0 has coordinates (0, 0, 0). - static Coord offsetToLocalCoord(Index n); - /// Return the global coordinates for a linear table offset. - Coord offsetToGlobalCoord(Index n) const; - - /// Return a string representation of this node. - std::string str() const; - - /// @brief Return @c true if the given node (which may have a different @c ValueType - /// than this node) has the same active value topology as this node. - template - bool hasSameTopology(const LeafNode* other) const; - - /// Check for buffer, state and origin equivalence. - bool operator==(const LeafNode& other) const; - bool operator!=(const LeafNode& other) const { return !(other == *this); } - -protected: - typedef typename NodeMaskType::OnIterator MaskOnIterator; - typedef typename NodeMaskType::OffIterator MaskOffIterator; - typedef typename NodeMaskType::DenseIterator MaskDenseIterator; - - // Type tags to disambiguate template instantiations - struct ValueOn {}; struct ValueOff {}; struct ValueAll {}; - struct ChildOn {}; struct ChildOff {}; struct ChildAll {}; - - template - struct ValueIter: - // Derives from SparseIteratorBase, but can also be used as a dense iterator, - // if MaskIterT is a dense mask iterator type. - public SparseIteratorBase< - MaskIterT, ValueIter, NodeT, ValueT> - { - typedef SparseIteratorBase BaseT; - - ValueIter() {} - ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {} - - ValueT& getItem(Index pos) const { return this->parent().getValue(pos); } - ValueT& getValue() const { return this->parent().getValue(this->pos()); } - - // Note: setItem() can't be called on const iterators. - void setItem(Index pos, const ValueT& value) const - { - this->parent().setValueOnly(pos, value); - } - // Note: setValue() can't be called on const iterators. - void setValue(const ValueT& value) const - { - this->parent().setValueOnly(this->pos(), value); - } - - // Note: modifyItem() can't be called on const iterators. - template - void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); } - // Note: modifyValue() can't be called on const iterators. - template - void modifyValue(const ModifyOp& op) const { this->parent().modifyValue(this->pos(), op); } - }; - - /// Leaf nodes have no children, so their child iterators have no get/set accessors. - template - struct ChildIter: - public SparseIteratorBase, NodeT, ValueType> - { - ChildIter() {} - ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase< - MaskIterT, ChildIter, NodeT, ValueType>(iter, parent) {} - }; - - template - struct DenseIter: public DenseIteratorBase< - MaskDenseIterator, DenseIter, NodeT, /*ChildT=*/void, ValueT> - { - typedef DenseIteratorBase BaseT; - typedef typename BaseT::NonConstValueType NonConstValueT; - - DenseIter() {} - DenseIter(const MaskDenseIterator& iter, NodeT* parent): BaseT(iter, parent) {} - - bool getItem(Index pos, void*& child, NonConstValueT& value) const - { - value = this->parent().getValue(pos); - child = NULL; - return false; // no child - } - - // Note: setItem() can't be called on const iterators. - //void setItem(Index pos, void* child) const {} - - // Note: unsetItem() can't be called on const iterators. - void unsetItem(Index pos, const ValueT& value) const - { - this->parent().setValueOnly(pos, value); - } - }; - -public: - typedef ValueIter ValueOnIter; - typedef ValueIter ValueOnCIter; - typedef ValueIter ValueOffIter; - typedef ValueIter ValueOffCIter; - typedef ValueIter ValueAllIter; - typedef ValueIter ValueAllCIter; - typedef ChildIter ChildOnIter; - typedef ChildIter ChildOnCIter; - typedef ChildIter ChildOffIter; - typedef ChildIter ChildOffCIter; - typedef DenseIter ChildAllIter; - typedef DenseIter ChildAllCIter; - - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); } - ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); } - ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); } - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); } - ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); } - ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); } - ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); } - ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); } - - ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); } - ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); } - ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); } - ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); } - ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); } - ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); } - ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); } - ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); } - ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); } - - // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators, - // because leaf nodes have no children. - ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); } - ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); } - ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); } - ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); } - ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); } - - ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); } - ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); } - ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); } - ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); } - ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); } - - // - // Buffer management - // - /// @brief Exchange this node's data buffer with the given data buffer - /// without changing the active states of the values. - void swap(Buffer& other) { mBuffer.swap(other); } - const Buffer& buffer() const { return mBuffer; } - Buffer& buffer() { return mBuffer; } - - // - // I/O methods - // - /// @brief Read in just the topology. - /// @param is the stream from which to read - /// @param fromHalf if true, floating-point input values are assumed to be 16-bit - void readTopology(std::istream& is, bool fromHalf = false); - /// @brief Write out just the topology. - /// @param os the stream to which to write - /// @param toHalf if true, output floating-point values as 16-bit half floats - void writeTopology(std::ostream& os, bool toHalf = false) const; - - /// @brief Read buffers from a stream. - /// @param is the stream from which to read - /// @param fromHalf if true, floating-point input values are assumed to be 16-bit - void readBuffers(std::istream& is, bool fromHalf = false); - /// @brief Read buffers that intersect the given bounding box. - /// @param is the stream from which to read - /// @param bbox an index-space bounding box - /// @param fromHalf if true, floating-point input values are assumed to be 16-bit - void readBuffers(std::istream& is, const CoordBBox& bbox, bool fromHalf = false); - /// @brief Write buffers to a stream. - /// @param os the stream to which to write - /// @param toHalf if true, output floating-point values as 16-bit half floats - void writeBuffers(std::ostream& os, bool toHalf = false) const; - - size_t streamingSize(bool toHalf = false) const; - - // - // Accessor methods - // - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const; - /// Return the value of the voxel at the given linear offset. - const ValueType& getValue(Index offset) const; - - /// @brief Return @c true if the voxel at the given coordinates is active. - /// @param xyz the coordinates of the voxel to be probed - /// @param[out] val the value of the voxel at the given coordinates - bool probeValue(const Coord& xyz, ValueType& val) const; - /// @brief Return @c true if the voxel at the given offset is active. - /// @param offset the linear offset of the voxel to be probed - /// @param[out] val the value of the voxel at the given coordinates - bool probeValue(Index offset, ValueType& val) const; - - /// Return the level (i.e., 0) at which leaf node values reside. - static Index getValueLevel(const Coord&) { return LEVEL; } - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on); - /// Set the active state of the voxel at the given offset but don't change its value. - void setActiveState(Index offset, bool on) { assert(offsetsetValueOn(LeafNode::coordToOffset(xyz), val); - } - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& val) { this->setValueOn(xyz, val); } - /// Set the value of the voxel at the given offset and mark the voxel as active. - void setValueOn(Index offset, const ValueType& val) { - mBuffer.setValue(offset, val); - mValueMask.setOn(offset); - } - - /// @brief Apply a functor to the value of the voxel at the given offset - /// and mark the voxel as active. - template - void modifyValue(Index offset, const ModifyOp& op) - { - ValueType val = mBuffer[offset]; - op(val); - mBuffer.setValue(offset, val); - mValueMask.setOn(offset); - } - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - this->modifyValue(this->coordToOffset(xyz), op); - } - - /// Apply a functor to the voxel at the given coordinates. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - const Index offset = this->coordToOffset(xyz); - bool state = mValueMask.isOn(offset); - ValueType val = mBuffer[offset]; - op(val, state); - mBuffer.setValue(offset, val); - mValueMask.set(offset, state); - } - - /// Mark all voxels as active but don't change their values. - void setValuesOn() { mValueMask.setOn(); } - /// Mark all voxels as inactive but don't change their values. - void setValuesOff() { mValueMask.setOff(); } - - /// Return @c true if the voxel at the given coordinates is active. - bool isValueOn(const Coord& xyz) const {return this->isValueOn(LeafNode::coordToOffset(xyz));} - /// Return @c true if the voxel at the given offset is active. - bool isValueOn(Index offset) const { return mValueMask.isOn(offset); } - - /// Return @c false since leaf nodes never contain tiles. - static bool hasActiveTiles() { return false; } - - /// Set all voxels that lie outside the given axis-aligned box to the background. - void clip(const CoordBBox&, const ValueType& background); - - /// Set all voxels within an axis-aligned box to the specified value and active state. - void fill(const CoordBBox& bbox, const ValueType&, bool active = true); - - /// Set all voxels to the specified value but don't change their active states. - void fill(const ValueType& value); - /// Set all voxels to the specified value and active state. - void fill(const ValueType& value, bool active); - - /// @brief Copy into a dense grid the values of the voxels that lie within - /// a given bounding box. - /// - /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - /// - /// @note @a bbox is assumed to be identical to or contained in the coordinate domains - /// of both the dense grid and this node, i.e., no bounds checking is performed. - /// @note Consider using tools::CopyToDense in tools/Dense.h - /// instead of calling this method directly. - template - void copyToDense(const CoordBBox& bbox, DenseT& dense) const; - - /// @brief Copy from a dense grid into this node the values of the voxels - /// that lie within a given bounding box. - /// @details Only values that are different (by more than the given tolerance) - /// from the background value will be active. Other values are inactive - /// and truncated to the background value. - /// - /// @param bbox inclusive bounding box of the voxels to be copied into this node - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - /// @param background background value of the tree that this node belongs to - /// @param tolerance tolerance within which a value equals the background value - /// - /// @note @a bbox is assumed to be identical to or contained in the coordinate domains - /// of both the dense grid and this node, i.e., no bounds checking is performed. - /// @note Consider using tools::CopyFromDense in tools/Dense.h - /// instead of calling this method directly. - template - void copyFromDense(const CoordBBox& bbox, const DenseT& dense, - const ValueType& background, const ValueType& tolerance); - - /// @brief Return the value of the voxel at the given coordinates. - /// @note Used internally by ValueAccessor. - template - const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const - { - return this->getValue(xyz); - } - - /// @brief Return @c true if the voxel at the given coordinates is active. - /// @note Used internally by ValueAccessor. - template - bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); } - - /// @brief Change the value of the voxel at the given coordinates and mark it as active. - /// @note Used internally by ValueAccessor. - template - void setValueAndCache(const Coord& xyz, const ValueType& val, AccessorT&) - { - this->setValueOn(xyz, val); - } - - /// @brief Change the value of the voxel at the given coordinates - /// but preserve its state. - /// @note Used internally by ValueAccessor. - template - void setValueOnlyAndCache(const Coord& xyz, const ValueType& val, AccessorT&) - { - this->setValueOnly(xyz, val); - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&) - { - this->modifyValue(xyz, op); - } - - /// Apply a functor to the voxel at the given coordinates. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&) - { - this->modifyValueAndActiveState(xyz, op); - } - - /// @brief Change the value of the voxel at the given coordinates and mark it as inactive. - /// @note Used internally by ValueAccessor. - template - void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&) - { - this->setValueOff(xyz, value); - } - - /// @brief Set the active state of the voxel at the given coordinates - /// without changing its value. - /// @note Used internally by ValueAccessor. - template - void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&) - { - this->setActiveState(xyz, on); - } - - /// @brief Return @c true if the voxel at the given coordinates is active - /// and return the voxel value in @a val. - /// @note Used internally by ValueAccessor. - template - bool probeValueAndCache(const Coord& xyz, ValueType& val, AccessorT&) const - { - return this->probeValue(xyz, val); - } - - /// @brief Return the value of the voxel at the given coordinates and return - /// its active state and level (i.e., 0) in @a state and @a level. - /// @note Used internally by ValueAccessor. - template - const ValueType& getValue(const Coord& xyz, bool& state, int& level, AccessorT&) const - { - const Index offset = this->coordToOffset(xyz); - state = mValueMask.isOn(offset); - level = LEVEL; - return mBuffer[offset]; - } - - /// @brief Return the LEVEL (=0) at which leaf node values reside. - /// @note Used internally by ValueAccessor (note last argument is a dummy). - template - static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; } - - /// @brief Return a const reference to the first value in the buffer. - /// @note Though it is potentially risky you can convert this - /// to a non-const pointer by means of const_case&. - const ValueType& getFirstValue() const { return mBuffer[0]; } - /// Return a const reference to the last value in the buffer. - const ValueType& getLastValue() const { return mBuffer[SIZE - 1]; } - - /// @brief Replace inactive occurrences of @a oldBackground with @a newBackground, - /// and inactive occurrences of @a -oldBackground with @a -newBackground. - void resetBackground(const ValueType& oldBackground, const ValueType& newBackground); - - void negate(); - - void voxelizeActiveTiles() {} - - template void merge(const LeafNode&); - template void merge(const ValueType& tileValue, bool tileActive); - template - void merge(const LeafNode& other, const ValueType& /*bg*/, const ValueType& /*otherBG*/); - - /// @brief Union this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active if either of the original voxels - /// were active. - /// - /// @note This operation modifies only active states, not values. - template - void topologyUnion(const LeafNode& other); - - /// @brief Intersect this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active only if both of the original voxels - /// were active. - /// - /// @details The last dummy argument is required to match the signature - /// for InternalNode::topologyIntersection. - /// - /// @note This operation modifies only active states, not - /// values. Also note that this operation can result in all voxels - /// being inactive so consider subsequnetly calling prune. - template - void topologyIntersection(const LeafNode& other, const ValueType&); - - /// @brief Difference this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active only if the original voxel is - /// active in this LeafNode and inactive in the other LeafNode. - /// - /// @details The last dummy argument is required to match the signature - /// for InternalNode::topologyDifference. - /// - /// @note This operation modifies only active states, not values. - /// Also, because it can deactivate all of this node's voxels, - /// consider subsequently calling prune. - template - void topologyDifference(const LeafNode& other, const ValueType&); - - template - void combine(const LeafNode& other, CombineOp& op); - template - void combine(const ValueType& value, bool valueIsActive, CombineOp& op); - - template - void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&); - template - void combine2(const ValueType&, const OtherNodeT& other, bool valueIsActive, CombineOp&); - template - void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&); - - /// @brief Calls the templated functor BBoxOp with bounding box - /// information. An additional level argument is provided to the - /// callback. - /// - /// @note The bounding boxes are guarenteed to be non-overlapping. - template void visitActiveBBox(BBoxOp&) const; - - template void visit(VisitorOp&); - template void visit(VisitorOp&) const; - - template - void visit2Node(OtherLeafNodeType& other, VisitorOp&); - template - void visit2Node(OtherLeafNodeType& other, VisitorOp&) const; - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false); - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const; - - //@{ - /// This function exists only to enable template instantiation. - void prune(const ValueType& /*tolerance*/ = zeroVal()) {} - void addLeaf(LeafNode*) {} - template - void addLeafAndCache(LeafNode*, AccessorT&) {} - template - NodeT* stealNode(const Coord&, const ValueType&, bool) { return NULL; } - template - NodeT* probeNode(const Coord&) { return NULL; } - template - const NodeT* probeConstNode(const Coord&) const { return NULL; } - template void getNodes(ArrayT&) const {} - //@} - - void addTile(Index level, const Coord&, const ValueType&, bool); - void addTile(Index offset, const ValueType&, bool); - template - void addTileAndCache(Index, const Coord&, const ValueType&, bool, AccessorT&); - - //@{ - /// @brief Return a pointer to this node. - LeafNode* touchLeaf(const Coord&) { return this; } - template - LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; } - template - NodeT* probeNodeAndCache(const Coord&, AccessorT&) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - LeafNode* probeLeaf(const Coord&) { return this; } - template - LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; } - //@} - //@{ - /// @brief Return a @const pointer to this node. - const LeafNode* probeConstLeaf(const Coord&) const { return this; } - template - const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; } - template - const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; } - const LeafNode* probeLeaf(const Coord&) const { return this; } - template - const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - //@} - - /// Return @c true if all of this node's values have the same active state - /// and are equal to within the given tolerance, and return the value in @a constValue - /// and the active state in @a state. - bool isConstant(ValueType& constValue, bool& state, - const ValueType& tolerance = zeroVal()) const; - /// Return @c true if all of this node's values are inactive. - bool isInactive() const { return mValueMask.isOff(); } - -protected: - friend class ::TestLeaf; - template friend class ::TestLeafIO; - - // During topology-only construction, access is needed - // to protected/private members of other template instances. - template friend class LeafNode; - - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - - // Allow iterators to call mask accessor methods (see below). - /// @todo Make mask accessors public? - friend class IteratorBase; - friend class IteratorBase; - friend class IteratorBase; - - // Mask accessors -public: - bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); } - bool isValueMaskOn() const { return mValueMask.isOn(); } - bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); } - bool isValueMaskOff() const { return mValueMask.isOff(); } - const NodeMaskType& getValueMask() const { return mValueMask; } - NodeMaskType& getValueMask() { return mValueMask; } - void setValueMask(const NodeMaskType& mask) { mValueMask = mask; } - bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children - bool isChildMaskOff(Index) const { return true; } - bool isChildMaskOff() const { return true; } -protected: - void setValueMask(Index n, bool on) { mValueMask.set(n, on); } - void setValueMaskOn(Index n) { mValueMask.setOn(n); } - void setValueMaskOff(Index n) { mValueMask.setOff(n); } - - /// Compute the origin of the leaf node that contains the voxel with the given coordinates. - static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); } - - template - static inline void doVisit(NodeT&, VisitorOp&); - - template - static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&); - - template - static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS); - -private: - /// Buffer containing the actual data values - Buffer mBuffer; - /// Bitmask that determines which voxels are active - NodeMaskType mValueMask; - /// Global grid index coordinates (x,y,z) of the local origin of this node - Coord mOrigin; -}; // end of LeafNode class - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -const T LeafNode::Buffer::sZero = zeroVal(); -#endif - - -//////////////////////////////////////// - - -//@{ -/// Helper metafunction used to implement LeafNode::SameConfiguration -/// (which, as an inner class, can't be independently specialized) -template -struct SameLeafConfig { static const bool value = false; }; - -template -struct SameLeafConfig > { static const bool value = true; }; -//@} - - -//////////////////////////////////////// - - -template -inline -LeafNode::LeafNode(): - mValueMask(),//default is off! - mOrigin(0, 0, 0) -{ -} - - -template -inline -LeafNode::LeafNode(const Coord& xyz, const ValueType& val, bool active): - mBuffer(val), - mValueMask(active), - mOrigin(xyz & (~(DIM - 1))) -{ -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -inline -LeafNode::LeafNode(PartialCreate, const Coord& xyz, const ValueType& val, bool active): - mBuffer(PartialCreate(), val), - mValueMask(active), - mOrigin(xyz & (~(DIM - 1))) -{ -} -#endif - - -template -inline -LeafNode::LeafNode(const LeafNode &other): - mBuffer(other.mBuffer), - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ -} - - -// Copy-construct from a leaf node with the same configuration but a different ValueType. -template -template -inline -LeafNode::LeafNode(const LeafNode& other): - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ - struct Local { - /// @todo Consider using a value conversion functor passed as an argument instead. - static inline ValueType convertValue(const OtherValueType& val) { return ValueType(val); } - }; - - for (Index i = 0; i < SIZE; ++i) { - mBuffer[i] = Local::convertValue(other.mBuffer[i]); - } -} - - -template -template -inline -LeafNode::LeafNode(const LeafNode& other, - const ValueType& background, TopologyCopy): - mBuffer(background), - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ -} - - -template -template -inline -LeafNode::LeafNode(const LeafNode& other, - const ValueType& offValue, const ValueType& onValue, TopologyCopy): - mValueMask(other.mValueMask), - mOrigin(other.mOrigin) -{ - for (Index i = 0; i < SIZE; ++i) { - mBuffer[i] = (mValueMask.isOn(i) ? onValue : offValue); - } -} - - -template -inline -LeafNode::~LeafNode() -{ -} - - -template -inline std::string -LeafNode::str() const -{ - std::ostringstream ostr; - ostr << "LeafNode @" << mOrigin << ": " << mBuffer; - return ostr.str(); -} - - -//////////////////////////////////////// - - -template -inline Index -LeafNode::coordToOffset(const Coord& xyz) -{ - assert ((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM); - return ((xyz[0] & (DIM-1u)) << 2*Log2Dim) - + ((xyz[1] & (DIM-1u)) << Log2Dim) - + (xyz[2] & (DIM-1u)); -} - -template -inline Coord -LeafNode::offsetToLocalCoord(Index n) -{ - assert(n<(1<< 3*Log2Dim)); - Coord xyz; - xyz.setX(n >> 2*Log2Dim); - n &= ((1<<2*Log2Dim)-1); - xyz.setY(n >> Log2Dim); - xyz.setZ(n & ((1< -inline Coord -LeafNode::offsetToGlobalCoord(Index n) const -{ - return (this->offsetToLocalCoord(n) + this->origin()); -} - - -//////////////////////////////////////// - - -template -inline const ValueT& -LeafNode::getValue(const Coord& xyz) const -{ - return this->getValue(LeafNode::coordToOffset(xyz)); -} - -template -inline const ValueT& -LeafNode::getValue(Index offset) const -{ - assert(offset < SIZE); - return mBuffer[offset]; -} - - -template -inline bool -LeafNode::probeValue(const Coord& xyz, ValueType& val) const -{ - return this->probeValue(LeafNode::coordToOffset(xyz), val); -} - -template -inline bool -LeafNode::probeValue(Index offset, ValueType& val) const -{ - assert(offset < SIZE); - val = mBuffer[offset]; - return mValueMask.isOn(offset); -} - - -template -inline void -LeafNode::setValueOff(const Coord& xyz, const ValueType& val) -{ - this->setValueOff(LeafNode::coordToOffset(xyz), val); -} - -template -inline void -LeafNode::setValueOff(Index offset, const ValueType& val) -{ - assert(offset < SIZE); - mBuffer.setValue(offset, val); - mValueMask.setOff(offset); -} - - -template -inline void -LeafNode::setActiveState(const Coord& xyz, bool on) -{ - mValueMask.set(this->coordToOffset(xyz), on); -} - - -template -inline void -LeafNode::setValueOnly(const Coord& xyz, const ValueType& val) -{ - this->setValueOnly(LeafNode::coordToOffset(xyz), val); -} - -template -inline void -LeafNode::setValueOnly(Index offset, const ValueType& val) -{ - assert(offset -inline void -LeafNode::clip(const CoordBBox& clipBBox, const T& background) -{ - CoordBBox nodeBBox = this->getNodeBoundingBox(); - if (!clipBBox.hasOverlap(nodeBBox)) { - // This node lies completely outside the clipping region. Fill it with the background. - this->fill(background, /*active=*/false); - } else if (clipBBox.isInside(nodeBBox)) { - // This node lies completely inside the clipping region. Leave it intact. - return; - } - - // This node isn't completely contained inside the clipping region. - // Set any voxels that lie outside the region to the background value. - - // Construct a boolean mask that is on inside the clipping region and off outside it. - NodeMaskType mask; - nodeBBox.intersect(clipBBox); - Coord xyz; - int &x = xyz.x(), &y = xyz.y(), &z = xyz.z(); - for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) { - for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) { - for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) { - mask.setOn(static_cast(this->coordToOffset(xyz))); - } - } - } - - // Set voxels that lie in the inactive region of the mask (i.e., outside - // the clipping region) to the background value. - for (MaskOffIterator maskIter = mask.beginOff(); maskIter; ++maskIter) { - this->setValueOff(maskIter.pos(), background); - } -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::fill(const CoordBBox& bbox, const ValueType& value, bool active) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - - for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) { - const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim; - for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) { - const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim); - for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) { - const Index offset = offsetXY + (z & (DIM-1u)); - mBuffer[offset] = value; - mValueMask.set(offset, active); - } - } - } -} - -template -inline void -LeafNode::fill(const ValueType& value) -{ - mBuffer.fill(value); -} - -template -inline void -LeafNode::fill(const ValueType& value, bool active) -{ - mBuffer.fill(value); - mValueMask.set(active); -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::copyToDense(const CoordBBox& bbox, DenseT& dense) const -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->isAllocated()) return; -#endif - - typedef typename DenseT::ValueType DenseValueType; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array - const T* s0 = &mBuffer[bbox.min()[2] & (DIM-1u)]; // source array - for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) { - DenseValueType* t1 = t0 + xStride * (x - min[0]); - const T* s1 = s0 + ((x & (DIM-1u)) << 2*Log2Dim); - for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) { - DenseValueType* t2 = t1 + yStride * (y - min[1]); - const T* s2 = s1 + ((y & (DIM-1u)) << Log2Dim); - for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) { - *t2 = DenseValueType(*s2++); - } - } - } -} - - -template -template -inline void -LeafNode::copyFromDense(const CoordBBox& bbox, const DenseT& dense, - const ValueType& background, const ValueType& tolerance) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - - typedef typename DenseT::ValueType DenseValueType; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - - const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source - const Int32 n0 = bbox.min()[2] & (DIM-1u); - for (Int32 x = bbox.min()[0], ex = bbox.max()[0]+1; x < ex; ++x) { - const DenseValueType* s1 = s0 + xStride * (x - min[0]); - const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM); - for (Int32 y = bbox.min()[1], ey = bbox.max()[1]+1; y < ey; ++y) { - const DenseValueType* s2 = s1 + yStride * (y - min[1]); - Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM); - for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) { - if (math::isApproxEqual(background, ValueType(*s2), tolerance)) { - mValueMask.setOff(n2); - mBuffer[n2] = background; - } else { - mValueMask.setOn(n2); - mBuffer[n2] = ValueType(*s2); - } - } - } - } -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::readTopology(std::istream& is, bool /*fromHalf*/) -{ - mValueMask.load(is); -} - - -template -inline void -LeafNode::writeTopology(std::ostream& os, bool /*toHalf*/) const -{ - mValueMask.save(os); -} - - -//////////////////////////////////////// - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -inline void -LeafNode::Buffer::doLoad() const -{ - if (!this->isOutOfCore()) return; - - Buffer* self = const_cast(this); - - // This lock will be contended at most once, after which this buffer - // will no longer be out-of-core. - tbb::spin_mutex::scoped_lock lock(self->mMutex); - if (!this->isOutOfCore()) return; - - boost::scoped_ptr info(self->mFileInfo); - assert(info.get() != NULL); - assert(info->mapping.get() != NULL); - assert(info->meta.get() != NULL); - - /// @todo For now, we have to clear the mData pointer in order for allocate() to take effect. - self->mData = NULL; - self->allocate(); - - boost::shared_ptr buf = info->mapping->createBuffer(); - std::istream is(buf.get()); - - io::setStreamMetadataPtr(is, info->meta, /*transfer=*/true); - - NodeMaskType mask; - is.seekg(info->maskpos); - mask.load(is); - - is.seekg(info->bufpos); - io::readCompressedValues(is, self->mData, SIZE, mask, io::getHalfFloat(is)); - - self->setOutOfCore(false); -} -#endif - - -//////////////////////////////////////// - - -template -inline void -LeafNode::readBuffers(std::istream& is, bool fromHalf) -{ - this->readBuffers(is, CoordBBox::inf(), fromHalf); -} - - -template -inline void -LeafNode::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - std::streamoff maskpos = is.tellg(); -#endif - - // Read in the value mask. - mValueMask.load(is); - - int8_t numBuffers = 1; - if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION) { - // Read in the origin. - is.read(reinterpret_cast(&mOrigin), sizeof(Coord::ValueType) * 3); - - // Read in the number of buffers, which should now always be one. - is.read(reinterpret_cast(&numBuffers), sizeof(int8_t)); - } - - CoordBBox nodeBBox = this->getNodeBoundingBox(); - if (!clipBBox.hasOverlap(nodeBBox)) { - // This node lies completely outside the clipping region. - // Read and discard its voxel values. - Buffer temp; - io::readCompressedValues(is, temp.mData, SIZE, mValueMask, fromHalf); - mValueMask.setOff(); - mBuffer.setOutOfCore(false); - } else { -#ifndef OPENVDB_2_ABI_COMPATIBLE - // If this node lies completely inside the clipping region and it is being read - // from a memory-mapped file, delay loading of its buffer until the buffer - // is actually accessed. (If this node requires clipping, its buffer - // must be accessed and therefore must be loaded.) - io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is); - const bool delayLoad = ((mappedFile.get() != NULL) && clipBBox.isInside(nodeBBox)); - - if (delayLoad) { - mBuffer.setOutOfCore(true); - mBuffer.mFileInfo = new FileInfo; - mBuffer.mFileInfo->bufpos = is.tellg(); - mBuffer.mFileInfo->mapping = mappedFile; - // Save the offset to the value mask, because the in-memory copy - // might change before the value buffer gets read. - mBuffer.mFileInfo->maskpos = maskpos; - - mBuffer.mFileInfo->meta = io::getStreamMetadataPtr(is); - - // Read and discard voxel values. - Buffer temp; - io::readCompressedValues(is, temp.mData, SIZE, mValueMask, fromHalf); - } else { -#endif - mBuffer.allocate(); - io::readCompressedValues(is, mBuffer.mData, SIZE, mValueMask, fromHalf); - mBuffer.setOutOfCore(false); - - // Get this tree's background value. - T background = zeroVal(); - if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) { - background = *static_cast(bgPtr); - } - this->clip(clipBBox, background); -#ifndef OPENVDB_2_ABI_COMPATIBLE - } -#endif - } - - if (numBuffers > 1) { - // Read in and discard auxiliary buffers that were created with earlier - // versions of the library. (Auxiliary buffers are not mask compressed.) - const bool zipped = io::getDataCompression(is) & io::COMPRESS_ZIP; - Buffer temp; - for (int i = 1; i < numBuffers; ++i) { - if (fromHalf) { - io::HalfReader::isReal, T>::read(is, temp.mData, SIZE, zipped); - } else { - io::readData(is, temp.mData, SIZE, zipped); - } - } - } -} - - -template -inline void -LeafNode::writeBuffers(std::ostream& os, bool toHalf) const -{ - // Write out the value mask. - mValueMask.save(os); - - mBuffer.loadValues(); - - io::writeCompressedValues(os, mBuffer.mData, SIZE, - mValueMask, /*childMask=*/NodeMaskType(), toHalf); -} - - -//////////////////////////////////////// - - -template -inline bool -LeafNode::operator==(const LeafNode& other) const -{ - return mOrigin == other.mOrigin && - mValueMask == other.mValueMask && - mBuffer == other.mBuffer; -} - - -template -inline Index64 -LeafNode::memUsage() const -{ - // Use sizeof(*this) to capture alignment-related padding - // (but note that sizeof(*this) includes sizeof(mBuffer)). - return sizeof(*this) + mBuffer.memUsage() - sizeof(mBuffer); -} - - -template -inline void -LeafNode::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const -{ - CoordBBox this_bbox = this->getNodeBoundingBox(); - if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox - if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values? - if (visitVoxels) {//use voxel granularity? - this_bbox.reset(); - for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos())); - this_bbox.translate(this->origin()); - } - bbox.expand(this_bbox); - } -} - - -template -template -inline bool -LeafNode::hasSameTopology(const LeafNode* other) const -{ - assert(other); - return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask()); -} - - -template -inline bool -LeafNode::isConstant(ValueType& constValue, - bool& state, const ValueType& tolerance) const -{ - state = mValueMask.isOn(); - - if (!(state || mValueMask.isOff())) return false; - - bool allEqual = true; - const T value = mBuffer[0]; - for (Index i = 1; allEqual && i < SIZE; ++i) { - /// @todo Alternatively, allEqual = !((maxVal - minVal) > (2 * tolerance)) - allEqual = math::isApproxEqual(mBuffer[i], value, tolerance); - } - if (allEqual) constValue = value; ///< @todo return average/median value? - return allEqual; -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::addTile(Index /*level*/, const Coord& xyz, const ValueType& val, bool active) -{ - this->addTile(this->coordToOffset(xyz), val, active); -} - -template -inline void -LeafNode::addTile(Index offset, const ValueType& val, bool active) -{ - assert(offset < SIZE); - setValueOnly(offset, val); - setActiveState(offset, active); -} - -template -template -inline void -LeafNode::addTileAndCache(Index level, const Coord& xyz, - const ValueType& val, bool active, AccessorT&) -{ - this->addTile(level, xyz, val, active); -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::resetBackground(const ValueType& oldBackground, - const ValueType& newBackground) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - - typename NodeMaskType::OffIterator iter; - // For all inactive values... - for (iter = this->mValueMask.beginOff(); iter; ++iter) { - ValueType &inactiveValue = mBuffer[iter.pos()]; - if (math::isApproxEqual(inactiveValue, oldBackground)) { - inactiveValue = newBackground; - } else if (math::isApproxEqual(inactiveValue, math::negative(oldBackground))) { - inactiveValue = math::negative(newBackground); - } - } -} - - -template -template -inline void -LeafNode::merge(const LeafNode& other) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (Policy == MERGE_NODES) return; - typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn(); - for (; iter; ++iter) { - const Index n = iter.pos(); - if (mValueMask.isOff(n)) { - mBuffer[n] = other.mBuffer[n]; - mValueMask.setOn(n); - } - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - -template -template -inline void -LeafNode::merge(const LeafNode& other, - const ValueType& /*bg*/, const ValueType& /*otherBG*/) -{ - this->template merge(other); -} - -template -template -inline void -LeafNode::merge(const ValueType& tileValue, bool tileActive) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return; - if (!tileActive) return; - // Replace all inactive values with the active tile value. - for (typename NodeMaskType::OffIterator iter = mValueMask.beginOff(); iter; ++iter) { - const Index n = iter.pos(); - mBuffer[n] = tileValue; - mValueMask.setOn(n); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline void -LeafNode::topologyUnion(const LeafNode& other) -{ - mValueMask |= other.getValueMask(); -} - -template -template -inline void -LeafNode::topologyIntersection(const LeafNode& other, - const ValueType&) -{ - mValueMask &= other.getValueMask(); -} - -template -template -inline void -LeafNode::topologyDifference(const LeafNode& other, - const ValueType&) -{ - mValueMask &= !other.getValueMask(); -} - -template -inline void -LeafNode::negate() -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - for (Index i = 0; i < SIZE; ++i) { - mBuffer[i] = -mBuffer[i]; - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::combine(const LeafNode& other, CombineOp& op) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - CombineArgs args; - for (Index i = 0; i < SIZE; ++i) { - op(args.setARef(mBuffer[i]) - .setAIsActive(mValueMask.isOn(i)) - .setBRef(other.mBuffer[i]) - .setBIsActive(other.mValueMask.isOn(i)) - .setResultRef(mBuffer[i])); - mValueMask.set(i, args.resultIsActive()); - } -} - - -template -template -inline void -LeafNode::combine(const ValueType& value, bool valueIsActive, CombineOp& op) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - CombineArgs args; - args.setBRef(value).setBIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - op(args.setARef(mBuffer[i]) - .setAIsActive(mValueMask.isOn(i)) - .setResultRef(mBuffer[i])); - mValueMask.set(i, args.resultIsActive()); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::combine2(const LeafNode& other, const OtherType& value, - bool valueIsActive, CombineOp& op) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - CombineArgs args; - args.setBRef(value).setBIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - op(args.setARef(other.mBuffer[i]) - .setAIsActive(other.mValueMask.isOn(i)) - .setResultRef(mBuffer[i])); - mValueMask.set(i, args.resultIsActive()); - } -} - - -template -template -inline void -LeafNode::combine2(const ValueType& value, const OtherNodeT& other, - bool valueIsActive, CombineOp& op) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - CombineArgs args; - args.setARef(value).setAIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - op(args.setBRef(other.mBuffer[i]) - .setBIsActive(other.mValueMask.isOn(i)) - .setResultRef(mBuffer[i])); - mValueMask.set(i, args.resultIsActive()); - } -} - - -template -template -inline void -LeafNode::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op) -{ -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (!this->allocate()) return; -#endif - CombineArgs args; - for (Index i = 0; i < SIZE; ++i) { - mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i)); - op(args.setARef(b0.mBuffer[i]) - .setAIsActive(b0.mValueMask.isOn(i)) - .setBRef(b1.mBuffer[i]) - .setBIsActive(b1.mValueMask.isOn(i)) - .setResultRef(mBuffer[i])); - mValueMask.set(i, args.resultIsActive()); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::visitActiveBBox(BBoxOp& op) const -{ - if (op.template descent()) { - for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) { -#ifdef _MSC_VER - op.operator()(CoordBBox::createCube(i.getCoord(), 1)); -#else - op.template operator()(CoordBBox::createCube(i.getCoord(), 1)); -#endif - } - } else { -#ifdef _MSC_VER - op.operator()(this->getNodeBoundingBox()); -#else - op.template operator()(this->getNodeBoundingBox()); -#endif - } -} - - -template -template -inline void -LeafNode::visit(VisitorOp& op) -{ - doVisit(*this, op); -} - - -template -template -inline void -LeafNode::visit(VisitorOp& op) const -{ - doVisit(*this, op); -} - - -template -template -inline void -LeafNode::doVisit(NodeT& self, VisitorOp& op) -{ - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(iter); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::visit2Node(OtherLeafNodeType& other, VisitorOp& op) -{ - doVisit2Node(*this, other, op); -} - - -template -template -inline void -LeafNode::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const -{ - doVisit2Node(*this, other, op); -} - - -template -template< - typename NodeT, - typename OtherNodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -LeafNode::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op) -{ - // Allow the two nodes to have different ValueTypes, but not different dimensions. - BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE); - BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL); - - ChildAllIterT iter = self.beginChildAll(); - OtherChildAllIterT otherIter = other.beginChildAll(); - - for ( ; iter && otherIter; ++iter, ++otherIter) { - op(iter, otherIter); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) -{ - doVisit2( - *this, otherIter, op, otherIsLHS); -} - - -template -template -inline void -LeafNode::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const -{ - doVisit2( - *this, otherIter, op, otherIsLHS); -} - - -template -template< - typename NodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -LeafNode::doVisit2(NodeT& self, OtherChildAllIterT& otherIter, - VisitorOp& op, bool otherIsLHS) -{ - if (!otherIter) return; - - if (otherIsLHS) { - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(otherIter, iter); - } - } else { - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(iter, otherIter); - } - } -} - - -//////////////////////////////////////// - - -template -inline std::ostream& -operator<<(std::ostream& os, const typename LeafNode::Buffer& buf) -{ - for (Index32 i = 0, N = buf.size(); i < N; ++i) os << buf.mData[i] << ", "; - return os; -} - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -//////////////////////////////////////// - - -// Specialization for LeafNodes of type bool -#include "LeafNodeBool.h" - -#endif // OPENVDB_TREE_LEAFNODE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/LeafNodeBool.h b/openvdb_3_0_0_library/tree/LeafNodeBool.h deleted file mode 100755 index eb7d545..0000000 --- a/openvdb_3_0_0_library/tree/LeafNodeBool.h +++ /dev/null @@ -1,1748 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include // for io::readData(), etc. -#include // for math::isZero() -#include -#include "LeafNode.h" -#include "Iterator.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -/// @brief LeafNode specialization for values of type bool that stores both -/// the active states and the values of (2^Log2Dim)^3 voxels as bit masks -template -class LeafNode -{ -public: - typedef LeafNode LeafNodeType; - typedef boost::shared_ptr Ptr; - typedef bool ValueType; - typedef util::NodeMask NodeMaskType; - - // These static declarations must be on separate lines to avoid VC9 compiler errors. - static const Index LOG2DIM = Log2Dim; // needed by parent nodes - static const Index TOTAL = Log2Dim; // needed by parent nodes - static const Index DIM = 1 << TOTAL; // dimension along one coordinate direction - static const Index NUM_VALUES = 1 << 3 * Log2Dim; - static const Index NUM_VOXELS = NUM_VALUES; // total number of voxels represented by this node - static const Index SIZE = NUM_VALUES; - static const Index LEVEL = 0; // level 0 = leaf - - /// @brief ValueConverter::Type is the type of a LeafNode having the same - /// dimensions as this node but a different value type, T. - template - struct ValueConverter { typedef LeafNode Type; }; - - /// @brief SameConfiguration::value is @c true if and only if - /// OtherNodeType is the type of a LeafNode with the same dimensions as this node. - template - struct SameConfiguration { - static const bool value = SameLeafConfig::value; - }; - - - class Buffer - { - public: - Buffer() {} - Buffer(bool on) : mData(on) {} - Buffer(const NodeMaskType& other): mData(other) {} - Buffer(const Buffer& other): mData(other.mData) {} - ~Buffer() {} - void fill(bool val) { mData.set(val); } - Buffer& operator=(const Buffer& b) { if (&b != this) { mData = b.mData; } return *this; } - - const bool& getValue(Index i) const - { - assert(i < SIZE); - // We can't use the ternary operator here, otherwise Visual C++ returns - // a reference to a temporary. - if (mData.isOn(i)) return LeafNode::sOn; else return LeafNode::sOff; - } - const bool& operator[](Index i) const { return this->getValue(i); } - - bool operator==(const Buffer& other) const { return mData == other.mData; } - bool operator!=(const Buffer& other) const { return mData != other.mData; } - - void setValue(Index i, bool val) { assert(i < SIZE); mData.set(i, val); } - - void swap(Buffer& other) { if (&other != this) std::swap(mData, other.mData); } - - Index memUsage() const { return mData.memUsage(); } - static Index size() { return SIZE; } - - private: - friend class ::TestLeaf; - // Allow the parent LeafNode to access this Buffer's bit mask. - friend class LeafNode; - - NodeMaskType mData; - }; // class Buffer - - - /// Default constructor - LeafNode(); - - /// Constructor - /// @param xyz the coordinates of a voxel that lies within the node - /// @param value the initial value for all of this node's voxels - /// @param active the active state to which to initialize all voxels - explicit LeafNode(const Coord& xyz, bool value = false, bool active = false); - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// "Partial creation" constructor used during file input - LeafNode(PartialCreate, const Coord& xyz, bool value = false, bool active = false); -#endif - - /// Deep copy constructor - LeafNode(const LeafNode&); - - /// Value conversion copy constructor - template - explicit LeafNode(const LeafNode& other); - - /// Topology copy constructor - template - LeafNode(const LeafNode& other, TopologyCopy); - - //@{ - /// @brief Topology copy constructor - /// @note This variant exists mainly to enable template instantiation. - template - LeafNode(const LeafNode& other, bool offValue, bool onValue, TopologyCopy); - template - LeafNode(const LeafNode& other, bool background, TopologyCopy); - //@} - - /// Destructor - ~LeafNode(); - - // - // Statistics - // - /// Return log2 of the size of the buffer storage. - static Index log2dim() { return Log2Dim; } - /// Return the number of voxels in each dimension. - static Index dim() { return DIM; } - static Index size() { return SIZE; } - static Index numValues() { return SIZE; } - static Index getLevel() { return LEVEL; } - static void getNodeLog2Dims(std::vector& dims) { dims.push_back(Log2Dim); } - static Index getChildDim() { return 1; } - - static Index32 leafCount() { return 1; } - static Index32 nonLeafCount() { return 0; } - - /// Return the number of active voxels. - Index64 onVoxelCount() const { return mValueMask.countOn(); } - /// Return the number of inactive voxels. - Index64 offVoxelCount() const { return mValueMask.countOff(); } - Index64 onLeafVoxelCount() const { return onVoxelCount(); } - Index64 offLeafVoxelCount() const { return offVoxelCount(); } - static Index64 onTileCount() { return 0; } - static Index64 offTileCount() { return 0; } - - /// Return @c true if this node has no active voxels. - bool isEmpty() const { return mValueMask.isOff(); } - /// Return @c true if this node only contains active voxels. - bool isDense() const { return mValueMask.isOn(); } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Return @c true if memory for this node's buffer has been allocated. - /// @details Currently, boolean leaf nodes don't support partial creation, - /// so this always returns @c true. - bool isAllocated() const { return true; } - /// @brief Allocate memory for this node's buffer if it has not already been allocated. - /// @details Currently, boolean leaf nodes don't support partial creation, - /// so this has no effect. - bool allocate() { return true; } -#endif - - /// Return the memory in bytes occupied by this node. - Index64 memUsage() const; - - /// Expand the given bounding box so that it includes this leaf node's active voxels. - /// If visitVoxels is false this LeafNode will be approximated as dense, i.e. with all - /// voxels active. Else the individual active voxels are visited to produce a tight bbox. - void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const; - - /// @brief Return the bounding box of this node, i.e., the full index space - /// spanned by this leaf node. - CoordBBox getNodeBoundingBox() const { return CoordBBox::createCube(mOrigin, DIM); } - - /// Set the grid index coordinates of this node's local origin. - void setOrigin(const Coord& origin) { mOrigin = origin; } - //@{ - /// Return the grid index coordinates of this node's local origin. - const Coord& origin() const { return mOrigin; } - void getOrigin(Coord& origin) const { origin = mOrigin; } - void getOrigin(Int32& x, Int32& y, Int32& z) const { mOrigin.asXYZ(x, y, z); } - //@} - - /// Return the linear table offset of the given global or local coordinates. - static Index coordToOffset(const Coord& xyz); - /// @brief Return the local coordinates for a linear table offset, - /// where offset 0 has coordinates (0, 0, 0). - static Coord offsetToLocalCoord(Index n); - /// Return the global coordinates for a linear table offset. - Coord offsetToGlobalCoord(Index n) const; - - /// Return a string representation of this node. - std::string str() const; - - /// @brief Return @c true if the given node (which may have a different @c ValueType - /// than this node) has the same active value topology as this node. - template - bool hasSameTopology(const LeafNode* other) const; - - /// Check for buffer equivalence by value. - bool operator==(const LeafNode&) const; - bool operator!=(const LeafNode&) const; - - // - // Buffer management - // - /// @brief Exchange this node's data buffer with the given data buffer - /// without changing the active states of the values. - void swap(Buffer& other) { mBuffer.swap(other); } - const Buffer& buffer() const { return mBuffer; } - Buffer& buffer() { return mBuffer; } - - // - // I/O methods - // - /// Read in just the topology. - void readTopology(std::istream&, bool fromHalf = false); - /// Write out just the topology. - void writeTopology(std::ostream&, bool toHalf = false) const; - - /// Read in the topology and the origin. - void readBuffers(std::istream&, bool fromHalf = false); - void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false); - /// Write out the topology and the origin. - void writeBuffers(std::ostream&, bool toHalf = false) const; - - // - // Accessor methods - // - /// Return the value of the voxel at the given coordinates. - const bool& getValue(const Coord& xyz) const; - /// Return the value of the voxel at the given offset. - const bool& getValue(Index offset) const; - - /// @brief Return @c true if the voxel at the given coordinates is active. - /// @param xyz the coordinates of the voxel to be probed - /// @param[out] val the value of the voxel at the given coordinates - bool probeValue(const Coord& xyz, bool& val) const; - - /// Return the level (0) at which leaf node values reside. - static Index getValueLevel(const Coord&) { return LEVEL; } - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on); - /// Set the active state of the voxel at the given offset but don't change its value. - void setActiveState(Index offset, bool on) { assert(offsetcoordToOffset(xyz)); } - /// Mark the voxel at the given offset as inactive but don't change its value. - void setValueOff(Index offset) { assert(offset < SIZE); mValueMask.setOff(offset); } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, bool val); - /// Set the value of the voxel at the given offset and mark the voxel as inactive. - void setValueOff(Index offset, bool val); - - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz) { mValueMask.setOn(this->coordToOffset(xyz)); } - /// Mark the voxel at the given offset as active but don't change its value. - void setValueOn(Index offset) { assert(offset < SIZE); mValueMask.setOn(offset); } - - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValueOn(const Coord& xyz, bool val); - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, bool val) { this->setValueOn(xyz, val); }; - /// Set the value of the voxel at the given offset and mark the voxel as active. - void setValueOn(Index offset, bool val); - - /// @brief Apply a functor to the value of the voxel at the given offset - /// and mark the voxel as active. - template - void modifyValue(Index offset, const ModifyOp& op); - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - template - void modifyValue(const Coord& xyz, const ModifyOp& op); - - /// Apply a functor to the voxel at the given coordinates. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op); - - /// Mark all voxels as active but don't change their values. - void setValuesOn() { mValueMask.setOn(); } - /// Mark all voxels as inactive but don't change their values. - void setValuesOff() { mValueMask.setOff(); } - - /// Return @c true if the voxel at the given coordinates is active. - bool isValueOn(const Coord& xyz) const { return mValueMask.isOn(this->coordToOffset(xyz)); } - /// Return @c true if the voxel at the given offset is active. - bool isValueOn(Index offset) const { assert(offset < SIZE); return mValueMask.isOn(offset); } - - /// Return @c false since leaf nodes never contain tiles. - static bool hasActiveTiles() { return false; } - - /// Set all voxels that lie outside the given axis-aligned box to the background. - void clip(const CoordBBox&, bool background); - - /// Set all voxels within an axis-aligned box to the specified value and active state. - void fill(const CoordBBox& bbox, bool value, bool active = true); - - /// Set all voxels to the specified value but don't change their active states. - void fill(const bool& value); - /// Set all voxels to the specified value and active state. - void fill(const bool& value, bool active); - - /// @brief Copy into a dense grid the values of the voxels that lie within - /// a given bounding box. - /// - /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - /// - /// @note @a bbox is assumed to be identical to or contained in the coordinate domains - /// of both the dense grid and this node, i.e., no bounds checking is performed. - /// @note Consider using tools::CopyToDense in tools/Dense.h - /// instead of calling this method directly. - template - void copyToDense(const CoordBBox& bbox, DenseT& dense) const; - - /// @brief Copy from a dense grid into this node the values of the voxels - /// that lie within a given bounding box. - /// @details Only values that are different (by more than the given tolerance) - /// from the background value will be active. Other values are inactive - /// and truncated to the background value. - /// - /// @param bbox inclusive bounding box of the voxels to be copied into this node - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - /// @param background background value of the tree that this node belongs to - /// @param tolerance tolerance within which a value equals the background value - /// - /// @note @a bbox is assumed to be identical to or contained in the coordinate domains - /// of both the dense grid and this node, i.e., no bounds checking is performed. - /// @note Consider using tools::CopyFromDense in tools/Dense.h - /// instead of calling this method directly. - template - void copyFromDense(const CoordBBox& bbox, const DenseT& dense, bool background, bool tolerance); - - /// @brief Return the value of the voxel at the given coordinates. - /// @note Used internally by ValueAccessor. - template - const bool& getValueAndCache(const Coord& xyz, AccessorT&) const {return this->getValue(xyz);} - - /// @brief Return @c true if the voxel at the given coordinates is active. - /// @note Used internally by ValueAccessor. - template - bool isValueOnAndCache(const Coord& xyz, AccessorT&) const { return this->isValueOn(xyz); } - - /// @brief Change the value of the voxel at the given coordinates and mark it as active. - /// @note Used internally by ValueAccessor. - template - void setValueAndCache(const Coord& xyz, bool val, AccessorT&) { this->setValueOn(xyz, val); } - - /// @brief Change the value of the voxel at the given coordinates - /// but preserve its state. - /// @note Used internally by ValueAccessor. - template - void setValueOnlyAndCache(const Coord& xyz, bool val, AccessorT&) {this->setValueOnly(xyz,val);} - - /// @brief Change the value of the voxel at the given coordinates and mark it as inactive. - /// @note Used internally by ValueAccessor. - template - void setValueOffAndCache(const Coord& xyz, bool value, AccessorT&) - { - this->setValueOff(xyz, value); - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&) - { - this->modifyValue(xyz, op); - } - - /// Apply a functor to the voxel at the given coordinates. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&) - { - this->modifyValueAndActiveState(xyz, op); - } - - /// @brief Set the active state of the voxel at the given coordinates - /// without changing its value. - /// @note Used internally by ValueAccessor. - template - void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&) - { - this->setActiveState(xyz, on); - } - - /// @brief Return @c true if the voxel at the given coordinates is active - /// and return the voxel value in @a val. - /// @note Used internally by ValueAccessor. - template - bool probeValueAndCache(const Coord& xyz, bool& val, AccessorT&) const - { - return this->probeValue(xyz, val); - } - - /// @brief Return the LEVEL (=0) at which leaf node values reside. - /// @note Used internally by ValueAccessor. - template - static Index getValueLevelAndCache(const Coord&, AccessorT&) { return LEVEL; } - - /// @brief Return a const reference to the first entry in the buffer. - /// @note Since it's actually a reference to a static data member - /// it should not be converted to a non-const pointer! - const bool& getFirstValue() const { if (mValueMask.isOn(0)) return sOn; else return sOff; } - /// @brief Return a const reference to the last entry in the buffer. - /// @note Since it's actually a reference to a static data member - /// it should not be converted to a non-const pointer! - const bool& getLastValue() const { if (mValueMask.isOn(SIZE-1)) return sOn; else return sOff; } - - /// Return @c true if all of this node's voxels have the same active state - /// and are equal to within the given tolerance, and return the value in - /// @a constValue and the active state in @a state. - bool isConstant(bool& constValue, bool& state, bool tolerance = 0) const; - /// Return @c true if all of this node's values are inactive. - bool isInactive() const { return mValueMask.isOff(); } - - void resetBackground(bool oldBackground, bool newBackground); - - void negate() { mBuffer.mData.toggle(); } - - template - void merge(const LeafNode& other, bool bg = false, bool otherBG = false); - template void merge(bool tileValue, bool tileActive); - - void voxelizeActiveTiles() {}; - - /// @brief Union this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active if either of the original voxels - /// were active. - /// - /// @note This operation modifies only active states, not values. - template - void topologyUnion(const LeafNode& other); - - /// @brief Intersect this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active only if both of the original voxels - /// were active. - /// - /// @details The last dummy argument is required to match the signature - /// for InternalNode::topologyIntersection. - /// - /// @note This operation modifies only active states, not - /// values. Also note that this operation can result in all voxels - /// being inactive so consider subsequnetly calling prune. - template - void topologyIntersection(const LeafNode& other, const bool&); - - /// @brief Difference this node's set of active values with the active values - /// of the other node, whose @c ValueType may be different. So a - /// resulting voxel will be active only if the original voxel is - /// active in this LeafNode and inactive in the other LeafNode. - /// - /// @details The last dummy argument is required to match the signature - /// for InternalNode::topologyDifference. - /// - /// @note This operation modifies only active states, not values. - /// Also, because it can deactivate all of this node's voxels, - /// consider subsequently calling prune. - template - void topologyDifference(const LeafNode& other, const bool&); - - template - void combine(const LeafNode& other, CombineOp& op); - template - void combine(bool, bool valueIsActive, CombineOp& op); - - template - void combine2(const LeafNode& other, const OtherType&, bool valueIsActive, CombineOp&); - template - void combine2(bool, const OtherNodeT& other, bool valueIsActive, CombineOp&); - template - void combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp&); - - /// @brief Calls the templated functor BBoxOp with bounding box information. - /// An additional level argument is provided to the callback. - /// - /// @note The bounding boxes are guarenteed to be non-overlapping. - template void visitActiveBBox(BBoxOp&) const; - - template void visit(VisitorOp&); - template void visit(VisitorOp&) const; - - template - void visit2Node(OtherLeafNodeType& other, VisitorOp&); - template - void visit2Node(OtherLeafNodeType& other, VisitorOp&) const; - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false); - template - void visit2(IterT& otherIter, VisitorOp&, bool otherIsLHS = false) const; - - //@{ - /// This function exists only to enable template instantiation. - void prune(const ValueType& /*tolerance*/ = zeroVal()) {} - void addLeaf(LeafNode*) {} - template - void addLeafAndCache(LeafNode*, AccessorT&) {} - template - NodeT* stealNode(const Coord&, const ValueType&, bool) { return NULL; } - template - NodeT* probeNode(const Coord&) { return NULL; } - template - const NodeT* probeConstNode(const Coord&) const { return NULL; } - template void getNodes(ArrayT&) const {} - //@} - - void addTile(Index level, const Coord&, bool val, bool active); - void addTile(Index offset, bool val, bool active); - template - void addTileAndCache(Index level, const Coord&, bool val, bool active, AccessorT&); - - //@{ - /// @brief Return a pointer to this node. - LeafNode* touchLeaf(const Coord&) { return this; } - template - LeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; } - LeafNode* probeLeaf(const Coord&) { return this; } - template - LeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; } - template - NodeT* probeNodeAndCache(const Coord&, AccessorT&) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - //@} - //@{ - /// @brief Return a @const pointer to this node. - const LeafNode* probeLeaf(const Coord&) const { return this; } - template - const LeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; } - const LeafNode* probeConstLeaf(const Coord&) const { return this; } - template - const LeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; } - template - const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (!(boost::is_same::value)) return NULL; - return reinterpret_cast(this); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - //@} - - // - // Iterators - // -protected: - typedef typename NodeMaskType::OnIterator MaskOnIter; - typedef typename NodeMaskType::OffIterator MaskOffIter; - typedef typename NodeMaskType::DenseIterator MaskDenseIter; - - template - struct ValueIter: - // Derives from SparseIteratorBase, but can also be used as a dense iterator, - // if MaskIterT is a dense mask iterator type. - public SparseIteratorBase, NodeT, ValueT> - { - typedef SparseIteratorBase BaseT; - - ValueIter() {} - ValueIter(const MaskIterT& iter, NodeT* parent): BaseT(iter, parent) {} - - const bool& getItem(Index pos) const { return this->parent().getValue(pos); } - const bool& getValue() const { return this->getItem(this->pos()); } - - // Note: setItem() can't be called on const iterators. - void setItem(Index pos, bool value) const { this->parent().setValueOnly(pos, value); } - // Note: setValue() can't be called on const iterators. - void setValue(bool value) const { this->setItem(this->pos(), value); } - - // Note: modifyItem() can't be called on const iterators. - template - void modifyItem(Index n, const ModifyOp& op) const { this->parent().modifyValue(n, op); } - // Note: modifyValue() can't be called on const iterators. - template - void modifyValue(const ModifyOp& op) const { this->modifyItem(this->pos(), op); } - }; - - /// Leaf nodes have no children, so their child iterators have no get/set accessors. - template - struct ChildIter: - public SparseIteratorBase, NodeT, bool> - { - ChildIter() {} - ChildIter(const MaskIterT& iter, NodeT* parent): SparseIteratorBase< - MaskIterT, ChildIter, NodeT, bool>(iter, parent) {} - }; - - template - struct DenseIter: public DenseIteratorBase< - MaskDenseIter, DenseIter, NodeT, /*ChildT=*/void, ValueT> - { - typedef DenseIteratorBase BaseT; - typedef typename BaseT::NonConstValueType NonConstValueT; - - DenseIter() {} - DenseIter(const MaskDenseIter& iter, NodeT* parent): BaseT(iter, parent) {} - - bool getItem(Index pos, void*& child, NonConstValueT& value) const - { - value = this->parent().getValue(pos); - child = NULL; - return false; // no child - } - - // Note: setItem() can't be called on const iterators. - //void setItem(Index pos, void* child) const {} - - // Note: unsetItem() can't be called on const iterators. - void unsetItem(Index pos, const ValueT& val) const {this->parent().setValueOnly(pos, val);} - }; - -public: - typedef ValueIter ValueOnIter; - typedef ValueIter ValueOnCIter; - typedef ValueIter ValueOffIter; - typedef ValueIter ValueOffCIter; - typedef ValueIter ValueAllIter; - typedef ValueIter ValueAllCIter; - typedef ChildIter ChildOnIter; - typedef ChildIter ChildOnCIter; - typedef ChildIter ChildOffIter; - typedef ChildIter ChildOffCIter; - typedef DenseIter ChildAllIter; - typedef DenseIter ChildAllCIter; - - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); } - ValueOnCIter beginValueOn() const { return ValueOnCIter(mValueMask.beginOn(), this); } - ValueOnIter beginValueOn() { return ValueOnIter(mValueMask.beginOn(), this); } - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); } - ValueOffCIter beginValueOff() const { return ValueOffCIter(mValueMask.beginOff(), this); } - ValueOffIter beginValueOff() { return ValueOffIter(mValueMask.beginOff(), this); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); } - ValueAllCIter beginValueAll() const { return ValueAllCIter(mValueMask.beginDense(), this); } - ValueAllIter beginValueAll() { return ValueAllIter(mValueMask.beginDense(), this); } - - ValueOnCIter cendValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); } - ValueOnCIter endValueOn() const { return ValueOnCIter(mValueMask.endOn(), this); } - ValueOnIter endValueOn() { return ValueOnIter(mValueMask.endOn(), this); } - ValueOffCIter cendValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); } - ValueOffCIter endValueOff() const { return ValueOffCIter(mValueMask.endOff(), this); } - ValueOffIter endValueOff() { return ValueOffIter(mValueMask.endOff(), this); } - ValueAllCIter cendValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); } - ValueAllCIter endValueAll() const { return ValueAllCIter(mValueMask.endDense(), this); } - ValueAllIter endValueAll() { return ValueAllIter(mValueMask.endDense(), this); } - - // Note that [c]beginChildOn() and [c]beginChildOff() actually return end iterators, - // because leaf nodes have no children. - ChildOnCIter cbeginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnCIter beginChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnIter beginChildOn() { return ChildOnIter(mValueMask.endOn(), this); } - ChildOffCIter cbeginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffCIter beginChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffIter beginChildOff() { return ChildOffIter(mValueMask.endOff(), this); } - ChildAllCIter cbeginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); } - ChildAllCIter beginChildAll() const { return ChildAllCIter(mValueMask.beginDense(), this); } - ChildAllIter beginChildAll() { return ChildAllIter(mValueMask.beginDense(), this); } - - ChildOnCIter cendChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnCIter endChildOn() const { return ChildOnCIter(mValueMask.endOn(), this); } - ChildOnIter endChildOn() { return ChildOnIter(mValueMask.endOn(), this); } - ChildOffCIter cendChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffCIter endChildOff() const { return ChildOffCIter(mValueMask.endOff(), this); } - ChildOffIter endChildOff() { return ChildOffIter(mValueMask.endOff(), this); } - ChildAllCIter cendChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); } - ChildAllCIter endChildAll() const { return ChildAllCIter(mValueMask.endDense(), this); } - ChildAllIter endChildAll() { return ChildAllIter(mValueMask.endDense(), this); } - - // - // Mask accessors - // - bool isValueMaskOn(Index n) const { return mValueMask.isOn(n); } - bool isValueMaskOn() const { return mValueMask.isOn(); } - bool isValueMaskOff(Index n) const { return mValueMask.isOff(n); } - bool isValueMaskOff() const { return mValueMask.isOff(); } - const NodeMaskType& getValueMask() const { return mValueMask; } - NodeMaskType& getValueMask() { return mValueMask; } - void setValueMask(const NodeMaskType& mask) { mValueMask = mask; } - bool isChildMaskOn(Index) const { return false; } // leaf nodes have no children - bool isChildMaskOff(Index) const { return true; } - bool isChildMaskOff() const { return true; } -protected: - void setValueMask(Index n, bool on) { mValueMask.set(n, on); } - void setValueMaskOn(Index n) { mValueMask.setOn(n); } - void setValueMaskOff(Index n) { mValueMask.setOff(n); } - - /// Compute the origin of the leaf node that contains the voxel with the given coordinates. - static void evalNodeOrigin(Coord& xyz) { xyz &= ~(DIM - 1); } - - template - static inline void doVisit(NodeT&, VisitorOp&); - - template - static inline void doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp&); - - template - static inline void doVisit2(NodeT& self, OtherChildAllIterT&, VisitorOp&, bool otherIsLHS); - - - /// Bitmask that determines which voxels are active - NodeMaskType mValueMask; - /// Bitmask representing the values of voxels - Buffer mBuffer; - /// Global grid index coordinates (x,y,z) of the local origin of this node - Coord mOrigin; - - // These static declarations must be on separate lines to avoid VC9 compiler errors. - static const bool sOn; - static const bool sOff; - -private: - /// @brief During topology-only construction, access is needed - /// to protected/private members of other template instances. - template friend class LeafNode; - - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - friend struct ValueIter; - - //@{ - /// Allow iterators to call mask accessor methods (see below). - /// @todo Make mask accessors public? - friend class IteratorBase; - friend class IteratorBase; - friend class IteratorBase; - //@} - -}; // class LeafNode - - -/// @internal For consistency with other nodes and with iterators, methods like -/// LeafNode::getValue() return a reference to a value. Since it's not possible -/// to return a reference to a bit in a node mask, we return a reference to one -/// of the following static values instead. -template const bool LeafNode::sOn = true; -template const bool LeafNode::sOff = false; - - -//////////////////////////////////////// - - -template -inline -LeafNode::LeafNode(): mOrigin(0, 0, 0) -{ -} - - -template -inline -LeafNode::LeafNode(const Coord& xyz, bool value, bool active): - mValueMask(active), - mBuffer(value), - mOrigin(xyz & (~(DIM - 1))) -{ -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -inline -LeafNode::LeafNode(PartialCreate, const Coord& xyz, bool value, bool active): - mValueMask(active), - mBuffer(value), - mOrigin(xyz & (~(DIM - 1))) -{ - /// @todo For now, this is identical to the non-PartialCreate constructor. - /// Consider modifying the Buffer class to allow it to be constructed - /// without allocating a bitmask. -} -#endif - - -template -inline -LeafNode::LeafNode(const LeafNode &other): - mValueMask(other.mValueMask), - mBuffer(other.mBuffer), - mOrigin(other.mOrigin) -{ -} - - -// Copy-construct from a leaf node with the same configuration but a different ValueType. -template -template -inline -LeafNode::LeafNode(const LeafNode& other): - mValueMask(other.getValueMask()), - mOrigin(other.origin()) -{ - struct Local { - /// @todo Consider using a value conversion functor passed as an argument instead. - static inline bool convertValue(const ValueT& val) { return bool(val); } - }; - - for (Index i = 0; i < SIZE; ++i) { - mBuffer.setValue(i, Local::convertValue(other.mBuffer[i])); - } -} - - -template -template -inline -LeafNode::LeafNode(const LeafNode& other, - bool background, TopologyCopy): - mValueMask(other.getValueMask()), - mBuffer(background), - mOrigin(other.origin()) -{ -} - - -template -template -inline -LeafNode::LeafNode(const LeafNode& other, TopologyCopy): - mValueMask(other.getValueMask()), - mBuffer(other.getValueMask()), // value = active state - mOrigin(other.origin()) -{ -} - - -template -template -inline -LeafNode::LeafNode(const LeafNode& other, - bool offValue, bool onValue, TopologyCopy): - mValueMask(other.getValueMask()), - mBuffer(other.getValueMask()), - mOrigin(other.origin()) -{ - if (offValue) { if (!onValue) mBuffer.mData.toggle(); else mBuffer.mData.setOn(); } -} - - -template -inline -LeafNode::~LeafNode() -{ -} - - -//////////////////////////////////////// - - -template -inline Index64 -LeafNode::memUsage() const -{ - return sizeof(mOrigin) + mValueMask.memUsage() + mBuffer.memUsage(); -} - - -template -inline void -LeafNode::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const -{ - CoordBBox this_bbox = this->getNodeBoundingBox(); - if (bbox.isInside(this_bbox)) return;//this LeafNode is already enclosed in the bbox - if (ValueOnCIter iter = this->cbeginValueOn()) {//any active values? - if (visitVoxels) {//use voxel granularity? - this_bbox.reset(); - for(; iter; ++iter) this_bbox.expand(this->offsetToLocalCoord(iter.pos())); - this_bbox.translate(this->origin()); - } - bbox.expand(this_bbox); - } -} - - -template -template -inline bool -LeafNode::hasSameTopology(const LeafNode* other) const -{ - assert(other); - return (Log2Dim == OtherLog2Dim && mValueMask == other->getValueMask()); -} - - -template -inline std::string -LeafNode::str() const -{ - std::ostringstream ostr; - ostr << "LeafNode @" << mOrigin << ": "; - for (Index32 n = 0; n < SIZE; ++n) ostr << (mValueMask.isOn(n) ? '#' : '.'); - return ostr.str(); -} - - -//////////////////////////////////////// - - -template -inline Index -LeafNode::coordToOffset(const Coord& xyz) -{ - assert ((xyz[0] & (DIM-1u)) < DIM && (xyz[1] & (DIM-1u)) < DIM && (xyz[2] & (DIM-1u)) < DIM); - return ((xyz[0] & (DIM-1u)) << 2*Log2Dim) - + ((xyz[1] & (DIM-1u)) << Log2Dim) - + (xyz[2] & (DIM-1u)); -} - - -template -inline Coord -LeafNode::offsetToLocalCoord(Index n) -{ - assert(n < (1 << 3*Log2Dim)); - Coord xyz; - xyz.setX(n >> 2*Log2Dim); - n &= ((1 << 2*Log2Dim) - 1); - xyz.setY(n >> Log2Dim); - xyz.setZ(n & ((1 << Log2Dim) - 1)); - return xyz; -} - - -template -inline Coord -LeafNode::offsetToGlobalCoord(Index n) const -{ - return (this->offsetToLocalCoord(n) + this->origin()); -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::readTopology(std::istream& is, bool /*fromHalf*/) -{ - mValueMask.load(is); -} - - -template -inline void -LeafNode::writeTopology(std::ostream& os, bool /*toHalf*/) const -{ - mValueMask.save(os); -} - - -template -inline void -LeafNode::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf) -{ - // Boolean LeafNodes don't currently implement lazy loading. - // Instead, load the full buffer, then clip it. - - this->readBuffers(is, fromHalf); - - // Get this tree's background value. - bool background = false; - if (const void* bgPtr = io::getGridBackgroundValuePtr(is)) { - background = *static_cast(bgPtr); - } - this->clip(clipBBox, background); -} - - -template -inline void -LeafNode::readBuffers(std::istream& is, bool /*fromHalf*/) -{ - // Read in the value mask. - mValueMask.load(is); - // Read in the origin. - is.read(reinterpret_cast(&mOrigin), sizeof(Coord::ValueType) * 3); - - if (io::getFormatVersion(is) >= OPENVDB_FILE_VERSION_BOOL_LEAF_OPTIMIZATION) { - // Read in the mask for the voxel values. - mBuffer.mData.load(is); - } else { - // Older files stored one or more bool arrays. - - // Read in the number of buffers, which should now always be one. - int8_t numBuffers = 0; - is.read(reinterpret_cast(&numBuffers), sizeof(int8_t)); - - // Read in the buffer. - // (Note: prior to the bool leaf optimization, buffers were always compressed.) - boost::shared_array buf(new bool[SIZE]); - io::readData(is, buf.get(), SIZE, /*isCompressed=*/true); - - // Transfer values to mBuffer. - mBuffer.mData.setOff(); - for (Index i = 0; i < SIZE; ++i) { - if (buf[i]) mBuffer.mData.setOn(i); - } - - if (numBuffers > 1) { - // Read in and discard auxiliary buffers that were created with - // earlier versions of the library. - for (int i = 1; i < numBuffers; ++i) { - io::readData(is, buf.get(), SIZE, /*isCompressed=*/true); - } - } - } -} - - -template -inline void -LeafNode::writeBuffers(std::ostream& os, bool /*toHalf*/) const -{ - // Write out the value mask. - mValueMask.save(os); - // Write out the origin. - os.write(reinterpret_cast(&mOrigin), sizeof(Coord::ValueType) * 3); - // Write out the voxel values. - mBuffer.mData.save(os); -} - - -//////////////////////////////////////// - - -template -inline bool -LeafNode::operator==(const LeafNode& other) const -{ - return (mValueMask == other.mValueMask && mBuffer.mData == other.mBuffer.mData); -} - - -template -inline bool -LeafNode::operator!=(const LeafNode& other) const -{ - return !(this->operator==(other)); -} - - -//////////////////////////////////////// - - -template -inline bool -LeafNode::isConstant(bool& constValue, bool& state, bool tolerance) const -{ - state = mValueMask.isOn(); - - if (!(state || mValueMask.isOff())) return false; - - // Note: if tolerance is true (i.e., 1), then all boolean values compare equal. - if (!tolerance && !(mBuffer.mData.isOn() || mBuffer.mData.isOff())) return false; - - state = mValueMask.isOn(); - constValue = mBuffer.mData.isOn(); - return true; -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::addTile(Index /*level*/, const Coord& xyz, bool val, bool active) -{ - this->addTile(this->coordToOffset(xyz), val, active); -} - -template -inline void -LeafNode::addTile(Index offset, bool val, bool active) -{ - assert(offset < SIZE); - setValueOnly(offset, val); - setActiveState(offset, active); -} - -template -template -inline void -LeafNode::addTileAndCache(Index level, const Coord& xyz, - bool val, bool active, AccessorT&) -{ - this->addTile(level, xyz, val, active); -} - - -//////////////////////////////////////// - - -template -inline const bool& -LeafNode::getValue(const Coord& xyz) const -{ - // This *CANNOT* use operator ? because Visual C++ - if (mBuffer.mData.isOn(this->coordToOffset(xyz))) return sOn; else return sOff; -} - - -template -inline const bool& -LeafNode::getValue(Index offset) const -{ - assert(offset < SIZE); - // This *CANNOT* use operator ? for Windows - if (mBuffer.mData.isOn(offset)) return sOn; else return sOff; -} - - -template -inline bool -LeafNode::probeValue(const Coord& xyz, bool& val) const -{ - const Index offset = this->coordToOffset(xyz); - val = mBuffer.mData.isOn(offset); - return mValueMask.isOn(offset); -} - - -template -inline void -LeafNode::setValueOn(const Coord& xyz, bool val) -{ - this->setValueOn(this->coordToOffset(xyz), val); -} - - -template -inline void -LeafNode::setValueOn(Index offset, bool val) -{ - assert(offset < SIZE); - mValueMask.setOn(offset); - mBuffer.mData.set(offset, val); -} - - -template -inline void -LeafNode::setValueOnly(const Coord& xyz, bool val) -{ - this->setValueOnly(this->coordToOffset(xyz), val); -} - - -template -inline void -LeafNode::setActiveState(const Coord& xyz, bool on) -{ - mValueMask.set(this->coordToOffset(xyz), on); -} - - -template -inline void -LeafNode::setValueOff(const Coord& xyz, bool val) -{ - this->setValueOff(this->coordToOffset(xyz), val); -} - - -template -inline void -LeafNode::setValueOff(Index offset, bool val) -{ - assert(offset < SIZE); - mValueMask.setOff(offset); - mBuffer.mData.set(offset, val); -} - - -template -template -inline void -LeafNode::modifyValue(Index offset, const ModifyOp& op) -{ - bool val = mBuffer.mData.isOn(offset); - op(val); - mBuffer.mData.set(offset, val); - mValueMask.setOn(offset); -} - - -template -template -inline void -LeafNode::modifyValue(const Coord& xyz, const ModifyOp& op) -{ - this->modifyValue(this->coordToOffset(xyz), op); -} - - -template -template -inline void -LeafNode::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) -{ - const Index offset = this->coordToOffset(xyz); - bool val = mBuffer.mData.isOn(offset), state = mValueMask.isOn(offset); - op(val, state); - mBuffer.mData.set(offset, val); - mValueMask.set(offset, state); -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::resetBackground(bool oldBackground, bool newBackground) -{ - if (newBackground != oldBackground) { - // Flip mBuffer's background bits and zero its foreground bits. - NodeMaskType bgMask = !(mBuffer.mData | mValueMask); - // Overwrite mBuffer's background bits, leaving its foreground bits intact. - mBuffer.mData = (mBuffer.mData & mValueMask) | bgMask; - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::merge(const LeafNode& other, bool /*bg*/, bool /*otherBG*/) -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (Policy == MERGE_NODES) return; - for (typename NodeMaskType::OnIterator iter = other.mValueMask.beginOn(); iter; ++iter) { - const Index n = iter.pos(); - if (mValueMask.isOff(n)) { - mBuffer.mData.set(n, other.mBuffer.mData.isOn(n)); - mValueMask.setOn(n); - } - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - -template -template -inline void -LeafNode::merge(bool tileValue, bool tileActive) -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (Policy != MERGE_ACTIVE_STATES_AND_NODES) return; - if (!tileActive) return; - // Replace all inactive values with the active tile value. - if (tileValue) mBuffer.mData |= !mValueMask; // -0=>1, +0=>0, -1=>1, +1=>1 (-,+ = off,on) - else mBuffer.mData &= mValueMask; // -0=>0, +0=>0, -1=>0, +1=>1 - mValueMask.setOn(); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::topologyUnion(const LeafNode& other) -{ - mValueMask |= other.getValueMask(); -} - - -template -template -inline void -LeafNode::topologyIntersection(const LeafNode& other, - const bool&) -{ - mValueMask &= other.getValueMask(); -} - - -template -template -inline void -LeafNode::topologyDifference(const LeafNode& other, - const bool&) -{ - mValueMask &= !other.getValueMask(); -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::clip(const CoordBBox& clipBBox, bool background) -{ - CoordBBox nodeBBox = this->getNodeBoundingBox(); - if (!clipBBox.hasOverlap(nodeBBox)) { - // This node lies completely outside the clipping region. Fill it with background tiles. - this->fill(nodeBBox, background, /*active=*/false); - } else if (clipBBox.isInside(nodeBBox)) { - // This node lies completely inside the clipping region. Leave it intact. - return; - } - - // This node isn't completely contained inside the clipping region. - // Set any voxels that lie outside the region to the background value. - - // Construct a boolean mask that is on inside the clipping region and off outside it. - NodeMaskType mask; - nodeBBox.intersect(clipBBox); - Coord xyz; - int &x = xyz.x(), &y = xyz.y(), &z = xyz.z(); - for (x = nodeBBox.min().x(); x <= nodeBBox.max().x(); ++x) { - for (y = nodeBBox.min().y(); y <= nodeBBox.max().y(); ++y) { - for (z = nodeBBox.min().z(); z <= nodeBBox.max().z(); ++z) { - mask.setOn(static_cast(this->coordToOffset(xyz))); - } - } - } - - // Set voxels that lie in the inactive region of the mask (i.e., outside - // the clipping region) to the background value. - for (MaskOffIter maskIter = mask.beginOff(); maskIter; ++maskIter) { - this->setValueOff(maskIter.pos(), background); - } -} - - -//////////////////////////////////////// - - -template -inline void -LeafNode::fill(const CoordBBox& bbox, bool value, bool active) -{ - for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) { - const Index offsetX = (x & (DIM-1u))<<2*Log2Dim; - for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) { - const Index offsetXY = offsetX + ((y & (DIM-1u))<< Log2Dim); - for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) { - const Index offset = offsetXY + (z & (DIM-1u)); - mValueMask.set(offset, active); - mBuffer.mData.set(offset, value); - } - } - } -} - -template -inline void -LeafNode::fill(const bool& value) -{ - mBuffer.fill(value); -} - -template -inline void -LeafNode::fill(const bool& value, bool active) -{ - mBuffer.fill(value); - mValueMask.set(active); -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::copyToDense(const CoordBBox& bbox, DenseT& dense) const -{ - typedef typename DenseT::ValueType DenseValueType; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - DenseValueType* t0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // target array - const Int32 n0 = bbox.min()[2] & (DIM-1u); - for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) { - DenseValueType* t1 = t0 + xStride * (x - min[0]); - const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM); - for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) { - DenseValueType* t2 = t1 + yStride * (y - min[1]); - Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM); - for (Int32 z = bbox.min()[2], ez = bbox.max()[2] + 1; z < ez; ++z, t2 += zStride) { - *t2 = DenseValueType(mBuffer.mData.isOn(n2++)); - } - } - } -} - - -template -template -inline void -LeafNode::copyFromDense(const CoordBBox& bbox, const DenseT& dense, - bool background, bool tolerance) -{ - typedef typename DenseT::ValueType DenseValueType; - struct Local { - inline static bool toBool(const DenseValueType& v) { return !math::isZero(v); } - }; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - const DenseValueType* s0 = dense.data() + zStride * (bbox.min()[2] - min[2]); // source - const Int32 n0 = bbox.min()[2] & (DIM-1u); - for (Int32 x = bbox.min()[0], ex = bbox.max()[0] + 1; x < ex; ++x) { - const DenseValueType* s1 = s0 + xStride * (x - min[0]); - const Int32 n1 = n0 + ((x & (DIM-1u)) << 2*LOG2DIM); - for (Int32 y = bbox.min()[1], ey = bbox.max()[1] + 1; y < ey; ++y) { - const DenseValueType* s2 = s1 + yStride * (y - min[1]); - Int32 n2 = n1 + ((y & (DIM-1u)) << LOG2DIM); - for (Int32 z = bbox.min()[2], ez = bbox.max()[2]+1; z < ez; ++z, ++n2, s2 += zStride) { - // Note: if tolerance is true (i.e., 1), then all boolean values compare equal. - if (tolerance || (background == Local::toBool(*s2))) { - mValueMask.setOff(n2); - mBuffer.mData.set(n2, background); - } else { - mValueMask.setOn(n2); - mBuffer.mData.set(n2, Local::toBool(*s2)); - } - } - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::combine(const LeafNode& other, CombineOp& op) -{ - CombineArgs args; - for (Index i = 0; i < SIZE; ++i) { - bool result = false, aVal = mBuffer.mData.isOn(i), bVal = other.mBuffer.mData.isOn(i); - op(args.setARef(aVal) - .setAIsActive(mValueMask.isOn(i)) - .setBRef(bVal) - .setBIsActive(other.mValueMask.isOn(i)) - .setResultRef(result)); - mValueMask.set(i, args.resultIsActive()); - mBuffer.mData.set(i, result); - } -} - - -template -template -inline void -LeafNode::combine(bool value, bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - args.setBRef(value).setBIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - bool result = false, aVal = mBuffer.mData.isOn(i); - op(args.setARef(aVal) - .setAIsActive(mValueMask.isOn(i)) - .setResultRef(result)); - mValueMask.set(i, args.resultIsActive()); - mBuffer.mData.set(i, result); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::combine2(const LeafNode& other, const OtherType& value, - bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - args.setBRef(value).setBIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - bool result = false, aVal = other.mBuffer.mData.isOn(i); - op(args.setARef(aVal) - .setAIsActive(other.mValueMask.isOn(i)) - .setResultRef(result)); - mValueMask.set(i, args.resultIsActive()); - mBuffer.mData.set(i, result); - } -} - - -template -template -inline void -LeafNode::combine2(bool value, const OtherNodeT& other, - bool valueIsActive, CombineOp& op) -{ - CombineArgs args; - args.setARef(value).setAIsActive(valueIsActive); - for (Index i = 0; i < SIZE; ++i) { - bool result = false, bVal = other.mBuffer.mData.isOn(i); - op(args.setBRef(bVal) - .setBIsActive(other.mValueMask.isOn(i)) - .setResultRef(result)); - mValueMask.set(i, args.resultIsActive()); - mBuffer.mData.set(i, result); - } -} - - -template -template -inline void -LeafNode::combine2(const LeafNode& b0, const OtherNodeT& b1, CombineOp& op) -{ - CombineArgs args; - for (Index i = 0; i < SIZE; ++i) { - // Default behavior: output voxel is active if either input voxel is active. - mValueMask.set(i, b0.mValueMask.isOn(i) || b1.mValueMask.isOn(i)); - - bool result = false, b0Val = b0.mBuffer.mData.isOn(i), b1Val = b1.mBuffer.mData.isOn(i); - op(args.setARef(b0Val) - .setAIsActive(b0.mValueMask.isOn(i)) - .setBRef(b1Val) - .setBIsActive(b1.mValueMask.isOn(i)) - .setResultRef(result)); - mValueMask.set(i, args.resultIsActive()); - mBuffer.mData.set(i, result); - } -} - - -//////////////////////////////////////// - -template -template -inline void -LeafNode::visitActiveBBox(BBoxOp& op) const -{ - if (op.template descent()) { - for (ValueOnCIter i=this->cbeginValueOn(); i; ++i) { -#ifdef _MSC_VER - op.operator()(CoordBBox::createCube(i.getCoord(), 1)); -#else - op.template operator()(CoordBBox::createCube(i.getCoord(), 1)); -#endif - } - } else { -#ifdef _MSC_VER - op.operator()(this->getNodeBoundingBox()); -#else - op.template operator()(this->getNodeBoundingBox()); -#endif - } -} - - -template -template -inline void -LeafNode::visit(VisitorOp& op) -{ - doVisit(*this, op); -} - - -template -template -inline void -LeafNode::visit(VisitorOp& op) const -{ - doVisit(*this, op); -} - - -template -template -inline void -LeafNode::doVisit(NodeT& self, VisitorOp& op) -{ - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(iter); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::visit2Node(OtherLeafNodeType& other, VisitorOp& op) -{ - doVisit2Node(*this, other, op); -} - - -template -template -inline void -LeafNode::visit2Node(OtherLeafNodeType& other, VisitorOp& op) const -{ - doVisit2Node(*this, other, op); -} - - -template -template< - typename NodeT, - typename OtherNodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -LeafNode::doVisit2Node(NodeT& self, OtherNodeT& other, VisitorOp& op) -{ - // Allow the two nodes to have different ValueTypes, but not different dimensions. - BOOST_STATIC_ASSERT(OtherNodeT::SIZE == NodeT::SIZE); - BOOST_STATIC_ASSERT(OtherNodeT::LEVEL == NodeT::LEVEL); - - ChildAllIterT iter = self.beginChildAll(); - OtherChildAllIterT otherIter = other.beginChildAll(); - - for ( ; iter && otherIter; ++iter, ++otherIter) { - op(iter, otherIter); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -LeafNode::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) -{ - doVisit2(*this, otherIter, op, otherIsLHS); -} - - -template -template -inline void -LeafNode::visit2(IterT& otherIter, VisitorOp& op, bool otherIsLHS) const -{ - doVisit2(*this, otherIter, op, otherIsLHS); -} - - -template -template< - typename NodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -LeafNode::doVisit2(NodeT& self, OtherChildAllIterT& otherIter, - VisitorOp& op, bool otherIsLHS) -{ - if (!otherIter) return; - - if (otherIsLHS) { - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(otherIter, iter); - } - } else { - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - op(iter, otherIter); - } - } -} - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_LEAFNODEBOOL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/NodeManager.h b/openvdb_3_0_0_library/tree/NodeManager.h deleted file mode 100755 index d3b72f4..0000000 --- a/openvdb_3_0_0_library/tree/NodeManager.h +++ /dev/null @@ -1,826 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file NodeManager.h -/// -/// @author Ken Museth -/// -/// @brief NodeManager produces linear arrays of all tree nodes -/// allowing for efficient threading and bottom-up processing. -/// -/// @note A NodeManager can be constructed from a Tree or LeafManager. -/// The latter is slightly more efficient since the cached leaf nodes will be reused. - -#ifndef OPENVDB_TREE_NODEMANAGER_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_NODEMANAGER_HAS_BEEN_INCLUDED - -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -// Produce linear arrays of all tree nodes, to facilitate efficient threading -// and bottom-up processing. -template -class NodeManager; - - -//////////////////////////////////////// - - -/// @brief This class caches tree nodes of a specific type in a linear array. -/// -/// @note It is for internal use and should rarely be used directly. -template -class NodeList -{ -public: - typedef NodeT* value_type; - typedef std::deque ListT; - - NodeList() {} - - void push_back(NodeT* node) { mList.push_back(node); } - - NodeT& operator()(size_t n) const { assert(nsize();} - - class Iterator - { - public: - Iterator(const NodeRange& range, size_t pos): mRange(range), mPos(pos) - { - assert(this->isValid()); - } - Iterator& operator=(const Iterator& other) - { - mRange = other.mRange; mPos = other.mPos; return *this; - } - /// Advance to the next node. - Iterator& operator++() { ++mPos; return *this; } - /// Return a reference to the node to which this iterator is pointing. - NodeT& operator*() const { return mRange.mNodeList(mPos); } - /// Return a pointer to the node to which this iterator is pointing. - NodeT* operator->() const { return &(this->operator*()); } - /// Return the index into the list of the current node. - size_t pos() const { return mPos; } - bool isValid() const { return mPos>=mRange.mBegin && mPos<=mRange.mEnd; } - /// Return @c true if this iterator is not yet exhausted. - bool test() const { return mPos < mRange.mEnd; } - /// Return @c true if this iterator is not yet exhausted. - operator bool() const { return this->test(); } - /// Return @c true if this iterator is exhausted. - bool empty() const { return !this->test(); } - bool operator!=(const Iterator& other) const - { - return (mPos != other.mPos) || (&mRange != &other.mRange); - } - bool operator==(const Iterator& other) const { return !(*this != other); } - const NodeRange& nodeRange() const { return mRange; } - - private: - const NodeRange& mRange; - size_t mPos; - };// NodeList::NodeRange::Iterator - - Iterator begin() const {return Iterator(*this, mBegin);} - - Iterator end() const {return Iterator(*this, mEnd);} - - private: - size_t mEnd, mBegin, mGrainSize; - const NodeList& mNodeList; - - static size_t doSplit(NodeRange& r) - { - assert(r.is_divisible()); - size_t middle = r.mBegin + (r.mEnd - r.mBegin) / 2u; - r.mEnd = middle; - return middle; - } - };// NodeList::NodeRange - - /// Return a TBB-compatible NodeRange. - NodeRange nodeRange(size_t grainsize = 1) const - { - return NodeRange(0, this->nodeCount(), *this, grainsize); - } - - template - struct NodeTransformer - { - NodeTransformer(const NodeOp& nodeOp) : mNodeOp(nodeOp) {} - void run(const NodeRange& range, bool threaded = true) - { - threaded ? tbb::parallel_for(range, *this) : (*this)(range); - } - void operator()(const NodeRange& range) const - { - for (typename NodeRange::Iterator it = range.begin(); it; ++it) mNodeOp(*it); - } - const NodeOp mNodeOp; - };// NodeRange - - template - void foreach(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - NodeTransformer transform(op); - transform.run(this->nodeRange(grainSize), threaded); - } - -protected: - ListT mList; -};// NodeList - - -///////////////////////////////////////////// - - -/// @brief This class is a link in a chain that each caches tree nodes -/// of a specific type in a linear array. -/// -/// @note It is for internal use and should rarely be used directly. -template -class NodeManagerLink -{ -public: - NodeManagerLink() {} - - virtual ~NodeManagerLink() {} - - void clear() { mList.clear(); mNext.clear(); } - - template - void init(ParentT& parent, TreeOrLeafManagerT& tree) - { - parent.getNodes(mList); - for (size_t i=0, n=mList.nodeCount(); i - void rebuild(ParentT& parent) - { - mList.clear(); - parent.getNodes(mList); - for (size_t i=0, n=mList.nodeCount(); i - void processBottomUp(const NodeOp& op, bool threaded, size_t grainSize) - { - mNext.processBottomUp(op, threaded, grainSize); - mList.foreach(op, threaded, grainSize); - } - - template - void processTopDown(const NodeOp& op, bool threaded, size_t grainSize) - { - mList.foreach(op, threaded, grainSize); - mNext.processTopDown(op, threaded, grainSize); - } - -protected: - NodeList mList; - NodeManagerLink mNext; -};// NodeManagerLink class - - -//////////////////////////////////////// - - -/// @brief Specialization that terminates the chain of cached tree nodes -/// -/// @note It is for internal use and should rarely be used directly. -template -class NodeManagerLink -{ -public: - NodeManagerLink() {} - - virtual ~NodeManagerLink() {} - - /// @brief Clear all the cached tree nodes - void clear() { mList.clear(); } - - template - void rebuild(ParentT& parent) { mList.clear(); parent.getNodes(mList); } - - Index64 nodeCount() const { return mList.nodeCount(); } - - Index64 nodeCount(Index) const { return mList.nodeCount(); } - - template - void processBottomUp(const NodeOp& op, bool threaded, size_t grainSize) - { - mList.foreach(op, threaded, grainSize); - } - - template - void processTopDown(const NodeOp& op, bool threaded, size_t grainSize) - { - mList.foreach(op, threaded, grainSize); - } - - template - void init(ParentT& parent, TreeOrLeafManagerT& tree) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (TreeOrLeafManagerT::DEPTH == 2 && NodeT::LEVEL == 0) { - tree.getNodes(mList); - } else { - parent.getNodes(mList); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } -protected: - NodeList mList; -};// NodeManagerLink class - - -//////////////////////////////////////// - - -/// @brief To facilitate threading over the nodes of a tree, cache -/// node pointers in linear arrays, one for each level of the tree. -/// -/// @details This implementation works with trees of any depth, but -/// optimized specializations are provided for the most typical tree depths. -template -class NodeManager -{ -public: - static const Index LEVELS = _LEVELS; - BOOST_STATIC_ASSERT(LEVELS > 0);//special implementation below - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - BOOST_STATIC_ASSERT(RootNodeType::LEVEL >= LEVELS); - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) { mChain.init(mRoot, tree); } - - virtual ~NodeManager() {} - - /// @brief Clear all the cached tree nodes - void clear() { mChain.clear(); } - - /// @brief Clear and recache all the tree nodes from the - /// tree. This is required if tree nodes have been added or removed. - void rebuild() { mChain.rebuild(mRoot); } - - /// @brief Return a reference to the root node. - const RootNodeType& root() const { return mRoot; } - - /// @brief Return the total number of cached nodes (excluding the root node) - Index64 nodeCount() const { return mChain.nodeCount(); } - - /// @brief Return the number of cached nodes at level @a i, where - /// 0 corresponds to the lowest level. - Index64 nodeCount(Index i) const { return mChain.nodeCount(i); } - - //@{ - /// @brief Threaded method that applies a user-supplied functor - /// to all the nodes in the tree. - /// - /// @param op user-supplied functor, see examples for interface details. - /// @param threaded optional toggle to disable threading, on by default. - /// @param grainSize optional parameter to specify the grainsize - /// for threading, one by default. - /// - /// @warning The functor object is deep-copied to create TBB tasks. - /// - /// @par Example: - /// @code - /// // Functor to offset all the inactive values of a tree. Note - /// // this implementation also illustrates how different - /// // computation can be applied to the different node types. - /// template - /// struct OffsetOp - /// { - /// typedef typename TreeT::ValueType ValueT; - /// typedef typename TreeT::RootNodeType RootT; - /// typedef typename TreeT::LeafNodeType LeafT; - /// OffsetOp(const ValueT& v) : mOffset(v) {} - /// - /// // Processes the root node. Required by the NodeManager - /// void operator()(RootT& root) const - /// { - /// for (typename RootT::ValueOffIter i = root.beginValueOff(); i; ++i) *i += mOffset; - /// } - /// // Processes the leaf nodes. Required by the NodeManager - /// void operator()(LeafT& leaf) const - /// { - /// for (typename LeafT::ValueOffIter i = leaf.beginValueOff(); i; ++i) *i += mOffset; - /// } - /// // Processes the internal nodes. Required by the NodeManager - /// template - /// void operator()(NodeT& node) const - /// { - /// for (typename NodeT::ValueOffIter i = node.beginValueOff(); i; ++i) *i += mOffset; - /// } - /// private: - /// const ValueT mOffset; - /// }; - /// - /// // usage: - /// OffsetOp op(tree); - /// tree::NodeManager nodes(tree); - /// nodes.processBottomUp(op); - /// - /// // or for better performance - /// typedef tree::LeafManager T; - /// OffsetOp op(leafManager); - /// tree::NodeManager nodes(leafManager); - /// nodes.processBottomUp(op); - /// - /// @endcode - template - void processBottomUp(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - mChain.processBottomUp(op, threaded, grainSize); - op(mRoot); - } - - template - void processTopDown(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - op(mRoot); - mChain.processTopDown(op, threaded, grainSize); - } - //@} - -protected: - RootNodeType& mRoot; - NodeManagerLink mChain; - -private: - NodeManager(const NodeManager&) {}//disallow copy-construction -};// NodeManager class - - -//////////////////////////////////////////// - - -/// Template specialization of the NodeManager with no caching of nodes -template -class NodeManager -{ -public: - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - static const Index LEVELS = 0; - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) {} - - virtual ~NodeManager() {} - - /// @brief Clear all the cached tree nodes - void clear() {} - - /// @brief Clear and recache all the tree nodes from the - /// tree. This is required if tree nodes have been added or removed. - void rebuild() {} - - /// @brief Return a reference to the root node. - const RootNodeType& root() const { return mRoot; } - - /// @brief Return the total number of cached nodes (excluding the root node) - Index64 nodeCount() const { return 0; } - - Index64 nodeCount(Index) const { return 0; } - - template - void processBottomUp(const NodeOp& op, bool, size_t) { op(mRoot); } - - template - void processTopDown(const NodeOp& op, bool, size_t) { op(mRoot); } - -protected: - RootNodeType& mRoot; - -private: - NodeManager(const NodeManager&) {} // disallow copy-construction -}; // NodeManager<0> - - -//////////////////////////////////////////// - - -/// Template specialization of the NodeManager with one level of nodes -template -class NodeManager -{ -public: - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - BOOST_STATIC_ASSERT(RootNodeType::LEVEL > 0); - static const Index LEVELS = 1; - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (TreeOrLeafManagerT::DEPTH == 2 && NodeT0::LEVEL == 0) { - tree.getNodes(mList0); - } else { - mRoot.getNodes(mList0); - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - virtual ~NodeManager() {} - - /// @brief Clear all the cached tree nodes - void clear() { mList0.clear(); } - - /// @brief Clear and recache all the tree nodes from the - /// tree. This is required if tree nodes have been added or removed. - void rebuild() { mList0.clear(); mRoot.getNodes(mList0); } - - /// @brief Return a reference to the root node. - const RootNodeType& root() const { return mRoot; } - - /// @brief Return the total number of cached nodes (excluding the root node) - Index64 nodeCount() const { return mList0.nodeCount(); } - - /// @brief Return the number of cached nodes at level @a i, where - /// 0 corresponds to the lowest level. - Index64 nodeCount(Index i) const { return i==0 ? mList0.nodeCount() : 0; } - - template - void processBottomUp(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - mList0.foreach(op, threaded, grainSize); - op(mRoot); - } - - template - void processTopDown(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - op(mRoot); - mList0.foreach(op, threaded, grainSize); - } - -protected: - typedef RootNodeType NodeT1; - typedef typename NodeT1::ChildNodeType NodeT0; - typedef NodeList ListT0; - - NodeT1& mRoot; - ListT0 mList0; - -private: - NodeManager(const NodeManager&) {} // disallow copy-construction -}; // NodeManager<1> - - -//////////////////////////////////////////// - - -/// Template specialization of the NodeManager with two levels of nodes -template -class NodeManager -{ -public: - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - BOOST_STATIC_ASSERT(RootNodeType::LEVEL > 1); - static const Index LEVELS = 2; - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) - { - mRoot.getNodes(mList1); - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (TreeOrLeafManagerT::DEPTH == 2 && NodeT0::LEVEL == 0) { - tree.getNodes(mList0); - } else { - for (size_t i=0, n=mList1.nodeCount(); iclear(); - mRoot.getNodes(mList1); - for (size_t i=0, n=mList1.nodeCount(); i - void processBottomUp(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - mList0.foreach(op, threaded, grainSize); - mList1.foreach(op, threaded, grainSize); - op(mRoot); - } - - template - void processTopDown(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - op(mRoot); - mList1.foreach(op, threaded, grainSize); - mList0.foreach(op, threaded, grainSize); - } - -protected: - typedef RootNodeType NodeT2; - typedef typename NodeT2::ChildNodeType NodeT1;//upper level - typedef typename NodeT1::ChildNodeType NodeT0;//lower level - - typedef NodeList ListT1;//upper level - typedef NodeList ListT0;//lower level - - NodeT2& mRoot; - ListT1 mList1; - ListT0 mList0; - -private: - NodeManager(const NodeManager&) {} // disallow copy-construction -}; // NodeManager<2> - - -//////////////////////////////////////////// - - -/// Template specialization of the NodeManager with three levels of nodes -template -class NodeManager -{ -public: - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - BOOST_STATIC_ASSERT(RootNodeType::LEVEL > 2); - static const Index LEVELS = 3; - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) - { - mRoot.getNodes(mList2); - for (size_t i=0, n=mList2.nodeCount(); iclear(); - mRoot.getNodes(mList2); - for (size_t i=0, n=mList2.nodeCount(); i - void processBottomUp(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - mList0.foreach(op, threaded, grainSize); - mList1.foreach(op, threaded, grainSize); - mList2.foreach(op, threaded, grainSize); - op(mRoot); - } - - template - void processTopDown(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - op(mRoot); - mList2.foreach(op, threaded, grainSize); - mList1.foreach(op, threaded, grainSize); - mList0.foreach(op, threaded, grainSize); - } - -protected: - typedef RootNodeType NodeT3; - typedef typename NodeT3::ChildNodeType NodeT2;//upper level - typedef typename NodeT2::ChildNodeType NodeT1;//mid level - typedef typename NodeT1::ChildNodeType NodeT0;//lower level - - typedef NodeList ListT2;//upper level of internal nodes - typedef NodeList ListT1;//lower level of internal nodes - typedef NodeList ListT0;//lower level of internal nodes or leafs - - NodeT3& mRoot; - ListT2 mList2; - ListT1 mList1; - ListT0 mList0; - -private: - NodeManager(const NodeManager&) {} // disallow copy-construction -}; // NodeManager<3> - - -//////////////////////////////////////////// - - -/// Template specialization of the NodeManager with four levels of nodes -template -class NodeManager -{ -public: - typedef typename TreeOrLeafManagerT::RootNodeType RootNodeType; - BOOST_STATIC_ASSERT(RootNodeType::LEVEL > 3); - static const Index LEVELS = 4; - - NodeManager(TreeOrLeafManagerT& tree) : mRoot(tree.root()) - { - mRoot.getNodes(mList3); - for (size_t i=0, n=mList3.nodeCount(); iclear(); - mRoot.getNodes(mList3); - for (size_t i=0, n=mList3.nodeCount(); i - void processBottomUp(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - mList0.foreach(op, threaded, grainSize); - mList1.foreach(op, threaded, grainSize); - mList2.foreach(op, threaded, grainSize); - mList3.foreach(op, threaded, grainSize); - op(mRoot); - } - - template - void processTopDown(const NodeOp& op, bool threaded = true, size_t grainSize=1) - { - op(mRoot); - mList3.foreach(op, threaded, grainSize); - mList2.foreach(op, threaded, grainSize); - mList1.foreach(op, threaded, grainSize); - mList0.foreach(op, threaded, grainSize); - } - -protected: - typedef RootNodeType NodeT4; - typedef typename NodeT4::ChildNodeType NodeT3;//upper level - typedef typename NodeT3::ChildNodeType NodeT2;//upper mid level - typedef typename NodeT2::ChildNodeType NodeT1;//lower mid level - typedef typename NodeT1::ChildNodeType NodeT0;//lower level - - typedef NodeList ListT3;//upper level of internal nodes - typedef NodeList ListT2;//upper mid level of internal nodes - typedef NodeList ListT1;//lower mid level of internal nodes - typedef NodeList ListT0;//lower level of internal nodes or leafs - - NodeT4& mRoot; - ListT3 mList3; - ListT2 mList2; - ListT1 mList1; - ListT0 mList0; - -private: - NodeManager(const NodeManager&) {} // disallow copy-construction -}; // NodeManager<4> - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_NODEMANAGER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/NodeUnion.h b/openvdb_3_0_0_library/tree/NodeUnion.h deleted file mode 100755 index ea01e44..0000000 --- a/openvdb_3_0_0_library/tree/NodeUnion.h +++ /dev/null @@ -1,137 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file NodeUnion.h -/// -/// @author Peter Cucka -/// -/// NodeUnion is a templated helper class that controls access to either -/// the child node pointer or the value for a particular element of a root -/// or internal node. For space efficiency, the child pointer and the value -/// are unioned, since the two are never in use simultaneously. -/// Template specializations of NodeUnion allow for values of either POD -/// (int, float, pointer, etc.) or class (std::string, math::Vec, etc.) types. -/// (The latter cannot be stored directly in a union.) - -#ifndef OPENVDB_TREE_NODEUNION_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_NODEUNION_HAS_BEEN_INCLUDED - -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -// Internal implementation of a union of a child node pointer and a value -template class NodeUnionImpl; - - -// Partial specialization for values of non-class types -// (int, float, pointer, etc.) that stores elements by value -template -class NodeUnionImpl -{ -private: - union { ChildT* child; ValueT value; } mUnion; - -public: - NodeUnionImpl() { setChild(NULL); } - - ChildT* getChild() const { return mUnion.child; } - const ValueT& getValue() const { return mUnion.value; } - ValueT& getValue() { return mUnion.value; } - void setChild(ChildT* child) { mUnion.child = child; } - void setValue(const ValueT& val) { mUnion.value = val; } -}; - - -// Partial specialization for values of class types (std::string, -// math::Vec, etc.) that stores elements by pointer -template -class NodeUnionImpl -{ -private: - union { ChildT* child; ValueT* value; } mUnion; - bool mHasChild; - -public: - NodeUnionImpl(): mHasChild(true) { setChild(NULL); } - NodeUnionImpl(const NodeUnionImpl& other) - { - if (other.mHasChild) setChild(other.getChild()); - else setValue(other.getValue()); - } - NodeUnionImpl& operator=(const NodeUnionImpl& other) - { - if (other.mHasChild) setChild(other.getChild()); - else setValue(other.getValue()); - } - ~NodeUnionImpl() { setChild(NULL); } - - ChildT* getChild() const - { return mHasChild ? mUnion.child : NULL; } - void setChild(ChildT* child) - { - if (!mHasChild) delete mUnion.value; - mUnion.child = child; - mHasChild = true; - } - - const ValueT& getValue() const { return *mUnion.value; } - ValueT& getValue() { return *mUnion.value; } - void setValue(const ValueT& val) - { - /// @todo To minimize storage across nodes, intern and reuse - /// common values, using, e.g., boost::flyweight. - if (!mHasChild) delete mUnion.value; - mUnion.value = new ValueT(val); - mHasChild = false; - } -}; - - -template -struct NodeUnion: public NodeUnionImpl< - boost::is_class::value, ValueT, ChildT> -{ - NodeUnion() {} -}; - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_NODEUNION_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/RootNode.h b/openvdb_3_0_0_library/tree/RootNode.h deleted file mode 100755 index fa164cf..0000000 --- a/openvdb_3_0_0_library/tree/RootNode.h +++ /dev/null @@ -1,3337 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -/// -/// @file RootNode.h -/// -/// @brief The root node of an OpenVDB tree - -#ifndef OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include //for boost::mpl::vector -#include -#include -#include -#include -#include -#include -#include // for truncateRealToHalf() -#include // for isZero(), isExactlyEqual(), etc. -#include -#include // for backward compatibility only (see readTopology()) -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -// Forward declarations -template struct NodeChain; -template struct SameRootConfig; -template struct RootNodeCopyHelper; -template struct RootNodeCombineHelper; - - -template -class RootNode -{ -public: - typedef ChildType ChildNodeType; - typedef typename ChildType::LeafNodeType LeafNodeType; - typedef typename ChildType::ValueType ValueType; - - static const Index LEVEL = 1 + ChildType::LEVEL; // level 0 = leaf - - /// NodeChainType is a list of this tree's node types, from LeafNodeType to RootNode. - typedef typename NodeChain::Type NodeChainType; - BOOST_STATIC_ASSERT(boost::mpl::size::value == LEVEL + 1); - - /// @brief ValueConverter::Type is the type of a RootNode having the same - /// child hierarchy as this node but a different value type, T. - template - struct ValueConverter { - typedef RootNode::Type> Type; - }; - - /// @brief SameConfiguration::value is @c true if and only if - /// OtherNodeType is the type of a RootNode whose ChildNodeType has the same - /// configuration as this node's ChildNodeType. - template - struct SameConfiguration { - static const bool value = SameRootConfig::value; - }; - - - /// Construct a new tree with a background value of 0. - RootNode(); - - /// Construct a new tree with the given background value. - explicit RootNode(const ValueType& background); - - RootNode(const RootNode& other) { *this = other; } - - /// @brief Construct a new tree that reproduces the topology and active states - /// of a tree of a different ValueType but the same configuration (levels, - /// node dimensions and branching factors). Cast the other tree's values to - /// this tree's ValueType. - /// @throw TypeError if the other tree's configuration doesn't match this tree's - /// or if this tree's ValueType is not constructible from the other tree's ValueType. - template - explicit RootNode(const RootNode& other) { *this = other; } - - /// @brief Construct a new tree that reproduces the topology and active states of - /// another tree (which may have a different ValueType), but not the other tree's values. - /// @details All tiles and voxels that are active in the other tree are set to - /// @a foreground in the new tree, and all inactive tiles and voxels are set to @a background. - /// @param other the root node of a tree having (possibly) a different ValueType - /// @param background the value to which inactive tiles and voxels are initialized - /// @param foreground the value to which active tiles and voxels are initialized - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - template - RootNode(const RootNode& other, - const ValueType& background, const ValueType& foreground, TopologyCopy); - - /// @brief Construct a new tree that reproduces the topology and active states of - /// another tree (which may have a different ValueType), but not the other tree's values. - /// All tiles and voxels in the new tree are set to @a background regardless of - /// their active states in the other tree. - /// @param other the root node of a tree having (possibly) a different ValueType - /// @param background the value to which inactive tiles and voxels are initialized - /// @note This copy constructor is generally faster than the one that takes both - /// a foreground and a background value. Its main application is in multithreaded - /// operations where the topology of the output tree exactly matches the input tree. - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - template - RootNode(const RootNode& other, const ValueType& background, TopologyCopy); - - /// @brief Copy a root node of the same type as this node. - RootNode& operator=(const RootNode& other); - /// @brief Copy a root node of the same tree configuration as this node - /// but a different ValueType. - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - /// @note This node's ValueType must be constructible from the other node's ValueType. - /// For example, a root node with values of type float can be assigned to a root node - /// with values of type Vec3s, because a Vec3s can be constructed from a float. - /// But a Vec3s root node cannot be assigned to a float root node. - template - RootNode& operator=(const RootNode& other); - - ~RootNode() { this->clearTable(); } - -private: - struct Tile { - Tile(): value(zeroVal()), active(false) {} - Tile(const ValueType& v, bool b): value(v), active(b) {} - ValueType value; - bool active; - }; - - // This lightweight struct pairs child pointers and tiles. - struct NodeStruct { - ChildType* child; - Tile tile; - - NodeStruct(): child(NULL) {} - NodeStruct(ChildType& c): child(&c) {} - NodeStruct(const Tile& t): child(NULL), tile(t) {} - ~NodeStruct() {} ///< @note doesn't delete child - - bool isChild() const { return child != NULL; } - bool isTile() const { return child == NULL; } - bool isTileOff() const { return isTile() && !tile.active; } - bool isTileOn() const { return isTile() && tile.active; } - - void set(ChildType& c) { delete child; child = &c; } - void set(const Tile& t) { delete child; child = NULL; tile = t; } - ChildType& steal(const Tile& t) { ChildType* c = child; child = NULL; tile = t; return *c; } - }; - - typedef std::map MapType; - typedef typename MapType::iterator MapIter; - typedef typename MapType::const_iterator MapCIter; - - typedef std::set CoordSet; - typedef typename CoordSet::iterator CoordSetIter; - typedef typename CoordSet::const_iterator CoordSetCIter; - - static void setTile(const MapIter& i, const Tile& t) { i->second.set(t); } - static void setChild(const MapIter& i, ChildType& c) { i->second.set(c); } - static Tile& getTile(const MapIter& i) { return i->second.tile; } - static const Tile& getTile(const MapCIter& i) { return i->second.tile; } - static ChildType& getChild(const MapIter& i) { return *(i->second.child); } - static const ChildType& getChild(const MapCIter& i) { return *(i->second.child); } - static ChildType& stealChild(const MapIter& i, const Tile& t) {return i->second.steal(t);} - static const ChildType& stealChild(const MapCIter& i,const Tile& t) {return i->second.steal(t);} - - static bool isChild(const MapCIter& i) { return i->second.isChild(); } - static bool isChild(const MapIter& i) { return i->second.isChild(); } - static bool isTile(const MapCIter& i) { return i->second.isTile(); } - static bool isTile(const MapIter& i) { return i->second.isTile(); } - static bool isTileOff(const MapCIter& i) { return i->second.isTileOff(); } - static bool isTileOff(const MapIter& i) { return i->second.isTileOff(); } - static bool isTileOn(const MapCIter& i) { return i->second.isTileOn(); } - static bool isTileOn(const MapIter& i) { return i->second.isTileOn(); } - - struct NullPred { - static inline bool test(const MapIter&) { return true; } - static inline bool test(const MapCIter&) { return true; } - }; - struct ValueOnPred { - static inline bool test(const MapIter& i) { return isTileOn(i); } - static inline bool test(const MapCIter& i) { return isTileOn(i); } - }; - struct ValueOffPred { - static inline bool test(const MapIter& i) { return isTileOff(i); } - static inline bool test(const MapCIter& i) { return isTileOff(i); } - }; - struct ValueAllPred { - static inline bool test(const MapIter& i) { return isTile(i); } - static inline bool test(const MapCIter& i) { return isTile(i); } - }; - struct ChildOnPred { - static inline bool test(const MapIter& i) { return isChild(i); } - static inline bool test(const MapCIter& i) { return isChild(i); } - }; - struct ChildOffPred { - static inline bool test(const MapIter& i) { return isTile(i); } - static inline bool test(const MapCIter& i) { return isTile(i); } - }; - - template - class BaseIter - { - public: - typedef _RootNodeT RootNodeT; - typedef _MapIterT MapIterT; // either MapIter or MapCIter - - bool operator==(const BaseIter& other) const - { - return (mParentNode == other.mParentNode) && (mIter == other.mIter); - } - bool operator!=(const BaseIter& other) const { return !(*this == other); } - - RootNodeT* getParentNode() const { return mParentNode; } - /// Return a reference to the node over which this iterator iterates. - RootNodeT& parent() const - { - if (!mParentNode) OPENVDB_THROW(ValueError, "iterator references a null parent node"); - return *mParentNode; - } - - bool test() const { assert(mParentNode); return mIter != mParentNode->mTable.end(); } - operator bool() const { return this->test(); } - - void increment() { ++mIter; this->skip(); } - bool next() { this->increment(); return this->test(); } - void increment(Index n) { for (int i = 0; i < n && this->next(); ++i) {} } - - /// @brief Return this iterator's position as an offset from - /// the beginning of the parent node's map. - Index pos() const - { - return !mParentNode ? 0U : Index(std::distance(mParentNode->mTable.begin(), mIter)); - } - - bool isValueOn() const { return RootNodeT::isTileOn(mIter); } - bool isValueOff() const { return RootNodeT::isTileOff(mIter); } - void setValueOn(bool on = true) const { mIter->second.tile.active = on; } - void setValueOff() const { mIter->second.tile.active = false; } - - /// Return the coordinates of the item to which this iterator is pointing. - Coord getCoord() const { return mIter->first; } - /// Return in @a xyz the coordinates of the item to which this iterator is pointing. - void getCoord(Coord& xyz) const { xyz = this->getCoord(); } - - protected: - BaseIter(): mParentNode(NULL) {} - BaseIter(RootNodeT& parent, const MapIterT& iter): mParentNode(&parent), mIter(iter) {} - - void skip() { while (this->test() && !FilterPredT::test(mIter)) ++mIter; } - - RootNodeT* mParentNode; - MapIterT mIter; - }; // BaseIter - - template - class ChildIter: public BaseIter - { - public: - typedef BaseIter BaseT; - typedef RootNodeT NodeType; - typedef NodeType ValueType; - typedef ChildNodeT ChildNodeType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::remove_const::type NonConstValueType; - typedef typename boost::remove_const::type NonConstChildNodeType; - using BaseT::mIter; - - ChildIter() {} - ChildIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); } - - ChildIter& operator++() { BaseT::increment(); return *this; } - - ChildNodeT& getValue() const { return getChild(mIter); } - ChildNodeT& operator*() const { return this->getValue(); } - ChildNodeT* operator->() const { return &this->getValue(); } - }; // ChildIter - - template - class ValueIter: public BaseIter - { - public: - typedef BaseIter BaseT; - typedef RootNodeT NodeType; - typedef ValueT ValueType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::remove_const::type NonConstValueType; - using BaseT::mIter; - - ValueIter() {} - ValueIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) { BaseT::skip(); } - - ValueIter& operator++() { BaseT::increment(); return *this; } - - ValueT& getValue() const { return getTile(mIter).value; } - ValueT& operator*() const { return this->getValue(); } - ValueT* operator->() const { return &(this->getValue()); } - - void setValue(const ValueT& v) const { assert(isTile(mIter)); getTile(mIter).value = v; } - - template - void modifyValue(const ModifyOp& op) const - { - assert(isTile(mIter)); - op(getTile(mIter).value); - } - }; // ValueIter - - template - class DenseIter: public BaseIter - { - public: - typedef BaseIter BaseT; - typedef RootNodeT NodeType; - typedef ValueT ValueType; - typedef ChildNodeT ChildNodeType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::remove_const::type NonConstValueType; - typedef typename boost::remove_const::type NonConstChildNodeType; - using BaseT::mIter; - - DenseIter() {} - DenseIter(RootNodeT& parent, const MapIterT& iter): BaseT(parent, iter) {} - - DenseIter& operator++() { BaseT::increment(); return *this; } - - bool isChildNode() const { return isChild(mIter); } - - ChildNodeT* probeChild(NonConstValueType& value) const - { - if (isChild(mIter)) return &getChild(mIter); - value = getTile(mIter).value; - return NULL; - } - bool probeChild(ChildNodeT*& child, NonConstValueType& value) const - { - child = this->probeChild(value); - return child != NULL; - } - bool probeValue(NonConstValueType& value) const { return !this->probeChild(value); } - - void setChild(ChildNodeT& c) const { RootNodeT::setChild(mIter, c); } - void setChild(ChildNodeT* c) const { assert(c != NULL); RootNodeT::setChild(mIter, *c); } - void setValue(const ValueT& v) const - { - if (isTile(mIter)) getTile(mIter).value = v; - /// @internal For consistency with iterators for other node types - /// (see, e.g., InternalNode::DenseIter::unsetItem()), we don't call - /// setTile() here, because that would also delete the child. - else stealChild(mIter, Tile(v, /*active=*/true)); - } - }; // DenseIter - -public: - typedef ChildIter ChildOnIter; - typedef ChildIter ChildOnCIter; - typedef ValueIter ChildOffIter; - typedef ValueIter ChildOffCIter; - typedef DenseIter ChildAllIter; - typedef DenseIter ChildAllCIter; - - typedef ValueIter ValueOnIter; - typedef ValueIter ValueOnCIter; - typedef ValueIter ValueOffIter; - typedef ValueIter ValueOffCIter; - typedef ValueIter ValueAllIter; - typedef ValueIter ValueAllCIter; - - - ChildOnCIter cbeginChildOn() const { return ChildOnCIter(*this, mTable.begin()); } - ChildOffCIter cbeginChildOff() const { return ChildOffCIter(*this, mTable.begin()); } - ChildAllCIter cbeginChildAll() const { return ChildAllCIter(*this, mTable.begin()); } - ChildOnCIter beginChildOn() const { return cbeginChildOn(); } - ChildOffCIter beginChildOff() const { return cbeginChildOff(); } - ChildAllCIter beginChildAll() const { return cbeginChildAll(); } - ChildOnIter beginChildOn() { return ChildOnIter(*this, mTable.begin()); } - ChildOffIter beginChildOff() { return ChildOffIter(*this, mTable.begin()); } - ChildAllIter beginChildAll() { return ChildAllIter(*this, mTable.begin()); } - - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this, mTable.begin()); } - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this, mTable.begin()); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this, mTable.begin()); } - ValueOnCIter beginValueOn() const { return cbeginValueOn(); } - ValueOffCIter beginValueOff() const { return cbeginValueOff(); } - ValueAllCIter beginValueAll() const { return cbeginValueAll(); } - ValueOnIter beginValueOn() { return ValueOnIter(*this, mTable.begin()); } - ValueOffIter beginValueOff() { return ValueOffIter(*this, mTable.begin()); } - ValueAllIter beginValueAll() { return ValueAllIter(*this, mTable.begin()); } - - /// Return the total amount of memory in bytes occupied by this node and its children. - Index64 memUsage() const; - - /// @brief Expand the specified bbox so it includes the active tiles of - /// this root node as well as all the active values in its child - /// nodes. If visitVoxels is false LeafNodes will be approximated - /// as dense, i.e. with all voxels active. Else the individual - /// active voxels are visited to produce a tight bbox. - void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const; - - /// Return the bounding box of this RootNode, i.e., an infinite bounding box. - static CoordBBox getNodeBoundingBox() { return CoordBBox::inf(); } - - /// @brief Change inactive tiles or voxels with a value equal to +/- the - /// old background to the specified value (with the same sign). Active values - /// are unchanged. - /// - /// @param value The new background value - /// @param updateChildNodes If true the background values of the - /// child nodes is also updated. Else only the background value - /// stored in the RootNode itself is changed. - /// - /// @note Instead of setting @a updateChildNodes to true, consider - /// using tools::changeBackground or - /// tools::changeLevelSetBackground which are multi-threaded! - void setBackground(const ValueType& value, bool updateChildNodes); - - /// Return this node's background value. - const ValueType& background() const { return mBackground; } - - /// Return @c true if the given tile is inactive and has the background value. - bool isBackgroundTile(const Tile&) const; - //@{ - /// Return @c true if the given iterator points to an inactive tile with the background value. - bool isBackgroundTile(const MapIter&) const; - bool isBackgroundTile(const MapCIter&) const; - //@} - - /// Return the number of background tiles. - size_t numBackgroundTiles() const; - /// @brief Remove all background tiles. - /// @return the number of tiles removed. - size_t eraseBackgroundTiles(); - void clear() { this->clearTable(); } - - /// Return @c true if this node's table is either empty or contains only background tiles. - bool empty() const { return mTable.size() == numBackgroundTiles(); } - - /// @brief Expand this node's table so that (x, y, z) is included in the index range. - /// @return @c true if an expansion was performed (i.e., if (x, y, z) was not already - /// included in the index range). - bool expand(const Coord& xyz); - - static Index getLevel() { return LEVEL; } - static void getNodeLog2Dims(std::vector& dims); - static Index getChildDim() { return ChildType::DIM; } - - /// Return the number of entries in this node's table. - Index getTableSize() const { return static_cast(mTable.size()); } - - Index getWidth() const { return this->getMaxIndex()[0] - this->getMinIndex()[0]; } - Index getHeight() const { return this->getMaxIndex()[1] - this->getMinIndex()[1]; } - Index getDepth() const { return this->getMaxIndex()[2] - this->getMinIndex()[2]; } - - /// Return the smallest index of the current tree. - Coord getMinIndex() const; - /// Return the largest index of the current tree. - Coord getMaxIndex() const; - /// Return the current index range. Both min and max are inclusive. - void getIndexRange(CoordBBox& bbox) const; - - /// @brief Return @c true if the given tree has the same node and active value - /// topology as this tree (but possibly a different @c ValueType). - template - bool hasSameTopology(const RootNode& other) const; - - /// Return @c false if the other node's dimensions don't match this node's. - template - static bool hasSameConfiguration(const RootNode& other); - - /// Return @c true if values of the other node's ValueType can be converted - /// to values of this node's ValueType. - template - static bool hasCompatibleValueType(const RootNode& other); - - Index32 leafCount() const; - Index32 nonLeafCount() const; - Index64 onVoxelCount() const; - Index64 offVoxelCount() const; - Index64 onLeafVoxelCount() const; - Index64 offLeafVoxelCount() const; - Index64 onTileCount() const; - - bool isValueOn(const Coord& xyz) const; - - bool hasActiveTiles() const; - - const ValueType& getValue(const Coord& xyz) const; - bool probeValue(const Coord& xyz, ValueType& value) const; - - /// @brief Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides. - /// @details If (x, y, z) isn't explicitly represented in the tree (i.e., - /// it is implicitly a background voxel), return -1. - int getValueDepth(const Coord& xyz) const; - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on); - /// Set the value of the voxel at the given coordinates but don't change its active state. - void setValueOnly(const Coord& xyz, const ValueType& value); - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValueOn(const Coord& xyz, const ValueType& value); - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz); - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value); - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - template - void modifyValue(const Coord& xyz, const ModifyOp& op); - /// Apply a functor to the voxel at the given coordinates. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op); - - /// @brief Set all voxels within a given box to a constant value, if necessary - /// subdividing tiles that intersect the box. - /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box - /// @param value the value to which to set voxels within the box - /// @param active if true, mark voxels within the box as active, - /// otherwise mark them as inactive - void fill(const CoordBBox& bbox, const ValueType& value, bool active = true); - - /// @brief Copy into a dense grid the values of all voxels, both active and inactive, - /// that intersect a given bounding box. - /// @param bbox inclusive bounding box of the voxels to be copied into the dense grid - /// @param dense dense grid with a stride in @e z of one (see tools::Dense - /// in tools/Dense.h for the required API) - template - void copyToDense(const CoordBBox& bbox, DenseT& dense) const; - - - // - // I/O - // - bool writeTopology(std::ostream&, bool toHalf = false) const; - bool readTopology(std::istream&, bool fromHalf = false); - - void writeBuffers(std::ostream&, bool toHalf = false) const; - void readBuffers(std::istream&, bool fromHalf = false); - void readBuffers(std::istream&, const CoordBBox&, bool fromHalf = false); - - - // - // Voxel access - // - /// Return the value of the voxel at the given coordinates and, if necessary, update - /// the accessor with pointers to the nodes along the path from the root node to - /// the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - const ValueType& getValueAndCache(const Coord& xyz, AccessorT&) const; - /// Return @c true if the voxel at the given coordinates is active and, if necessary, - /// update the accessor with pointers to the nodes along the path from the root node - /// to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - bool isValueOnAndCache(const Coord& xyz, AccessorT&) const; - - /// Change the value of the voxel at the given coordinates and mark it as active. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// Set the value of the voxel at the given coordinates without changing its active state. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&); - - /// Apply a functor to the voxel at the given coordinates. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void modifyValueAndActiveStateAndCache(const Coord& xyz, const ModifyOp& op, AccessorT&); - - /// Change the value of the voxel at the given coordinates and mark it as inactive. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT&); - - /// Set the active state of the voxel at the given coordinates without changing its value. - /// If necessary, update the accessor with pointers to the nodes along the path - /// from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT&); - - /// Return, in @a value, the value of the voxel at the given coordinates and, - /// if necessary, update the accessor with pointers to the nodes along - /// the path from the root node to the node containing the voxel. - /// @return @c true if the voxel at the given coordinates is active - /// @note Used internally by ValueAccessor. - template - bool probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT&) const; - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides. - /// If (x, y, z) isn't explicitly represented in the tree (i.e., it is implicitly - /// a background voxel), return -1. If necessary, update the accessor with pointers - /// to the nodes along the path from the root node to the node containing the voxel. - /// @note Used internally by ValueAccessor. - template - int getValueDepthAndCache(const Coord& xyz, AccessorT&) const; - - /// Set all voxels that lie outside the given axis-aligned box to the background. - void clip(const CoordBBox&); - - /// @brief Reduce the memory footprint of this tree by replacing with tiles - /// any nodes whose values are all the same (optionally to within a tolerance) - /// and have the same active state. - void prune(const ValueType& tolerance = zeroVal()); - - /// @brief Add the given leaf node to this tree, creating a new branch if necessary. - /// If a leaf node with the same origin already exists, replace it. - void addLeaf(LeafNodeType* leaf); - - /// @brief Same as addLeaf() but, if necessary, update the given accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - void addLeafAndCache(LeafNodeType* leaf, AccessorT&); - - /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z) - /// and replace it with a tile of the specified value and state. - /// If no such node exists, leave the tree unchanged and return @c NULL. - /// - /// @note The caller takes ownership of the node and is responsible for deleting it. - /// - /// @warning Since this method potentially removes nodes and branches of the tree, - /// it is important to clear the caches of all ValueAccessors associated with this tree. - template - NodeT* stealNode(const Coord& xyz, const ValueType& value, bool state); - - /// @brief Add a tile containing voxel (x, y, z) at the root level, - /// deleting the existing branch if necessary. - void addTile(const Coord& xyz, const ValueType& value, bool state); - - /// @brief Add a tile containing voxel (x, y, z) at the specified tree level, - /// creating a new branch if necessary. Delete any existing lower-level nodes - /// that contain (x, y, z). - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state); - - /// @brief Same as addTile() but, if necessary, update the given accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - void addTileAndCache(Index level, const Coord& xyz, const ValueType&, bool state, AccessorT&); - - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, create one that preserves the values and - /// active states of all voxels. - /// @details Use this method to preallocate a static tree topology - /// over which to safely perform multithreaded processing. - LeafNodeType* touchLeaf(const Coord& xyz); - - /// @brief Same as touchLeaf() but, if necessary, update the given accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - LeafNodeType* touchLeafAndCache(const Coord& xyz, AccessorT& acc); - - //@{ - /// @brief Return a pointer to the node that contains voxel (x, y, z). - /// If no such node exists, return NULL. - template - NodeT* probeNode(const Coord& xyz); - template - const NodeT* probeConstNode(const Coord& xyz) const; - //@} - - //@{ - /// @brief Same as probeNode() but, if necessary, update the given accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - NodeT* probeNodeAndCache(const Coord& xyz, AccessorT& acc); - template - const NodeT* probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const; - //@} - - //@{ - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, return NULL. - LeafNodeType* probeLeaf(const Coord& xyz); - const LeafNodeType* probeConstLeaf(const Coord& xyz) const; - const LeafNodeType* probeLeaf(const Coord& xyz) const; - //@} - - //@{ - /// @brief Same as probeLeaf() but, if necessary, update the given accessor with pointers - /// to the nodes along the path from the root node to the node containing the coordinate. - template - LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc); - template - const LeafNodeType* probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const; - template - const LeafNodeType* probeLeafAndCache(const Coord& xyz, AccessorT& acc) const; - //@} - - - // - // Aux methods - // - - //@{ - /// @brief Adds all nodes of a certain type to a container with the following API: - /// @code - /// struct ArrayT { - /// typedef value_type;// defines the type of nodes to be added to the array - /// void push_back(value_type nodePtr);// method that add nodes to the array - /// }; - /// @endcode - /// @details An example of a wrapper around a c-style array is: - /// @code - /// struct MyArray { - /// typedef LeafType* value_type; - /// value_type* ptr; - /// MyArray(value_type* array) : ptr(array) {} - /// void push_back(value_type leaf) { *ptr++ = leaf; } - ///}; - /// @endcode - /// @details An example that constructs a list of pointer to all leaf nodes is: - /// @code - /// std::vector array;//most std contains have the required API - /// array.reserve(tree.leafCount());//this is a fast preallocation. - /// tree.getNodes(array); - /// @endcode - template void getNodes(ArrayT& array); - template void getNodes(ArrayT& array) const; - //@} - - /// Densify active tiles, i.e., replace them with leaf-level active voxels. - void voxelizeActiveTiles(); - - /// @brief Efficiently merge another tree into this tree using one of several schemes. - /// @details This operation is primarily intended to combine trees that are mostly - /// non-overlapping (for example, intermediate trees from computations that are - /// parallelized across disjoint regions of space). - /// @note This operation is not guaranteed to produce an optimally sparse tree. - /// Follow merge() with prune() for optimal sparseness. - /// @warning This operation always empties the other tree. - template void merge(RootNode& other); - - /// @brief Union this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. - /// @details The resulting state of a value is active if the corresponding value - /// was already active OR if it is active in the other tree. Also, a resulting - /// value maps to a voxel if the corresponding value already mapped to a voxel - /// OR if it is a voxel in the other tree. Thus, a resulting value can only - /// map to a tile if the corresponding value already mapped to a tile - /// AND if it is a tile value in other tree. - /// - /// @note This operation modifies only active states, not values. - /// Specifically, active tiles and voxels in this tree are not changed, and - /// tiles or voxels that were inactive in this tree but active in the other tree - /// are marked as active in this tree but left with their original values. - template - void topologyUnion(const RootNode& other); - - /// @brief Intersects this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. - /// @details The resulting state of a value is active only if the corresponding - /// value was already active AND if it is active in the other tree. Also, a - /// resulting value maps to a voxel if the corresponding value - /// already mapped to an active voxel in either of the two grids - /// and it maps to an active tile or voxel in the other grid. - /// - /// @note This operation can delete branches in this grid if they - /// overlap with inactive tiles in the other grid. Likewise active - /// voxels can be turned into inactive voxels resulting in leaf - /// nodes with no active values. Thus, it is recommended to - /// subsequently call prune. - template - void topologyIntersection(const RootNode& other); - - /// @brief Difference this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. So a - /// resulting voxel will be active only if the original voxel is - /// active in this tree and inactive in the other tree. - /// - /// @note This operation can delete branches in this grid if they - /// overlap with active tiles in the other grid. Likewise active - /// voxels can be turned into inactive voxels resulting in leaf - /// nodes with no active values. Thus, it is recommended to - /// subsequently call prune. - template - void topologyDifference(const RootNode& other); - - template - void combine(RootNode& other, CombineOp&, bool prune = false); - - template - void combine2(const RootNode& other0, const OtherRootNode& other1, - CombineOp& op, bool prune = false); - - /// @brief Call the templated functor BBoxOp with bounding box - /// information for all active tiles and leaf nodes in the tree. - /// An additional level argument is provided for each callback. - /// - /// @note The bounding boxes are guaranteed to be non-overlapping. - template void visitActiveBBox(BBoxOp&) const; - - template void visit(VisitorOp&); - template void visit(VisitorOp&) const; - - template - void visit2(OtherRootNodeType& other, VisitorOp&); - template - void visit2(OtherRootNodeType& other, VisitorOp&) const; - -private: - /// During topology-only construction, access is needed - /// to protected/private members of other template instances. - template friend class RootNode; - - template friend struct RootNodeCopyHelper; - template friend struct RootNodeCombineHelper; - - /// Currently no-op, but can be used to define empty and delete keys for mTable - void initTable() {} - inline void clearTable(); - //@{ - /// @internal Used by doVisit2(). - void resetTable(MapType& table) { mTable.swap(table); table.clear(); } - void resetTable(const MapType&) const {} - //@} - - Index getChildCount() const; - Index getTileCount() const; - Index getActiveTileCount() const; - Index getInactiveTileCount() const; - - /// Return a MapType key for the given coordinates. - static Coord coordToKey(const Coord& xyz) { return xyz & ~(ChildType::DIM - 1); } - - /// Insert this node's mTable keys into the given set. - void insertKeys(CoordSet&) const; - - /// Return @c true if this node's mTable contains the given key. - bool hasKey(const Coord& key) const { return mTable.find(key) != mTable.end(); } - //@{ - /// @brief Look up the given key in this node's mTable. - /// @return an iterator pointing to the matching mTable entry or to mTable.end(). - MapIter findKey(const Coord& key) { return mTable.find(key); } - MapCIter findKey(const Coord& key) const { return mTable.find(key); } - //@} - //@{ - /// @brief Convert the given coordinates to a key and look the key up in this node's mTable. - /// @return an iterator pointing to the matching mTable entry or to mTable.end(). - MapIter findCoord(const Coord& xyz) { return mTable.find(coordToKey(xyz)); } - MapCIter findCoord(const Coord& xyz) const { return mTable.find(coordToKey(xyz)); } - //@} - /// @brief Convert the given coordinates to a key and look the key up in this node's mTable. - /// @details If the key is not found, insert a background tile with that key. - /// @return an iterator pointing to the matching mTable entry. - MapIter findOrAddCoord(const Coord& xyz); - - /// @brief Verify that the tree rooted at @a other has the same configuration - /// (levels, branching factors and node dimensions) as this tree, but allow - /// their ValueTypes to differ. - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - template - static void enforceSameConfiguration(const RootNode& other); - - /// @brief Verify that @a other has values of a type that can be converted - /// to this node's ValueType. - /// @details For example, values of type float are compatible with values of type Vec3s, - /// because a Vec3s can be constructed from a float. But the reverse is not true. - /// @throw TypeError if the other node's ValueType is not convertible into this node's. - template - static void enforceCompatibleValueTypes(const RootNode& other); - - template - void doCombine2(const RootNode&, const OtherRootNode&, CombineOp&, bool prune); - - template - static inline void doVisit(RootNodeT&, VisitorOp&); - - template - static inline void doVisit2(RootNodeT&, OtherRootNodeT&, VisitorOp&); - - - MapType mTable; - ValueType mBackground; -}; // end of RootNode class - - -//////////////////////////////////////// - - -/// @brief NodeChain::Type is a boost::mpl::vector -/// that lists the types of the nodes of the tree rooted at RootNodeType in reverse order, -/// from LeafNode to RootNode. -/// @details For example, if RootNodeType is -/// @code -/// RootNode > > -/// @endcode -/// then NodeChain::Type is -/// @code -/// boost::mpl::vector< -/// LeafNode, -/// InternalNode, -/// InternalNode >, -/// RootNode > > > -/// @endcode -/// -/// @note Use the following to get the Nth node type, where N=0 is the LeafNodeType: -/// @code -/// boost::mpl::at >::type -/// @endcode -template -struct NodeChain { - typedef typename NodeChain::Type SubtreeT; - typedef typename boost::mpl::push_back::type Type; -}; - -/// Specialization to terminate NodeChain -template -struct NodeChain { - typedef typename boost::mpl::vector::type Type; -}; - - -//////////////////////////////////////// - - -//@{ -/// Helper metafunction used to implement RootNode::SameConfiguration -/// (which, as an inner class, can't be independently specialized) -template -struct SameRootConfig { - static const bool value = false; -}; - -template -struct SameRootConfig > { - static const bool value = ChildT1::template SameConfiguration::value; -}; -//@} - - -//////////////////////////////////////// - - -template -inline -RootNode::RootNode(): mBackground(zeroVal()) -{ - this->initTable(); -} - - -template -inline -RootNode::RootNode(const ValueType& background): mBackground(background) -{ - this->initTable(); -} - - -template -template -inline -RootNode::RootNode(const RootNode& other, - const ValueType& backgd, const ValueType& foregd, TopologyCopy): - mBackground(backgd) -{ - typedef RootNode OtherRootT; - - enforceSameConfiguration(other); - - const Tile bgTile(backgd, /*active=*/false), fgTile(foregd, true); - this->initTable(); - - for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) { - mTable[i->first] = OtherRootT::isTile(i) - ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile) - : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, foregd, TopologyCopy()))); - } -} - - -template -template -inline -RootNode::RootNode(const RootNode& other, - const ValueType& backgd, TopologyCopy): - mBackground(backgd) -{ - typedef RootNode OtherRootT; - - enforceSameConfiguration(other); - - const Tile bgTile(backgd, /*active=*/false), fgTile(backgd, true); - this->initTable(); - for (typename OtherRootT::MapCIter i=other.mTable.begin(), e=other.mTable.end(); i != e; ++i) { - mTable[i->first] = OtherRootT::isTile(i) - ? NodeStruct(OtherRootT::isTileOn(i) ? fgTile : bgTile) - : NodeStruct(*(new ChildT(OtherRootT::getChild(i), backgd, TopologyCopy()))); - } -} - - -//////////////////////////////////////// - - -// This helper class is a friend of RootNode and is needed so that assignment -// with value conversion can be specialized for compatible and incompatible -// pairs of RootNode types. -template -struct RootNodeCopyHelper -{ - static inline void copyWithValueConversion(RootT& self, const OtherRootT& other) - { - // If the two root nodes have different configurations or incompatible ValueTypes, - // throw an exception. - self.enforceSameConfiguration(other); - self.enforceCompatibleValueTypes(other); - // One of the above two tests should throw, so we should never get here: - std::ostringstream ostr; - ostr << "cannot convert a " << typeid(OtherRootT).name() - << " to a " << typeid(RootT).name(); - OPENVDB_THROW(TypeError, ostr.str()); - } -}; - -// Specialization for root nodes of compatible types -template -struct RootNodeCopyHelper -{ - static inline void copyWithValueConversion(RootT& self, const OtherRootT& other) - { - typedef typename RootT::ValueType ValueT; - typedef typename RootT::ChildNodeType ChildT; - typedef typename RootT::NodeStruct NodeStruct; - typedef typename RootT::Tile Tile; - typedef typename OtherRootT::ValueType OtherValueT; - typedef typename OtherRootT::MapCIter OtherMapCIter; - typedef typename OtherRootT::Tile OtherTile; - - struct Local { - /// @todo Consider using a value conversion functor passed as an argument instead. - static inline ValueT convertValue(const OtherValueT& val) { return ValueT(val); } - }; - - self.mBackground = Local::convertValue(other.mBackground); - - self.clearTable(); - self.initTable(); - - for (OtherMapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - if (other.isTile(i)) { - // Copy the other node's tile, but convert its value to this node's ValueType. - const OtherTile& otherTile = other.getTile(i); - self.mTable[i->first] = NodeStruct( - Tile(Local::convertValue(otherTile.value), otherTile.active)); - } else { - // Copy the other node's child, but convert its values to this node's ValueType. - self.mTable[i->first] = NodeStruct(*(new ChildT(other.getChild(i)))); - } - } - } -}; - - -// Overload for root nodes of the same type as this node -template -inline RootNode& -RootNode::operator=(const RootNode& other) -{ - if (&other != this) { - mBackground = other.mBackground; - - this->clearTable(); - this->initTable(); - - for (MapCIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - mTable[i->first] = - isTile(i) ? NodeStruct(getTile(i)) : NodeStruct(*(new ChildT(getChild(i)))); - } - } - return *this; -} - -// Overload for root nodes of different types -template -template -inline RootNode& -RootNode::operator=(const RootNode& other) -{ - typedef RootNode OtherRootT; - typedef typename OtherRootT::ValueType OtherValueT; - static const bool compatible = (SameConfiguration::value - && CanConvertType::value); - RootNodeCopyHelper::copyWithValueConversion(*this, other); - return *this; -} - - -//////////////////////////////////////// - -template -inline void -RootNode::setBackground(const ValueType& background, bool updateChildNodes) -{ - if (math::isExactlyEqual(background, mBackground)) return; - - if (updateChildNodes) { - // Traverse the tree, replacing occurrences of mBackground with background - // and -mBackground with -background. - for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) { - ChildT *child = iter->second.child; - if (child) { - child->resetBackground(/*old=*/mBackground, /*new=*/background); - } else { - Tile& tile = getTile(iter); - if (tile.active) continue;//only change inactive tiles - if (math::isApproxEqual(tile.value, mBackground)) { - tile.value = background; - } else if (math::isApproxEqual(tile.value, math::negative(mBackground))) { - tile.value = math::negative(background); - } - } - } - } - mBackground = background; -} - -template -inline bool -RootNode::isBackgroundTile(const Tile& tile) const -{ - return !tile.active && math::isApproxEqual(tile.value, mBackground); -} - -template -inline bool -RootNode::isBackgroundTile(const MapIter& iter) const -{ - return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground); -} - -template -inline bool -RootNode::isBackgroundTile(const MapCIter& iter) const -{ - return isTileOff(iter) && math::isApproxEqual(getTile(iter).value, mBackground); -} - - -template -inline size_t -RootNode::numBackgroundTiles() const -{ - size_t count = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (this->isBackgroundTile(i)) ++count; - } - return count; -} - - -template -inline size_t -RootNode::eraseBackgroundTiles() -{ - std::set keysToErase; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (this->isBackgroundTile(i)) keysToErase.insert(i->first); - } - for (std::set::iterator i = keysToErase.begin(), e = keysToErase.end(); i != e; ++i) { - mTable.erase(*i); - } - return keysToErase.size(); -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::insertKeys(CoordSet& keys) const -{ - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - keys.insert(i->first); - } -} - - -template -inline typename RootNode::MapIter -RootNode::findOrAddCoord(const Coord& xyz) -{ - const Coord key = coordToKey(xyz); - std::pair result = mTable.insert( - typename MapType::value_type(key, NodeStruct(Tile(mBackground, /*active=*/false)))); - return result.first; -} - - -template -inline bool -RootNode::expand(const Coord& xyz) -{ - const Coord key = coordToKey(xyz); - std::pair result = mTable.insert( - typename MapType::value_type(key, NodeStruct(Tile(mBackground, /*active=*/false)))); - return result.second; // return true if the key did not already exist -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::getNodeLog2Dims(std::vector& dims) -{ - dims.push_back(0); // magic number; RootNode has no Log2Dim - ChildT::getNodeLog2Dims(dims); -} - - -template -inline Coord -RootNode::getMinIndex() const -{ - return mTable.empty() ? Coord(0) : mTable.begin()->first; -} - -template -inline Coord -RootNode::getMaxIndex() const -{ - return mTable.empty() ? Coord(0) : mTable.rbegin()->first + Coord(ChildT::DIM - 1); -} - - -template -inline void -RootNode::getIndexRange(CoordBBox& bbox) const -{ - bbox.min() = this->getMinIndex(); - bbox.max() = this->getMaxIndex(); -} - - -//////////////////////////////////////// - - -template -template -inline bool -RootNode::hasSameTopology(const RootNode& other) const -{ - typedef RootNode OtherRootT; - typedef typename OtherRootT::MapType OtherMapT; - typedef typename OtherRootT::MapIter OtherIterT; - typedef typename OtherRootT::MapCIter OtherCIterT; - - if (!hasSameConfiguration(other)) return false; - - // Create a local copy of the other node's table. - OtherMapT copyOfOtherTable = other.mTable; - - // For each entry in this node's table... - for (MapCIter thisIter = mTable.begin(); thisIter != mTable.end(); ++thisIter) { - if (this->isBackgroundTile(thisIter)) continue; // ignore background tiles - - // Fail if there is no corresponding entry in the other node's table. - OtherCIterT otherIter = other.findKey(thisIter->first); - if (otherIter == other.mTable.end()) return false; - - // Fail if this entry is a tile and the other is a child or vice-versa. - if (isChild(thisIter)) {//thisIter points to a child - if (OtherRootT::isTile(otherIter)) return false; - // Fail if both entries are children, but the children have different topology. - if (!getChild(thisIter).hasSameTopology(&OtherRootT::getChild(otherIter))) return false; - } else {//thisIter points to a tile - if (OtherRootT::isChild(otherIter)) return false; - if (getTile(thisIter).active != OtherRootT::getTile(otherIter).active) return false; - } - - // Remove tiles and child nodes with matching topology from - // the copy of the other node's table. This is required since - // the two root tables can include an arbitrary number of - // background tiles and still have the same topology! - copyOfOtherTable.erase(otherIter->first); - } - // Fail if the remaining entries in copyOfOtherTable are not all background tiles. - for (OtherIterT i = copyOfOtherTable.begin(), e = copyOfOtherTable.end(); i != e; ++i) { - if (!other.isBackgroundTile(i)) return false; - } - return true; -} - - -template -template -inline bool -RootNode::hasSameConfiguration(const RootNode&) -{ - std::vector thisDims, otherDims; - RootNode::getNodeLog2Dims(thisDims); - RootNode::getNodeLog2Dims(otherDims); - return (thisDims == otherDims); -} - - -template -template -inline void -RootNode::enforceSameConfiguration(const RootNode&) -{ - std::vector thisDims, otherDims; - RootNode::getNodeLog2Dims(thisDims); - RootNode::getNodeLog2Dims(otherDims); - if (thisDims != otherDims) { - std::ostringstream ostr; - ostr << "grids have incompatible configurations (" << thisDims[0]; - for (size_t i = 1, N = thisDims.size(); i < N; ++i) ostr << " x " << thisDims[i]; - ostr << " vs. " << otherDims[0]; - for (size_t i = 1, N = otherDims.size(); i < N; ++i) ostr << " x " << otherDims[i]; - ostr << ")"; - OPENVDB_THROW(TypeError, ostr.str()); - } -} - - -template -template -inline bool -RootNode::hasCompatibleValueType(const RootNode&) -{ - typedef typename OtherChildType::ValueType OtherValueType; - return CanConvertType::value; -} - - -template -template -inline void -RootNode::enforceCompatibleValueTypes(const RootNode&) -{ - typedef typename OtherChildType::ValueType OtherValueType; - if (!CanConvertType::value) { - std::ostringstream ostr; - ostr << "values of type " << typeNameAsString() - << " cannot be converted to type " << typeNameAsString(); - OPENVDB_THROW(TypeError, ostr.str()); - } -} - - -//////////////////////////////////////// - - -template -inline Index64 -RootNode::memUsage() const -{ - Index64 sum = sizeof(*this); - for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) { - if (const ChildT *child = iter->second.child) { - sum += child->memUsage(); - } - } - return sum; -} - - -template -inline void -RootNode::clearTable() -{ - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - delete i->second.child; - } - mTable.clear(); -} - - -template -inline void -RootNode::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const -{ - for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) { - if (const ChildT *child = iter->second.child) { - child->evalActiveBoundingBox(bbox, visitVoxels); - } else if (isTileOn(iter)) { - bbox.expand(iter->first, ChildT::DIM); - } - } -} - - -template -inline Index -RootNode::getChildCount() const { - Index sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) ++sum; - } - return sum; -} - - -template -inline Index -RootNode::getTileCount() const -{ - Index sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isTile(i)) ++sum; - } - return sum; -} - - -template -inline Index -RootNode::getActiveTileCount() const -{ - Index sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isTileOn(i)) ++sum; - } - return sum; -} - - -template -inline Index -RootNode::getInactiveTileCount() const -{ - Index sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isTileOff(i)) ++sum; - } - return sum; -} - - -template -inline Index32 -RootNode::leafCount() const -{ - Index32 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) sum += getChild(i).leafCount(); - } - return sum; -} - - -template -inline Index32 -RootNode::nonLeafCount() const -{ - Index32 sum = 1; - if (ChildT::LEVEL != 0) { - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) sum += getChild(i).nonLeafCount(); - } - } - return sum; -} - - -template -inline Index64 -RootNode::onVoxelCount() const -{ - Index64 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) { - sum += getChild(i).onVoxelCount(); - } else if (isTileOn(i)) { - sum += ChildT::NUM_VOXELS; - } - } - return sum; -} - - -template -inline Index64 -RootNode::offVoxelCount() const -{ - Index64 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) { - sum += getChild(i).offVoxelCount(); - } else if (isTileOff(i) && !this->isBackgroundTile(i)) { - sum += ChildT::NUM_VOXELS; - } - } - return sum; -} - - -template -inline Index64 -RootNode::onLeafVoxelCount() const -{ - Index64 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) sum += getChild(i).onLeafVoxelCount(); - } - return sum; -} - - -template -inline Index64 -RootNode::offLeafVoxelCount() const -{ - Index64 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) sum += getChild(i).offLeafVoxelCount(); - } - return sum; -} - -template -inline Index64 -RootNode::onTileCount() const -{ - Index64 sum = 0; - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) { - sum += getChild(i).onTileCount(); - } else if (isTileOn(i)) { - sum += 1; - } - } - return sum; -} - -//////////////////////////////////////// - - -template -inline bool -RootNode::isValueOn(const Coord& xyz) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTileOff(iter)) return false; - return isTileOn(iter) ? true : getChild(iter).isValueOn(xyz); -} - -template -inline bool -RootNode::hasActiveTiles() const -{ - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i) ? getChild(i).hasActiveTiles() : getTile(i).active) return true; - } - return false; -} - -template -template -inline bool -RootNode::isValueOnAndCache(const Coord& xyz, AccessorT& acc) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTileOff(iter)) return false; - if (isTileOn(iter)) return true; - acc.insert(xyz, &getChild(iter)); - return getChild(iter).isValueOnAndCache(xyz, acc); -} - - -template -inline const typename ChildT::ValueType& -RootNode::getValue(const Coord& xyz) const -{ - MapCIter iter = this->findCoord(xyz); - return iter == mTable.end() ? mBackground - : (isTile(iter) ? getTile(iter).value : getChild(iter).getValue(xyz)); -} - -template -template -inline const typename ChildT::ValueType& -RootNode::getValueAndCache(const Coord& xyz, AccessorT& acc) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end()) return mBackground; - if (isChild(iter)) { - acc.insert(xyz, &getChild(iter)); - return getChild(iter).getValueAndCache(xyz, acc); - } - return getTile(iter).value; -} - - -template -inline int -RootNode::getValueDepth(const Coord& xyz) const -{ - MapCIter iter = this->findCoord(xyz); - return iter == mTable.end() ? -1 - : (isTile(iter) ? 0 : int(LEVEL) - int(getChild(iter).getValueLevel(xyz))); -} - -template -template -inline int -RootNode::getValueDepthAndCache(const Coord& xyz, AccessorT& acc) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end()) return -1; - if (isTile(iter)) return 0; - acc.insert(xyz, &getChild(iter)); - return int(LEVEL) - int(getChild(iter).getValueLevelAndCache(xyz, acc)); -} - - -template -inline void -RootNode::setValueOff(const Coord& xyz) -{ - MapIter iter = this->findCoord(xyz); - if (iter != mTable.end() && !isTileOff(iter)) { - if (isTileOn(iter)) { - setChild(iter, *new ChildT(xyz, getTile(iter).value, /*active=*/true)); - } - getChild(iter).setValueOff(xyz); - } -} - - -template -inline void -RootNode::setActiveState(const Coord& xyz, bool on) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (on) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else { - // Nothing to do; (x, y, z) is background and therefore already inactive. - } - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (on != getTile(iter).active) { - child = new ChildT(xyz, getTile(iter).value, !on); - setChild(iter, *child); - } - if (child) child->setActiveState(xyz, on); -} - -template -template -inline void -RootNode::setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (on) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else { - // Nothing to do; (x, y, z) is background and therefore already inactive. - } - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (on != getTile(iter).active) { - child = new ChildT(xyz, getTile(iter).value, !on); - setChild(iter, *child); - } - if (child) { - acc.insert(xyz, child); - child->setActiveStateAndCache(xyz, on, acc); - } -} - - -template -inline void -RootNode::setValueOff(const Coord& xyz, const ValueType& value) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (!math::isExactlyEqual(mBackground, value)) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) child->setValueOff(xyz, value); -} - -template -template -inline void -RootNode::setValueOffAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (!math::isExactlyEqual(mBackground, value)) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (isTileOn(iter) || !math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) { - acc.insert(xyz, child); - child->setValueOffAndCache(xyz, value, acc); - } -} - - -template -inline void -RootNode::setValueOn(const Coord& xyz, const ValueType& value) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) child->setValueOn(xyz, value); -} - -template -template -inline void -RootNode::setValueAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (isTileOff(iter) || !math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) { - acc.insert(xyz, child); - child->setValueAndCache(xyz, value, acc); - } -} - - -template -inline void -RootNode::setValueOnly(const Coord& xyz, const ValueType& value) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (!math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) child->setValueOnly(xyz, value); -} - -template -template -inline void -RootNode::setValueOnlyAndCache(const Coord& xyz, const ValueType& value, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else if (!math::isExactlyEqual(getTile(iter).value, value)) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - if (child) { - acc.insert(xyz, child); - child->setValueOnlyAndCache(xyz, value, acc); - } -} - - -template -template -inline void -RootNode::modifyValue(const Coord& xyz, const ModifyOp& op) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - // Need to create a child if the tile is inactive, - // in order to activate voxel (x, y, z). - bool createChild = isTileOff(iter); - if (!createChild) { - // Need to create a child if applying the functor - // to the tile value produces a different value. - const ValueType& tileVal = getTile(iter).value; - ValueType modifiedVal = tileVal; - op(modifiedVal); - createChild = !math::isExactlyEqual(tileVal, modifiedVal); - } - if (createChild) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - } - if (child) child->modifyValue(xyz, op); -} - -template -template -inline void -RootNode::modifyValueAndCache(const Coord& xyz, const ModifyOp& op, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - // Need to create a child if the tile is inactive, - // in order to activate voxel (x, y, z). - bool createChild = isTileOff(iter); - if (!createChild) { - // Need to create a child if applying the functor - // to the tile value produces a different value. - const ValueType& tileVal = getTile(iter).value; - ValueType modifiedVal = tileVal; - op(modifiedVal); - createChild = !math::isExactlyEqual(tileVal, modifiedVal); - } - if (createChild) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - } - if (child) { - acc.insert(xyz, child); - child->modifyValueAndCache(xyz, op, acc); - } -} - - -template -template -inline void -RootNode::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - const Tile& tile = getTile(iter); - bool modifiedState = tile.active; - ValueType modifiedVal = tile.value; - op(modifiedVal, modifiedState); - // Need to create a child if applying the functor to the tile - // produces a different value or active state. - if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) { - child = new ChildT(xyz, tile.value, tile.active); - setChild(iter, *child); - } - } - if (child) child->modifyValueAndActiveState(xyz, op); -} - -template -template -inline void -RootNode::modifyValueAndActiveStateAndCache( - const Coord& xyz, const ModifyOp& op, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - const Tile& tile = getTile(iter); - bool modifiedState = tile.active; - ValueType modifiedVal = tile.value; - op(modifiedVal, modifiedState); - // Need to create a child if applying the functor to the tile - // produces a different value or active state. - if (modifiedState != tile.active || !math::isExactlyEqual(modifiedVal, tile.value)) { - child = new ChildT(xyz, tile.value, tile.active); - setChild(iter, *child); - } - } - if (child) { - acc.insert(xyz, child); - child->modifyValueAndActiveStateAndCache(xyz, op, acc); - } -} - - -template -inline bool -RootNode::probeValue(const Coord& xyz, ValueType& value) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - value = mBackground; - return false; - } else if (isChild(iter)) { - return getChild(iter).probeValue(xyz, value); - } - value = getTile(iter).value; - return isTileOn(iter); -} - -template -template -inline bool -RootNode::probeValueAndCache(const Coord& xyz, ValueType& value, AccessorT& acc) const -{ - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - value = mBackground; - return false; - } else if (isChild(iter)) { - acc.insert(xyz, &getChild(iter)); - return getChild(iter).probeValueAndCache(xyz, value, acc); - } - value = getTile(iter).value; - return isTileOn(iter); -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::fill(const CoordBBox& bbox, const ValueType& value, bool active) -{ - if (bbox.empty()) return; - - Coord xyz, tileMax; - for (int x = bbox.min().x(); x <= bbox.max().x(); x = tileMax.x() + 1) { - xyz.setX(x); - for (int y = bbox.min().y(); y <= bbox.max().y(); y = tileMax.y() + 1) { - xyz.setY(y); - for (int z = bbox.min().z(); z <= bbox.max().z(); z = tileMax.z() + 1) { - xyz.setZ(z); - - // Get the bounds of the tile that contains voxel (x, y, z). - Coord tileMin = coordToKey(xyz); - tileMax = tileMin.offsetBy(ChildT::DIM - 1); - - if (xyz != tileMin || Coord::lessThan(bbox.max(), tileMax)) { - // If the box defined by (xyz, bbox.max()) doesn't completely enclose - // the tile to which xyz belongs, create a child node (or retrieve - // the existing one). - ChildT* child = NULL; - MapIter iter = this->findKey(tileMin); - if (iter == mTable.end()) { - // No child or tile exists. Create a child and initialize it - // with the background value. - child = new ChildT(xyz, mBackground); - mTable[tileMin] = NodeStruct(*child); - } else if (isTile(iter)) { - // Replace the tile with a newly-created child that is initialized - // with the tile's value and active state. - const Tile& tile = getTile(iter); - child = new ChildT(xyz, tile.value, tile.active); - mTable[tileMin] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } - // Forward the fill request to the child. - if (child) { - child->fill(CoordBBox(xyz, Coord::minComponent(bbox.max(), tileMax)), - value, active); - } - } else { - // If the box given by (xyz, bbox.max()) completely encloses - // the tile to which xyz belongs, create the tile (if it - // doesn't already exist) and give it the fill value. - MapIter iter = this->findOrAddCoord(tileMin); - setTile(iter, Tile(value, active)); - } - } - } - } -} - -template -template -inline void -RootNode::copyToDense(const CoordBBox& bbox, DenseT& dense) const -{ - typedef typename DenseT::ValueType DenseValueType; - - const size_t xStride = dense.xStride(), yStride = dense.yStride(), zStride = dense.zStride(); - const Coord& min = dense.bbox().min(); - CoordBBox nodeBBox; - for (Coord xyz = bbox.min(); xyz[0] <= bbox.max()[0]; xyz[0] = nodeBBox.max()[0] + 1) { - for (xyz[1] = bbox.min()[1]; xyz[1] <= bbox.max()[1]; xyz[1] = nodeBBox.max()[1] + 1) { - for (xyz[2] = bbox.min()[2]; xyz[2] <= bbox.max()[2]; xyz[2] = nodeBBox.max()[2] + 1) { - - // Get the coordinate bbox of the child node that contains voxel xyz. - nodeBBox = CoordBBox::createCube(coordToKey(xyz), ChildT::DIM); - - // Get the coordinate bbox of the interection of inBBox and nodeBBox - CoordBBox sub(xyz, Coord::minComponent(bbox.max(), nodeBBox.max())); - - MapCIter iter = this->findKey(nodeBBox.min()); - if (iter != mTable.end() && isChild(iter)) {//is a child - getChild(iter).copyToDense(sub, dense); - } else {//is background or a tile value - const ValueType value = iter==mTable.end() ? mBackground : getTile(iter).value; - sub.translate(-min); - DenseValueType* a0 = dense.data() + zStride*sub.min()[2]; - for (Int32 x=sub.min()[0], ex=sub.max()[0]+1; x -inline bool -RootNode::writeTopology(std::ostream& os, bool toHalf) const -{ - if (!toHalf) { - os.write(reinterpret_cast(&mBackground), sizeof(ValueType)); - } else { - ValueType truncatedVal = io::truncateRealToHalf(mBackground); - os.write(reinterpret_cast(&truncatedVal), sizeof(ValueType)); - } - io::setGridBackgroundValuePtr(os, &mBackground); - - const Index numTiles = this->getTileCount(), numChildren = this->getChildCount(); - os.write(reinterpret_cast(&numTiles), sizeof(Index)); - os.write(reinterpret_cast(&numChildren), sizeof(Index)); - - if (numTiles == 0 && numChildren == 0) return false; - - // Write tiles. - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) continue; - os.write(reinterpret_cast(i->first.asPointer()), 3 * sizeof(Int32)); - os.write(reinterpret_cast(&getTile(i).value), sizeof(ValueType)); - os.write(reinterpret_cast(&getTile(i).active), sizeof(bool)); - } - // Write child nodes. - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isTile(i)) continue; - os.write(reinterpret_cast(i->first.asPointer()), 3 * sizeof(Int32)); - getChild(i).writeTopology(os, toHalf); - } - - return true; // not empty -} - - -template -inline bool -RootNode::readTopology(std::istream& is, bool fromHalf) -{ - // Delete the existing tree. - this->clearTable(); - - if (io::getFormatVersion(is) < OPENVDB_FILE_VERSION_ROOTNODE_MAP) { - // Read and convert an older-format RootNode. - - // For backward compatibility with older file formats, read both - // outside and inside background values. - is.read(reinterpret_cast(&mBackground), sizeof(ValueType)); - ValueType inside; - is.read(reinterpret_cast(&inside), sizeof(ValueType)); - - io::setGridBackgroundValuePtr(is, &mBackground); - - // Read the index range. - Coord rangeMin, rangeMax; - is.read(reinterpret_cast(rangeMin.asPointer()), 3 * sizeof(Int32)); - is.read(reinterpret_cast(rangeMax.asPointer()), 3 * sizeof(Int32)); - - this->initTable(); - Index tableSize = 0, log2Dim[4] = { 0, 0, 0, 0 }; - Int32 offset[3]; - for (int i = 0; i < 3; ++i) { - offset[i] = rangeMin[i] >> ChildT::TOTAL; - rangeMin[i] = offset[i] << ChildT::TOTAL; - log2Dim[i] = 1 + util::FindHighestOn((rangeMax[i] >> ChildT::TOTAL) - offset[i]); - tableSize += log2Dim[i]; - rangeMax[i] = (((1 << log2Dim[i]) + offset[i]) << ChildT::TOTAL) - 1; - } - log2Dim[3] = log2Dim[1] + log2Dim[2]; - tableSize = 1U << tableSize; - - // Read masks. - util::RootNodeMask childMask(tableSize), valueMask(tableSize); - childMask.load(is); - valueMask.load(is); - - // Read child nodes/values. - for (Index i = 0; i < tableSize; ++i) { - // Compute origin = offset2coord(i). - Index n = i; - Coord origin; - origin[0] = (n >> log2Dim[3]) + offset[0]; - n &= (1U << log2Dim[3]) - 1; - origin[1] = (n >> log2Dim[2]) + offset[1]; - origin[2] = (n & ((1U << log2Dim[2]) - 1)) + offset[1]; - origin <<= ChildT::TOTAL; - - if (childMask.isOn(i)) { - // Read in and insert a child node. -#ifdef OPENVDB_2_ABI_COMPATIBLE - ChildT* child = new ChildT(origin, mBackground); -#else - ChildT* child = new ChildT(PartialCreate(), origin, mBackground); -#endif - child->readTopology(is); - mTable[origin] = NodeStruct(*child); - } else { - // Read in a tile value and insert a tile, but only if the value - // is either active or non-background. - ValueType value; - is.read(reinterpret_cast(&value), sizeof(ValueType)); - if (valueMask.isOn(i) || (!math::isApproxEqual(value, mBackground))) { - mTable[origin] = NodeStruct(Tile(value, valueMask.isOn(i))); - } - } - } - return true; - } - - // Read a RootNode that was stored in the current format. - - is.read(reinterpret_cast(&mBackground), sizeof(ValueType)); - io::setGridBackgroundValuePtr(is, &mBackground); - - Index numTiles = 0, numChildren = 0; - is.read(reinterpret_cast(&numTiles), sizeof(Index)); - is.read(reinterpret_cast(&numChildren), sizeof(Index)); - - if (numTiles == 0 && numChildren == 0) return false; - - Int32 vec[3]; - ValueType value; - bool active; - - // Read tiles. - for (Index n = 0; n < numTiles; ++n) { - is.read(reinterpret_cast(vec), 3 * sizeof(Int32)); - is.read(reinterpret_cast(&value), sizeof(ValueType)); - is.read(reinterpret_cast(&active), sizeof(bool)); - mTable[Coord(vec)] = NodeStruct(Tile(value, active)); - } - - // Read child nodes. - for (Index n = 0; n < numChildren; ++n) { - is.read(reinterpret_cast(vec), 3 * sizeof(Int32)); - Coord origin(vec); -#ifdef OPENVDB_2_ABI_COMPATIBLE - ChildT* child = new ChildT(origin, mBackground); -#else - ChildT* child = new ChildT(PartialCreate(), origin, mBackground); -#endif - child->readTopology(is, fromHalf); - mTable[Coord(vec)] = NodeStruct(*child); - } - - return true; // not empty -} - - -template -inline void -RootNode::writeBuffers(std::ostream& os, bool toHalf) const -{ - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) getChild(i).writeBuffers(os, toHalf); - } -} - - -template -inline void -RootNode::readBuffers(std::istream& is, bool fromHalf) -{ - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) getChild(i).readBuffers(is, fromHalf); - } -} - - -template -inline void -RootNode::readBuffers(std::istream& is, const CoordBBox& clipBBox, bool fromHalf) -{ - const Tile bgTile(mBackground, /*active=*/false); - - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (isChild(i)) { - // Stream in and clip the branch rooted at this child. - // (We can't skip over children that lie outside the clipping region, - // because buffers are serialized in depth-first order and need to be - // unserialized in the same order.) - ChildT& child = getChild(i); - child.readBuffers(is, clipBBox, fromHalf); - } - } - // Clip root-level tiles and prune children that were clipped. - this->clip(clipBBox); -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::clip(const CoordBBox& clipBBox) -{ - const Tile bgTile(mBackground, /*active=*/false); - - // Iterate over a copy of this node's table so that we can modify the original. - // (Copying the table copies child node pointers, not the nodes themselves.) - MapType copyOfTable(mTable); - for (MapIter i = copyOfTable.begin(), e = copyOfTable.end(); i != e; ++i) { - const Coord& xyz = i->first; // tile or child origin - CoordBBox tileBBox(xyz, xyz.offsetBy(ChildT::DIM - 1)); // tile or child bounds - if (!clipBBox.hasOverlap(tileBBox)) { - // This table entry lies completely outside the clipping region. Delete it. - setTile(this->findCoord(xyz), bgTile); // delete any existing child node first - mTable.erase(xyz); - } else if (!clipBBox.isInside(tileBBox)) { - // This table entry does not lie completely inside the clipping region - // and must be clipped. - if (isChild(i)) { - getChild(i).clip(clipBBox, mBackground); - } else { - // Replace this tile with a background tile, then fill the clip region - // with the tile's original value. (This might create a child branch.) - tileBBox.intersect(clipBBox); - const Tile& origTile = getTile(i); - setTile(this->findCoord(xyz), bgTile); - this->fill(tileBBox, origTile.value, origTile.active); - } - } else { - // This table entry lies completely inside the clipping region. Leave it intact. - } - } - this->prune(); // also erases root-level background tiles -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::prune(const ValueType& tolerance) -{ - bool state = false; - ValueType value = zeroVal(); - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (this->isTile(i)) continue; - this->getChild(i).prune(tolerance); - if (this->getChild(i).isConstant(value, state, tolerance)) { - this->setTile(i, Tile(value, state)); - } - } - this->eraseBackgroundTiles(); -} - - -//////////////////////////////////////// - - -template -template -inline NodeT* -RootNode::stealNode(const Coord& xyz, const ValueType& value, bool state) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTile(iter)) return NULL; - return (boost::is_same::value) - ? reinterpret_cast(&stealChild(iter, Tile(value, state))) - : getChild(iter).template stealNode(xyz, value, state); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::addLeaf(LeafNodeType* leaf) -{ - if (leaf == NULL) return; - ChildT* child = NULL; - const Coord& xyz = leaf->origin(); - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, mBackground, false); - } else { - child = reinterpret_cast(leaf); - } - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - if (ChildT::LEVEL>0) { - child = &getChild(iter); - } else { - child = reinterpret_cast(leaf); - setChild(iter, *child);//this also deletes the existing child node - } - } else {//tile - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - } else { - child = reinterpret_cast(leaf); - } - setChild(iter, *child); - } - child->addLeaf(leaf); -} - - -template -template -inline void -RootNode::addLeafAndCache(LeafNodeType* leaf, AccessorT& acc) -{ - if (leaf == NULL) return; - ChildT* child = NULL; - const Coord& xyz = leaf->origin(); - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, mBackground, false); - } else { - child = reinterpret_cast(leaf); - } - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - if (ChildT::LEVEL>0) { - child = &getChild(iter); - } else { - child = reinterpret_cast(leaf); - setChild(iter, *child);//this also deletes the existing child node - } - } else {//tile - if (ChildT::LEVEL>0) { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - } else { - child = reinterpret_cast(leaf); - } - setChild(iter, *child); - } - acc.insert(xyz, child); - child->addLeafAndCache(leaf, acc); -} - -template -inline void -RootNode::addTile(const Coord& xyz, const ValueType& value, bool state) -{ - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) {//background - mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state)); - } else {//child or tile - setTile(iter, Tile(value, state));//this also deletes the existing child node - } -} - -template -inline void -RootNode::addTile(Index level, const Coord& xyz, - const ValueType& value, bool state) -{ - if (LEVEL >= level) { - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) {//background - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, mBackground, false); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - child->addTile(level, xyz, value, state); - } else { - mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state)); - } - } else if (isChild(iter)) {//child - if (LEVEL > level) { - getChild(iter).addTile(level, xyz, value, state); - } else { - setTile(iter, Tile(value, state));//this also deletes the existing child node - } - } else {//tile - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - child->addTile(level, xyz, value, state); - } else { - setTile(iter, Tile(value, state)); - } - } - } -} - - -template -template -inline void -RootNode::addTileAndCache(Index level, const Coord& xyz, const ValueType& value, - bool state, AccessorT& acc) -{ - if (LEVEL >= level) { - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) {//background - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, mBackground, false); - acc.insert(xyz, child); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - child->addTileAndCache(level, xyz, value, state, acc); - } else { - mTable[this->coordToKey(xyz)] = NodeStruct(Tile(value, state)); - } - } else if (isChild(iter)) {//child - if (LEVEL > level) { - ChildT* child = &getChild(iter); - acc.insert(xyz, child); - child->addTileAndCache(level, xyz, value, state, acc); - } else { - setTile(iter, Tile(value, state));//this also deletes the existing child node - } - } else {//tile - if (LEVEL > level) { - ChildT* child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - acc.insert(xyz, child); - setChild(iter, *child); - child->addTileAndCache(level, xyz, value, state, acc); - } else { - setTile(iter, Tile(value, state)); - } - } - } -} - - -//////////////////////////////////////// - - -template -inline typename ChildT::LeafNodeType* -RootNode::touchLeaf(const Coord& xyz) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground, false); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - return child->touchLeaf(xyz); -} - - -template -template -inline typename ChildT::LeafNodeType* -RootNode::touchLeafAndCache(const Coord& xyz, AccessorT& acc) -{ - ChildT* child = NULL; - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end()) { - child = new ChildT(xyz, mBackground, false); - mTable[this->coordToKey(xyz)] = NodeStruct(*child); - } else if (isChild(iter)) { - child = &getChild(iter); - } else { - child = new ChildT(xyz, getTile(iter).value, isTileOn(iter)); - setChild(iter, *child); - } - acc.insert(xyz, child); - return child->touchLeafAndCache(xyz, acc); -} - - -//////////////////////////////////////// - - -template -template -inline NodeT* -RootNode::probeNode(const Coord& xyz) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTile(iter)) return NULL; - ChildT* child = &getChild(iter); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline const NodeT* -RootNode::probeConstNode(const Coord& xyz) const -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTile(iter)) return NULL; - const ChildT* child = &getChild(iter); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeConstNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -inline typename ChildT::LeafNodeType* -RootNode::probeLeaf(const Coord& xyz) -{ - return this->template probeNode(xyz); -} - - -template -inline const typename ChildT::LeafNodeType* -RootNode::probeConstLeaf(const Coord& xyz) const -{ - return this->template probeConstNode(xyz); -} - - -template -template -inline typename ChildT::LeafNodeType* -RootNode::probeLeafAndCache(const Coord& xyz, AccessorT& acc) -{ - return this->template probeNodeAndCache(xyz, acc); -} - - -template -template -inline const typename ChildT::LeafNodeType* -RootNode::probeConstLeafAndCache(const Coord& xyz, AccessorT& acc) const -{ - return this->template probeConstNodeAndCache(xyz, acc); -} - - -template -template -inline const typename ChildT::LeafNodeType* -RootNode::probeLeafAndCache(const Coord& xyz, AccessorT& acc) const -{ - return this->probeConstLeafAndCache(xyz, acc); -} - - -template -template -inline NodeT* -RootNode::probeNodeAndCache(const Coord& xyz, AccessorT& acc) -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - MapIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTile(iter)) return NULL; - ChildT* child = &getChild(iter); - acc.insert(xyz, child); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeNodeAndCache(xyz, acc); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -template -template -inline const NodeT* -RootNode::probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const -{ - if ((NodeT::LEVEL == ChildT::LEVEL && !(boost::is_same::value)) || - NodeT::LEVEL > ChildT::LEVEL) return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - MapCIter iter = this->findCoord(xyz); - if (iter == mTable.end() || isTile(iter)) return NULL; - const ChildT* child = &getChild(iter); - acc.insert(xyz, child); - return (boost::is_same::value) - ? reinterpret_cast(child) - : child->template probeConstNodeAndCache(xyz, acc); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - -template -template -inline void -RootNode::getNodes(ArrayT& array) -{ - typedef typename ArrayT::value_type NodePtr; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - typedef typename boost::remove_pointer::type NodeType; - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::mpl::contains::type result; - BOOST_STATIC_ASSERT(result::value); - typedef typename boost::mpl::if_, - const ChildT, ChildT>::type ArrayChildT; - - for (MapIter iter=mTable.begin(); iter!=mTable.end(); ++iter) { - if (ChildT* child = iter->second.child) { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.push_back(reinterpret_cast(iter->second.child)); - } else { - child->getNodes(array);//descent - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - } -} - -template -template -inline void -RootNode::getNodes(ArrayT& array) const -{ - typedef typename ArrayT::value_type NodePtr; - BOOST_STATIC_ASSERT(boost::is_pointer::value); - typedef typename boost::remove_pointer::type NodeType; - BOOST_STATIC_ASSERT(boost::is_const::value); - typedef typename boost::remove_const::type NonConstNodeType; - typedef typename boost::mpl::contains::type result; - BOOST_STATIC_ASSERT(result::value); - - for (MapCIter iter=mTable.begin(); iter!=mTable.end(); ++iter) { - if (const ChildNodeType *child = iter->second.child) { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (boost::is_same::value) { - array.push_back(reinterpret_cast(iter->second.child)); - } else { - child->getNodes(array);//descent - } - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - } -} - - -//////////////////////////////////////// - - -template -inline void -RootNode::voxelizeActiveTiles() -{ - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (this->isTileOff(i)) continue; - ChildT* child = i->second.child; - if (child==NULL) { - child = new ChildT(i->first, this->getTile(i).value, true); - i->second.child = child; - } - child->voxelizeActiveTiles(); - } -} - - -//////////////////////////////////////// - - -template -template -inline void -RootNode::merge(RootNode& other) -{ - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - - switch (Policy) { - - default: - case MERGE_ACTIVE_STATES: - for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - MapIter j = mTable.find(i->first); - if (other.isChild(i)) { - if (j == mTable.end()) { // insert other node's child - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - mTable[i->first] = NodeStruct(child); - } else if (isTile(j)) { - if (isTileOff(j)) { // replace inactive tile with other node's child - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - setChild(j, child); - } - } else { // merge both child nodes - getChild(j).template merge(getChild(i), - other.mBackground, mBackground); - } - } else if (other.isTileOn(i)) { - if (j == mTable.end()) { // insert other node's active tile - mTable[i->first] = i->second; - } else if (!isTileOn(j)) { - // Replace anything except an active tile with the other node's active tile. - setTile(j, Tile(other.getTile(i).value, true)); - } - } - } - break; - - case MERGE_NODES: - for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - MapIter j = mTable.find(i->first); - if (other.isChild(i)) { - if (j == mTable.end()) { // insert other node's child - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - mTable[i->first] = NodeStruct(child); - } else if (isTile(j)) { // replace tile with other node's child - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - setChild(j, child); - } else { // merge both child nodes - getChild(j).template merge( - getChild(i), other.mBackground, mBackground); - } - } - } - break; - - case MERGE_ACTIVE_STATES_AND_NODES: - for (MapIter i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - MapIter j = mTable.find(i->first); - if (other.isChild(i)) { - if (j == mTable.end()) { - // Steal and insert the other node's child. - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - mTable[i->first] = NodeStruct(child); - } else if (isTile(j)) { - // Replace this node's tile with the other node's child. - ChildNodeType& child = stealChild(i, Tile(other.mBackground, /*on=*/false)); - child.resetBackground(other.mBackground, mBackground); - const Tile tile = getTile(j); - setChild(j, child); - if (tile.active) { - // Merge the other node's child with this node's active tile. - child.template merge( - tile.value, tile.active); - } - } else /*if (isChild(j))*/ { - // Merge the other node's child into this node's child. - getChild(j).template merge(getChild(i), - other.mBackground, mBackground); - } - } else if (other.isTileOn(i)) { - if (j == mTable.end()) { - // Insert a copy of the other node's active tile. - mTable[i->first] = i->second; - } else if (isTileOff(j)) { - // Replace this node's inactive tile with a copy of the other's active tile. - setTile(j, Tile(other.getTile(i).value, true)); - } else if (isChild(j)) { - // Merge the other node's active tile into this node's child. - const Tile& tile = getTile(i); - getChild(j).template merge( - tile.value, tile.active); - } - } // else if (other.isTileOff(i)) {} // ignore the other node's inactive tiles - } - break; - } - - // Empty the other tree so as not to leave it in a partially cannibalized state. - other.clear(); - - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END -} - - -//////////////////////////////////////// - - -template -template -inline void -RootNode::topologyUnion(const RootNode& other) -{ - typedef RootNode OtherRootT; - typedef typename OtherRootT::MapCIter OtherCIterT; - - enforceSameConfiguration(other); - - for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - MapIter j = mTable.find(i->first); - if (other.isChild(i)) { - if (j == mTable.end()) { // create child branch with identical topology - mTable[i->first] = NodeStruct( - *(new ChildT(other.getChild(i), mBackground, TopologyCopy()))); - } else if (this->isChild(j)) { // union with child branch - this->getChild(j).topologyUnion(other.getChild(i)); - } else {// this is a tile so replace it with a child branch with identical topology - ChildT* child = new ChildT( - other.getChild(i), this->getTile(j).value, TopologyCopy()); - if (this->isTileOn(j)) child->setValuesOn();//this is an active tile - this->setChild(j, *child); - } - } else if (other.isTileOn(i)) { // other is an active tile - if (j == mTable.end()) { // insert an active tile - mTable[i->first] = NodeStruct(Tile(mBackground, true)); - } else if (this->isChild(j)) { - this->getChild(j).setValuesOn(); - } else if (this->isTileOff(j)) { - this->setTile(j, Tile(this->getTile(j).value, true)); - } - } - } -} - -template -template -inline void -RootNode::topologyIntersection(const RootNode& other) -{ - typedef RootNode OtherRootT; - typedef typename OtherRootT::MapCIter OtherCIterT; - - enforceSameConfiguration(other); - - std::set tmp;//keys to erase - for (MapIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - OtherCIterT j = other.mTable.find(i->first); - if (this->isChild(i)) { - if (j == other.mTable.end() || other.isTileOff(j)) { - tmp.insert(i->first);//delete child branch - } else if (other.isChild(j)) { // intersect with child branch - this->getChild(i).topologyIntersection(other.getChild(j), mBackground); - } - } else if (this->isTileOn(i)) { - if (j == other.mTable.end() || other.isTileOff(j)) { - this->setTile(i, Tile(this->getTile(i).value, false));//turn inactive - } else if (other.isChild(j)) { //replace with a child branch with identical topology - ChildT* child = - new ChildT(other.getChild(j), this->getTile(i).value, TopologyCopy()); - this->setChild(i, *child); - } - } - } - for (std::set::iterator i = tmp.begin(), e = tmp.end(); i != e; ++i) { - MapIter it = this->findCoord(*i); - setTile(it, Tile()); // delete any existing child node first - mTable.erase(it); - } -} - -template -template -inline void -RootNode::topologyDifference(const RootNode& other) -{ - typedef RootNode OtherRootT; - typedef typename OtherRootT::MapCIter OtherCIterT; - - enforceSameConfiguration(other); - - for (OtherCIterT i = other.mTable.begin(), e = other.mTable.end(); i != e; ++i) { - MapIter j = mTable.find(i->first); - if (other.isChild(i)) { - if (j == mTable.end() || this->isTileOff(j)) { - //do nothing - } else if (this->isChild(j)) { // difference with child branch - this->getChild(j).topologyDifference(other.getChild(i), mBackground); - } else if (this->isTileOn(j)) { - // this is an active tile so create a child node and descent - ChildT* child = new ChildT(j->first, this->getTile(j).value, true); - child->topologyDifference(other.getChild(i), mBackground); - this->setChild(j, *child); - } - } else if (other.isTileOn(i)) { // other is an active tile - if (j == mTable.end() || this->isTileOff(j)) { - // do nothing - } else if (this->isChild(j)) { - setTile(j, Tile()); // delete any existing child node first - mTable.erase(j); - } else if (this->isTileOn(j)) { - this->setTile(j, Tile(this->getTile(j).value, false)); - } - } - } -} - -//////////////////////////////////////// - - -template -template -inline void -RootNode::combine(RootNode& other, CombineOp& op, bool prune) -{ - CombineArgs args; - - CoordSet keys; - this->insertKeys(keys); - other.insertKeys(keys); - - for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) { - MapIter iter = findOrAddCoord(*i), otherIter = other.findOrAddCoord(*i); - if (isTile(iter) && isTile(otherIter)) { - // Both this node and the other node have constant values (tiles). - // Combine the two values and store the result as this node's new tile value. - op(args.setARef(getTile(iter).value) - .setAIsActive(isTileOn(iter)) - .setBRef(getTile(otherIter).value) - .setBIsActive(isTileOn(otherIter))); - setTile(iter, Tile(args.result(), args.resultIsActive())); - - } else if (isChild(iter) && isTile(otherIter)) { - // Combine this node's child with the other node's constant value. - ChildT& child = getChild(iter); - child.combine(getTile(otherIter).value, isTileOn(otherIter), op); - - } else if (isTile(iter) && isChild(otherIter)) { - // Combine this node's constant value with the other node's child, - // but use a new functor in which the A and B values are swapped, - // since the constant value is the A value, not the B value. - SwappedCombineOp swappedOp(op); - ChildT& child = getChild(otherIter); - child.combine(getTile(iter).value, isTileOn(iter), swappedOp); - - // Steal the other node's child. - setChild(iter, stealChild(otherIter, Tile())); - - } else /*if (isChild(iter) && isChild(otherIter))*/ { - // Combine this node's child with the other node's child. - ChildT &child = getChild(iter), &otherChild = getChild(otherIter); - child.combine(otherChild, op); - } - if (prune && isChild(iter)) getChild(iter).prune(); - } - - // Combine background values. - op(args.setARef(mBackground).setBRef(other.mBackground)); - mBackground = args.result(); - - // Empty the other tree so as not to leave it in a partially cannibalized state. - other.clear(); -} - - -//////////////////////////////////////// - - -// This helper class is a friend of RootNode and is needed so that combine2 -// can be specialized for compatible and incompatible pairs of RootNode types. -template -struct RootNodeCombineHelper -{ - static inline void combine2(RootT& self, const RootT&, const OtherRootT& other1, - CombineOp&, bool) - { - // If the two root nodes have different configurations or incompatible ValueTypes, - // throw an exception. - self.enforceSameConfiguration(other1); - self.enforceCompatibleValueTypes(other1); - // One of the above two tests should throw, so we should never get here: - std::ostringstream ostr; - ostr << "cannot combine a " << typeid(OtherRootT).name() - << " into a " << typeid(RootT).name(); - OPENVDB_THROW(TypeError, ostr.str()); - } -}; - -// Specialization for root nodes of compatible types -template -struct RootNodeCombineHelper -{ - static inline void combine2(RootT& self, const RootT& other0, const OtherRootT& other1, - CombineOp& op, bool prune) - { - self.doCombine2(other0, other1, op, prune); - } -}; - - -template -template -inline void -RootNode::combine2(const RootNode& other0, const OtherRootNode& other1, - CombineOp& op, bool prune) -{ - typedef typename OtherRootNode::ValueType OtherValueType; - static const bool compatible = (SameConfiguration::value - && CanConvertType::value); - RootNodeCombineHelper::combine2( - *this, other0, other1, op, prune); -} - - -template -template -inline void -RootNode::doCombine2(const RootNode& other0, const OtherRootNode& other1, - CombineOp& op, bool prune) -{ - enforceSameConfiguration(other1); - - typedef typename OtherRootNode::ValueType OtherValueT; - typedef typename OtherRootNode::Tile OtherTileT; - typedef typename OtherRootNode::NodeStruct OtherNodeStructT; - typedef typename OtherRootNode::MapCIter OtherMapCIterT; - - CombineArgs args; - - CoordSet keys; - other0.insertKeys(keys); - other1.insertKeys(keys); - - const NodeStruct bg0(Tile(other0.mBackground, /*active=*/false)); - const OtherNodeStructT bg1(OtherTileT(other1.mBackground, /*active=*/false)); - - for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) { - MapIter thisIter = this->findOrAddCoord(*i); - MapCIter iter0 = other0.findKey(*i); - OtherMapCIterT iter1 = other1.findKey(*i); - const NodeStruct& ns0 = (iter0 != other0.mTable.end()) ? iter0->second : bg0; - const OtherNodeStructT& ns1 = (iter1 != other1.mTable.end()) ? iter1->second : bg1; - if (ns0.isTile() && ns1.isTile()) { - // Both input nodes have constant values (tiles). - // Combine the two values and add a new tile to this node with the result. - op(args.setARef(ns0.tile.value) - .setAIsActive(ns0.isTileOn()) - .setBRef(ns1.tile.value) - .setBIsActive(ns1.isTileOn())); - setTile(thisIter, Tile(args.result(), args.resultIsActive())); - } else { - if (!isChild(thisIter)) { - // Add a new child with the same coordinates, etc. as the other node's child. - const Coord& childOrigin = - ns0.isChild() ? ns0.child->origin() : ns1.child->origin(); - setChild(thisIter, *(new ChildT(childOrigin, getTile(thisIter).value))); - } - ChildT& child = getChild(thisIter); - - if (ns0.isTile()) { - // Combine node1's child with node0's constant value - // and write the result into this node's child. - child.combine2(ns0.tile.value, *ns1.child, ns0.isTileOn(), op); - } else if (ns1.isTile()) { - // Combine node0's child with node1's constant value - // and write the result into this node's child. - child.combine2(*ns0.child, ns1.tile.value, ns1.isTileOn(), op); - } else { - // Combine node0's child with node1's child - // and write the result into this node's child. - child.combine2(*ns0.child, *ns1.child, op); - } - } - if (prune && isChild(thisIter)) getChild(thisIter).prune(); - } - - // Combine background values. - op(args.setARef(other0.mBackground).setBRef(other1.mBackground)); - mBackground = args.result(); -} - - -//////////////////////////////////////// - - -template -template -inline void -RootNode::visitActiveBBox(BBoxOp& op) const -{ - const bool descent = op.template descent(); - for (MapCIter i = mTable.begin(), e = mTable.end(); i != e; ++i) { - if (this->isTileOff(i)) continue; - if (this->isChild(i) && descent) { - this->getChild(i).visitActiveBBox(op); - } else { -#ifdef _MSC_VER - op.operator()(CoordBBox::createCube(i->first, ChildT::DIM)); -#else - op.template operator()(CoordBBox::createCube(i->first, ChildT::DIM)); -#endif - } - } -} - - -template -template -inline void -RootNode::visit(VisitorOp& op) -{ - doVisit(*this, op); -} - - -template -template -inline void -RootNode::visit(VisitorOp& op) const -{ - doVisit(*this, op); -} - - -template -template -inline void -RootNode::doVisit(RootNodeT& self, VisitorOp& op) -{ - typename RootNodeT::ValueType val; - for (ChildAllIterT iter = self.beginChildAll(); iter; ++iter) { - if (op(iter)) continue; - if (typename ChildAllIterT::ChildNodeType* child = iter.probeChild(val)) { - child->visit(op); - } - } -} - - -//////////////////////////////////////// - - -template -template -inline void -RootNode::visit2(OtherRootNodeType& other, VisitorOp& op) -{ - doVisit2(*this, other, op); -} - - -template -template -inline void -RootNode::visit2(OtherRootNodeType& other, VisitorOp& op) const -{ - doVisit2(*this, other, op); -} - - -template -template< - typename RootNodeT, - typename OtherRootNodeT, - typename VisitorOp, - typename ChildAllIterT, - typename OtherChildAllIterT> -inline void -RootNode::doVisit2(RootNodeT& self, OtherRootNodeT& other, VisitorOp& op) -{ - enforceSameConfiguration(other); - - typename RootNodeT::ValueType val; - typename OtherRootNodeT::ValueType otherVal; - - // The two nodes are required to have corresponding table entries, - // but since that might require background tiles to be added to one or both, - // and the nodes might be const, we operate on shallow copies of the nodes instead. - RootNodeT copyOfSelf(self.mBackground); - copyOfSelf.mTable = self.mTable; - OtherRootNodeT copyOfOther(other.mBackground); - copyOfOther.mTable = other.mTable; - - // Add background tiles to both nodes as needed. - CoordSet keys; - self.insertKeys(keys); - other.insertKeys(keys); - for (CoordSetCIter i = keys.begin(), e = keys.end(); i != e; ++i) { - copyOfSelf.findOrAddCoord(*i); - copyOfOther.findOrAddCoord(*i); - } - - ChildAllIterT iter = copyOfSelf.beginChildAll(); - OtherChildAllIterT otherIter = copyOfOther.beginChildAll(); - - for ( ; iter && otherIter; ++iter, ++otherIter) - { - const size_t skipBranch = static_cast(op(iter, otherIter)); - - typename ChildAllIterT::ChildNodeType* child = - (skipBranch & 1U) ? NULL : iter.probeChild(val); - typename OtherChildAllIterT::ChildNodeType* otherChild = - (skipBranch & 2U) ? NULL : otherIter.probeChild(otherVal); - - if (child != NULL && otherChild != NULL) { - child->visit2Node(*otherChild, op); - } else if (child != NULL) { - child->visit2(otherIter, op); - } else if (otherChild != NULL) { - otherChild->visit2(iter, op, /*otherIsLHS=*/true); - } - } - // Remove any background tiles that were added above, - // as well as any that were created by the visitors. - copyOfSelf.eraseBackgroundTiles(); - copyOfOther.eraseBackgroundTiles(); - - // If either input node is non-const, replace its table with - // the (possibly modified) copy. - self.resetTable(copyOfSelf.mTable); - other.resetTable(copyOfOther.mTable); -} - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_ROOTNODE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/Tree.h b/openvdb_3_0_0_library/tree/Tree.h deleted file mode 100755 index ecda765..0000000 --- a/openvdb_3_0_0_library/tree/Tree.h +++ /dev/null @@ -1,2254 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file tree/Tree.h - -#ifndef OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "RootNode.h" -#include "InternalNode.h" -#include "LeafNode.h" -#include "TreeIterator.h" -#include "ValueAccessor.h" - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -/// @brief Base class for typed trees -class OPENVDB_API TreeBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - TreeBase() {} - virtual ~TreeBase() {} - - /// Return the name of this tree's type. - virtual const Name& type() const = 0; - - /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d"). - virtual Name valueType() const = 0; - - /// Return a pointer to a deep copy of this tree - virtual TreeBase::Ptr copy() const = 0; - - // - // Tree methods - // - /// @brief Return this tree's background value wrapped as metadata. - /// @note Query the metadata object for the value's type. - virtual Metadata::Ptr getBackgroundValue() const { return Metadata::Ptr(); } - - /// @brief Return in @a bbox the axis-aligned bounding box of all - /// leaf nodes and active tiles. - /// @details This is faster then calling evalActiveVoxelBoundingBox, - /// which visits the individual active voxels, and hence - /// evalLeafBoundingBox produces a less tight, i.e. approximate, bbox. - /// @return @c false if the bounding box is empty (in which case - /// the bbox is set to its default value). - virtual bool evalLeafBoundingBox(CoordBBox& bbox) const = 0; - - /// @brief Return in @a dim the dimensions of the axis-aligned bounding box - /// of all leaf nodes. - /// @return @c false if the bounding box is empty. - virtual bool evalLeafDim(Coord& dim) const = 0; - - /// @brief Return in @a bbox the axis-aligned bounding box of all - /// active voxels and tiles. - /// @details This method produces a more accurate, i.e. tighter, - /// bounding box than evalLeafBoundingBox which is approximate but - /// faster. - /// @return @c false if the bounding box is empty (in which case - /// the bbox is set to its default value). - virtual bool evalActiveVoxelBoundingBox(CoordBBox& bbox) const = 0; - - /// @brief Return in @a dim the dimensions of the axis-aligned bounding box of all - /// active voxels. This is a tighter bounding box than the leaf node bounding box. - /// @return @c false if the bounding box is empty. - virtual bool evalActiveVoxelDim(Coord& dim) const = 0; - - virtual void getIndexRange(CoordBBox& bbox) const = 0; - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Replace with background tiles any nodes whose voxel buffers - /// have not yet been allocated. - /// @details Typically, unallocated nodes are leaf nodes whose voxel buffers - /// are not yet resident in memory because delayed loading is in effect. - /// @sa readNonresidentBuffers, io::File::open - virtual void clipUnallocatedNodes() = 0; -#endif - - - // - // Statistics - // - /// @brief Return the depth of this tree. - /// - /// A tree with only a root node and leaf nodes has depth 2, for example. - virtual Index treeDepth() const = 0; - /// Return the number of leaf nodes. - virtual Index32 leafCount() const = 0; - /// Return the number of non-leaf nodes. - virtual Index32 nonLeafCount() const = 0; - /// Return the number of active voxels stored in leaf nodes. - virtual Index64 activeLeafVoxelCount() const = 0; - /// Return the number of inactive voxels stored in leaf nodes. - virtual Index64 inactiveLeafVoxelCount() const = 0; - /// Return the total number of active voxels. - virtual Index64 activeVoxelCount() const = 0; - /// Return the number of inactive voxels within the bounding box of all active voxels. - virtual Index64 inactiveVoxelCount() const = 0; -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Return the total number of active tiles. - virtual Index64 activeTileCount() const = 0; -#endif - - /// Return the total amount of memory in bytes occupied by this tree. - virtual Index64 memUsage() const { return 0; } - - - // - // I/O methods - // - /// @brief Read the tree topology from a stream. - /// - /// This will read the tree structure and tile values, but not voxel data. - virtual void readTopology(std::istream&, bool saveFloatAsHalf = false); - /// @brief Write the tree topology to a stream. - /// - /// This will write the tree structure and tile values, but not voxel data. - virtual void writeTopology(std::ostream&, bool saveFloatAsHalf = false) const; - - /// Read all data buffers for this tree. - virtual void readBuffers(std::istream&, bool saveFloatAsHalf = false) = 0; -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Read all of this tree's data buffers that intersect the given bounding box. - virtual void readBuffers(std::istream&, const CoordBBox&, bool saveFloatAsHalf = false) = 0; - /// @brief Read all of this tree's data buffers that are not yet resident in memory - /// (because delayed loading is in effect). - /// @details If this tree was read from a memory-mapped file, this operation - /// disconnects the tree from the file. - /// @sa clipUnallocatedNodes, io::File::open, io::MappedFile - virtual void readNonresidentBuffers() const = 0; -#endif - /// Write out all the data buffers for this tree. - virtual void writeBuffers(std::ostream&, bool saveFloatAsHalf = false) const = 0; - - /// @brief Print statistics, memory usage and other information about this tree. - /// @param os a stream to which to write textual information - /// @param verboseLevel 1: print tree configuration only; - /// 2: include node and voxel statistics; - /// 3: include memory usage; - /// 4: include minimum and maximum voxel values - /// @warning @a verboseLevel 4 forces loading of any unallocated nodes. - virtual void print(std::ostream& os = std::cout, int verboseLevel = 1) const; - -private: - // Disallow copying of instances of this class. - //TreeBase(const TreeBase& other); - TreeBase& operator=(const TreeBase& other); -}; - - -//////////////////////////////////////// - - -template -class Tree: public TreeBase -{ -public: - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - typedef _RootNodeType RootNodeType; - typedef typename RootNodeType::ValueType ValueType; - typedef typename RootNodeType::LeafNodeType LeafNodeType; - - static const Index DEPTH = RootNodeType::LEVEL + 1; - - /// @brief ValueConverter::Type is the type of a tree having the same - /// hierarchy as this tree but a different value type, T. - /// - /// For example, FloatTree::ValueConverter::Type is equivalent to DoubleTree. - /// @note If the source tree type is a template argument, it might be necessary - /// to write "typename SourceTree::template ValueConverter::Type". - template - struct ValueConverter { - typedef Tree::Type> Type; - }; - - - Tree() {} - - /// Deep copy constructor - Tree(const Tree& other): TreeBase(other), mRoot(other.mRoot) - { - } - - /// @brief Value conversion deep copy constructor - /// - /// Deep copy a tree of the same configuration as this tree type but a different - /// ValueType, casting the other tree's values to this tree's ValueType. - /// @throw TypeError if the other tree's configuration doesn't match this tree's - /// or if this tree's ValueType is not constructible from the other tree's ValueType. - template - explicit Tree(const Tree& other): TreeBase(other), mRoot(other.root()) - { - } - - /// @brief Topology copy constructor from a tree of a different type - /// - /// Copy the structure, i.e., the active states of tiles and voxels, of another - /// tree of a possibly different type, but don't copy any tile or voxel values. - /// Instead, initialize tiles and voxels with the given active and inactive values. - /// @param other a tree having (possibly) a different ValueType - /// @param inactiveValue background value for this tree, and the value to which - /// all inactive tiles and voxels are initialized - /// @param activeValue value to which active tiles and voxels are initialized - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - template - Tree(const OtherTreeType& other, - const ValueType& inactiveValue, - const ValueType& activeValue, - TopologyCopy): - TreeBase(other), - mRoot(other.root(), inactiveValue, activeValue, TopologyCopy()) - { - } - - /// @brief Topology copy constructor from a tree of a different type - /// - /// @note This topology copy constructor is generally faster than - /// the one that takes both a foreground and a background value. - /// - /// Copy the structure, i.e., the active states of tiles and voxels, of another - /// tree of a possibly different type, but don't copy any tile or voxel values. - /// Instead, initialize tiles and voxels with the given background value. - /// @param other a tree having (possibly) a different ValueType - /// @param background the value to which tiles and voxels are initialized - /// @throw TypeError if the other tree's configuration doesn't match this tree's. - template - Tree(const OtherTreeType& other, const ValueType& background, TopologyCopy): - TreeBase(other), - mRoot(other.root(), background, TopologyCopy()) - { - } - - /// Empty tree constructor - Tree(const ValueType& background): mRoot(background) {} - - virtual ~Tree() { releaseAllAccessors(); } - - /// Return a pointer to a deep copy of this tree - virtual TreeBase::Ptr copy() const { return TreeBase::Ptr(new Tree(*this)); } - - /// Return the name of the type of a voxel's value (e.g., "float" or "vec3d") - virtual Name valueType() const { return typeNameAsString(); } - - /// Return the name of this type of tree. - static const Name& treeType(); - /// Return the name of this type of tree. - virtual const Name& type() const { return this->treeType(); } - - bool operator==(const Tree&) const { OPENVDB_THROW(NotImplementedError, ""); } - bool operator!=(const Tree&) const { OPENVDB_THROW(NotImplementedError, ""); } - - //@{ - /// Return this tree's root node. - RootNodeType& root() { return mRoot; } - const RootNodeType& root() const { return mRoot; } - //@} - - - // - // Tree methods - // - /// @brief Return @c true if the given tree has the same node and active value - /// topology as this tree, whether or not it has the same @c ValueType. - template - bool hasSameTopology(const Tree& other) const; - - virtual bool evalLeafBoundingBox(CoordBBox& bbox) const; - virtual bool evalActiveVoxelBoundingBox(CoordBBox& bbox) const; - virtual bool evalActiveVoxelDim(Coord& dim) const; - virtual bool evalLeafDim(Coord& dim) const; - - /// @brief Traverse the type hierarchy of nodes, and return, in @a dims, a list - /// of the Log2Dims of nodes in order from RootNode to LeafNode. - /// @note Because RootNodes are resizable, the RootNode Log2Dim is 0 for all trees. - static void getNodeLog2Dims(std::vector& dims); - - - // - // I/O methods - // - /// @brief Read the tree topology from a stream. - /// - /// This will read the tree structure and tile values, but not voxel data. - virtual void readTopology(std::istream&, bool saveFloatAsHalf = false); - /// @brief Write the tree topology to a stream. - /// - /// This will write the tree structure and tile values, but not voxel data. - virtual void writeTopology(std::ostream&, bool saveFloatAsHalf = false) const; - /// Read all data buffers for this tree. - virtual void readBuffers(std::istream&, bool saveFloatAsHalf = false); -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// Read all of this tree's data buffers that intersect the given bounding box. - virtual void readBuffers(std::istream&, const CoordBBox&, bool saveFloatAsHalf = false); - /// @brief Read all of this tree's data buffers that are not yet resident in memory - /// (because delayed loading is in effect). - /// @details If this tree was read from a memory-mapped file, this operation - /// disconnects the tree from the file. - /// @sa clipUnallocatedNodes, io::File::open, io::MappedFile - virtual void readNonresidentBuffers() const; -#endif - /// Write out all data buffers for this tree. - virtual void writeBuffers(std::ostream&, bool saveFloatAsHalf = false) const; - - virtual void print(std::ostream& os = std::cout, int verboseLevel = 1) const; - - - // - // Statistics - // - /// @brief Return the depth of this tree. - /// - /// A tree with only a root node and leaf nodes has depth 2, for example. - virtual Index treeDepth() const { return DEPTH; } - /// Return the number of leaf nodes. - virtual Index32 leafCount() const { return mRoot.leafCount(); } - /// Return the number of non-leaf nodes. - virtual Index32 nonLeafCount() const { return mRoot.nonLeafCount(); } - /// Return the number of active voxels stored in leaf nodes. - virtual Index64 activeLeafVoxelCount() const { return mRoot.onLeafVoxelCount(); } - /// Return the number of inactive voxels stored in leaf nodes. - virtual Index64 inactiveLeafVoxelCount() const { return mRoot.offLeafVoxelCount(); } - /// Return the total number of active voxels. - virtual Index64 activeVoxelCount() const { return mRoot.onVoxelCount(); } - /// Return the number of inactive voxels within the bounding box of all active voxels. - virtual Index64 inactiveVoxelCount() const; - /// Return the total number of active tiles. - Index64 activeTileCount() const { return mRoot.onTileCount(); } - - /// Return the minimum and maximum active values in this tree. - void evalMinMax(ValueType &min, ValueType &max) const; - - virtual Index64 memUsage() const { return sizeof(*this) + mRoot.memUsage(); } - - - // - // Voxel access methods (using signed indexing) - // - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const; - /// @brief Return the value of the voxel at the given coordinates - /// and update the given accessor's node cache. - template const ValueType& getValue(const Coord& xyz, AccessT&) const; - - /// @brief Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides. - /// @details If (x, y, z) isn't explicitly represented in the tree (i.e., it is - /// implicitly a background voxel), return -1. - int getValueDepth(const Coord& xyz) const; - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on); - /// Set the value of the voxel at the given coordinates but don't change its active state. - void setValueOnly(const Coord& xyz, const ValueType& value); - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz); - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValueOn(const Coord& xyz, const ValueType& value); - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value); - /// @brief Set the value of the voxel at the given coordinates, mark the voxel as active, - /// and update the given accessor's node cache. - template void setValue(const Coord& xyz, const ValueType& value, AccessT&); - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz); - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value); - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details Provided that the functor can be inlined, this is typically - /// significantly faster than calling getValue() followed by setValueOn(). - /// @param xyz the coordinates of a voxel whose value is to be modified - /// @param op a functor of the form void op(ValueType&) const that modifies - /// its argument in place - /// @par Example: - /// @code - /// Coord xyz(1, 0, -2); - /// // Multiply the value of a voxel by a constant and mark the voxel as active. - /// floatTree.modifyValue(xyz, [](float& f) { f *= 0.25; }); // C++11 - /// // Set the value of a voxel to the maximum of its current value and 0.25, - /// // and mark the voxel as active. - /// floatTree.modifyValue(xyz, [](float& f) { f = std::max(f, 0.25f); }); // C++11 - /// @endcode - /// @note The functor is not guaranteed to be called only once. - /// @see tools::foreach() - template - void modifyValue(const Coord& xyz, const ModifyOp& op); - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details Provided that the functor can be inlined, this is typically - /// significantly faster than calling getValue() followed by setValue(). - /// @param xyz the coordinates of a voxel to be modified - /// @param op a functor of the form void op(ValueType&, bool&) const that - /// modifies its arguments, a voxel's value and active state, in place - /// @par Example: - /// @code - /// Coord xyz(1, 0, -2); - /// // Multiply the value of a voxel by a constant and mark the voxel as inactive. - /// floatTree.modifyValueAndActiveState(xyz, - /// [](float& f, bool& b) { f *= 0.25; b = false; }); // C++11 - /// // Set the value of a voxel to the maximum of its current value and 0.25, - /// // but don't change the voxel's active state. - /// floatTree.modifyValueAndActiveState(xyz, - /// [](float& f, bool&) { f = std::max(f, 0.25f); }); // C++11 - /// @endcode - /// @note The functor is not guaranteed to be called only once. - /// @see tools::foreach() - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op); - - /// @brief Get the value of the voxel at the given coordinates. - /// @return @c true if the value is active. - bool probeValue(const Coord& xyz, ValueType& value) const; - - /// Return @c true if the value at the given coordinates is active. - bool isValueOn(const Coord& xyz) const { return mRoot.isValueOn(xyz); } - /// Return @c true if the value at the given coordinates is inactive. - bool isValueOff(const Coord& xyz) const { return !this->isValueOn(xyz); } - /// Return @c true if this tree has any active tiles. - bool hasActiveTiles() const { return mRoot.hasActiveTiles(); } - - /// Set all voxels that lie outside the given axis-aligned box to the background. - void clip(const CoordBBox&); - -#ifndef OPENVDB_2_ABI_COMPATIBLE - /// @brief Replace with background tiles any nodes whose voxel buffers - /// have not yet been allocated. - /// @details Typically, unallocated nodes are leaf nodes whose voxel buffers - /// are not yet resident in memory because delayed loading is in effect. - /// @sa readNonresidentBuffers, io::File::open - virtual void clipUnallocatedNodes(); -#endif - - /// @brief Set all voxels within a given axis-aligned box to a constant value. - /// If necessary, subdivide tiles that intersect the box. - /// @param bbox inclusive coordinates of opposite corners of an axis-aligned box - /// @param value the value to which to set voxels within the box - /// @param active if true, mark voxels within the box as active, - /// otherwise mark them as inactive - /// @note This operation generates a sparse, but not always optimally sparse, - /// representation of the filled box. Follow fill operations with a prune() - /// operation for optimal sparseness. - void fill(const CoordBBox& bbox, const ValueType& value, bool active = true); - - /// @brief Reduce the memory footprint of this tree by replacing with tiles - /// any nodes whose values are all the same (optionally to within a tolerance) - /// and have the same active state. - /// @warning Will soon be deprecated! - void prune(const ValueType& tolerance = zeroVal()) - { - this->clearAllAccessors(); - mRoot.prune(tolerance); - } - - /// @brief Add the given leaf node to this tree, creating a new branch if necessary. - /// If a leaf node with the same origin already exists, replace it. - void addLeaf(LeafNodeType& leaf) { mRoot.addLeaf(&leaf); } - - /// @brief Add a tile containing voxel (x, y, z) at the specified tree level, - /// creating a new branch if necessary. Delete any existing lower-level nodes - /// that contain (x, y, z). - /// @note @a level must be less than this tree's depth. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool active); - - /// @brief Return a pointer to the node of type @c NodeT that contains voxel (x, y, z) - /// and replace it with a tile of the specified value and state. - /// If no such node exists, leave the tree unchanged and return @c NULL. - /// @note The caller takes ownership of the node and is responsible for deleting it. - template - NodeT* stealNode(const Coord& xyz, const ValueType& value, bool active); - - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, create one that preserves the values and - /// active states of all voxels. - /// @details Use this method to preallocate a static tree topology over which to - /// safely perform multithreaded processing. - LeafNodeType* touchLeaf(const Coord& xyz); - - //@{ - /// @brief Return a pointer to the node of type @c NodeType that contains - /// voxel (x, y, z). If no such node exists, return NULL. - template NodeType* probeNode(const Coord& xyz); - template const NodeType* probeConstNode(const Coord& xyz) const; - template const NodeType* probeNode(const Coord& xyz) const; - //@} - - //@{ - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, return NULL. - LeafNodeType* probeLeaf(const Coord& xyz); - const LeafNodeType* probeConstLeaf(const Coord& xyz) const; - const LeafNodeType* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); } - //@} - - - //@{ - /// @brief Adds all nodes of a certain type to a container with the following API: - /// @code - /// struct ArrayT { - /// typedef value_type;// defines the type of nodes to be added to the array - /// void push_back(value_type nodePtr);// method that add nodes to the array - /// }; - /// @endcode - /// @details An example of a wrapper around a c-style array is: - /// @code - /// struct MyArray { - /// typedef LeafType* value_type; - /// value_type* ptr; - /// MyArray(value_type* array) : ptr(array) {} - /// void push_back(value_type leaf) { *ptr++ = leaf; } - ///}; - /// @endcode - /// @details An example that constructs a list of pointer to all leaf nodes is: - /// @code - /// std::vector array;//most std contains have the required API - /// array.reserve(tree.leafCount());//this is a fast preallocation. - /// tree.getNodes(array); - /// @endcode - template void getNodes(ArrayT& array) { mRoot.getNodes(array); } - template void getNodes(ArrayT& array) const { mRoot.getNodes(array); } - //@} - - // - // Aux methods - // - /// @brief Return @c true if this tree contains no nodes other than - /// the root node and no tiles other than background tiles. - bool empty() const { return mRoot.empty(); } - - /// Remove all tiles from this tree and all nodes other than the root node. - void clear() { this->clearAllAccessors(); mRoot.clear(); } - - /// Clear all registered accessors. - void clearAllAccessors(); - - //@{ - /// @brief Register an accessor for this tree. Registered accessors are - /// automatically cleared whenever one of this tree's nodes is deleted. - void attachAccessor(ValueAccessorBase&) const; - void attachAccessor(ValueAccessorBase&) const; - //@} - //@{ - /// Deregister an accessor so that it is no longer automatically cleared. - void releaseAccessor(ValueAccessorBase&) const; - void releaseAccessor(ValueAccessorBase&) const; - //@} - - /// @brief Return this tree's background value wrapped as metadata. - /// @note Query the metadata object for the value's type. - virtual Metadata::Ptr getBackgroundValue() const; - - /// @brief Return this tree's background value. - /// - /// @note Use tools::changeBackground to efficiently modify the - /// background values. Else use tree.root().setBackground, which - /// is serial and hence slower. - const ValueType& background() const { return mRoot.background(); } - - /// Min and max are both inclusive. - virtual void getIndexRange(CoordBBox& bbox) const { mRoot.getIndexRange(bbox); } - - /// Densify active tiles, i.e., replace them with leaf-level active voxels. - void voxelizeActiveTiles(); - - /// @brief Efficiently merge another tree into this tree using one of several schemes. - /// @details This operation is primarily intended to combine trees that are mostly - /// non-overlapping (for example, intermediate trees from computations that are - /// parallelized across disjoint regions of space). - /// @note This operation is not guaranteed to produce an optimally sparse tree. - /// Follow merge() with prune() for optimal sparseness. - /// @warning This operation always empties the other tree. - void merge(Tree& other, MergePolicy = MERGE_ACTIVE_STATES); - - /// @brief Union this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. - /// @details The resulting state of a value is active if the corresponding value - /// was already active OR if it is active in the other tree. Also, a resulting - /// value maps to a voxel if the corresponding value already mapped to a voxel - /// OR if it is a voxel in the other tree. Thus, a resulting value can only - /// map to a tile if the corresponding value already mapped to a tile - /// AND if it is a tile value in other tree. - /// - /// @note This operation modifies only active states, not values. - /// Specifically, active tiles and voxels in this tree are not changed, and - /// tiles or voxels that were inactive in this tree but active in the other tree - /// are marked as active in this tree but left with their original values. - template - void topologyUnion(const Tree& other); - - /// @brief Intersects this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. - /// @details The resulting state of a value is active only if the corresponding - /// value was already active AND if it is active in the other tree. Also, a - /// resulting value maps to a voxel if the corresponding value - /// already mapped to an active voxel in either of the two grids - /// and it maps to an active tile or voxel in the other grid. - /// - /// @note This operation can delete branches in this grid if they - /// overlap with inactive tiles in the other grid. Likewise active - /// voxels can be turned into unactive voxels resulting in leaf - /// nodes with no active values. Thus, it is recommended to - /// subsequently call tools::pruneInactive. - template - void topologyIntersection(const Tree& other); - - /// @brief Difference this tree's set of active values with the active values - /// of the other tree, whose @c ValueType may be different. So a - /// resulting voxel will be active only if the original voxel is - /// active in this tree and inactive in the other tree. - /// - /// @note This operation can delete branches in this grid if they - /// overlap with active tiles in the other grid. Likewise active - /// voxels can be turned into inactive voxels resulting in leaf - /// nodes with no active values. Thus, it is recommended to - /// subsequently call tools::pruneInactive. - template - void topologyDifference(const Tree& other); - - /// For a given function @c f, use sparse traversal to compute f(this, other) - /// over all corresponding pairs of values (tile or voxel) of this tree and the other tree - /// and store the result in this tree. - /// This method is typically more space-efficient than the two-tree combine2(), - /// since it moves rather than copies nodes from the other tree into this tree. - /// @note This operation always empties the other tree. - /// @param other a tree of the same type as this tree - /// @param op a functor of the form void op(const T& a, const T& b, T& result), - /// where @c T is this tree's @c ValueType, that computes - /// result = f(a, b) - /// @param prune if true, prune the resulting tree one branch at a time (this is usually - /// more space-efficient than pruning the entire tree in one pass) - /// - /// @par Example: - /// Compute the per-voxel difference between two floating-point trees, - /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty). - /// @code - /// { - /// struct Local { - /// static inline void diff(const float& a, const float& b, float& result) { - /// result = a - b; - /// } - /// }; - /// aTree.combine(bTree, Local::diff); - /// } - /// @endcode - /// - /// @par Example: - /// Compute f * a + (1 - f) * b over all voxels of two floating-point trees, - /// @c aTree and @c bTree, and store the result in @c aTree (leaving @c bTree empty). - /// @code - /// namespace { - /// struct Blend { - /// Blend(float f): frac(f) {} - /// inline void operator()(const float& a, const float& b, float& result) const { - /// result = frac * a + (1.0 - frac) * b; - /// } - /// float frac; - /// }; - /// } - /// { - /// aTree.combine(bTree, Blend(0.25)); // 0.25 * a + 0.75 * b - /// } - /// @endcode - template - void combine(Tree& other, CombineOp& op, bool prune = false); -#ifndef _MSC_VER - template - void combine(Tree& other, const CombineOp& op, bool prune = false); -#endif - - /// Like combine(), but with - /// @param other a tree of the same type as this tree - /// @param op a functor of the form void op(CombineArgs& args) that - /// computes args.setResult(f(args.a(), args.b())) and, optionally, - /// args.setResultIsActive(g(args.aIsActive(), args.bIsActive())) - /// for some functions @c f and @c g - /// @param prune if true, prune the resulting tree one branch at a time (this is usually - /// more space-efficient than pruning the entire tree in one pass) - /// - /// This variant passes not only the @em a and @em b values but also the active states - /// of the @em a and @em b values to the functor, which may then return, by calling - /// @c args.setResultIsActive(), a computed active state for the result value. - /// By default, the result is active if either the @em a or the @em b value is active. - /// - /// @see openvdb/Types.h for the definition of the CombineArgs struct. - /// - /// @par Example: - /// Replace voxel values in floating-point @c aTree with corresponding values - /// from floating-point @c bTree (leaving @c bTree empty) wherever the @c bTree - /// values are larger. Also, preserve the active states of any transferred values. - /// @code - /// { - /// struct Local { - /// static inline void max(CombineArgs& args) { - /// if (args.b() > args.a()) { - /// // Transfer the B value and its active state. - /// args.setResult(args.b()); - /// args.setResultIsActive(args.bIsActive()); - /// } else { - /// // Preserve the A value and its active state. - /// args.setResult(args.a()); - /// args.setResultIsActive(args.aIsActive()); - /// } - /// } - /// }; - /// aTree.combineExtended(bTree, Local::max); - /// } - /// @endcode - template - void combineExtended(Tree& other, ExtendedCombineOp& op, bool prune = false); -#ifndef _MSC_VER - template - void combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune = false); -#endif - - /// For a given function @c f, use sparse traversal to compute f(a, b) over all - /// corresponding pairs of values (tile or voxel) of trees A and B and store the result - /// in this tree. - /// @param a,b two trees with the same configuration (levels and node dimensions) - /// as this tree but with the B tree possibly having a different value type - /// @param op a functor of the form void op(const T1& a, const T2& b, T1& result), - /// where @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the - /// B tree's @c ValueType, that computes result = f(a, b) - /// @param prune if true, prune the resulting tree one branch at a time (this is usually - /// more space-efficient than pruning the entire tree in one pass) - /// - /// @throw TypeError if the B tree's configuration doesn't match this tree's - /// or if this tree's ValueType is not constructible from the B tree's ValueType. - /// - /// @par Example: - /// Compute the per-voxel difference between two floating-point trees, - /// @c aTree and @c bTree, and store the result in a third tree. - /// @code - /// { - /// struct Local { - /// static inline void diff(const float& a, const float& b, float& result) { - /// result = a - b; - /// } - /// }; - /// FloatTree resultTree; - /// resultTree.combine2(aTree, bTree, Local::diff); - /// } - /// @endcode - template - void combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune = false); -#ifndef _MSC_VER - template - void combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune = false); -#endif - - /// Like combine2(), but with - /// @param a,b two trees with the same configuration (levels and node dimensions) - /// as this tree but with the B tree possibly having a different value type - /// @param op a functor of the form void op(CombineArgs& args), where - /// @c T1 is this tree's and the A tree's @c ValueType and @c T2 is the B tree's - /// @c ValueType, that computes args.setResult(f(args.a(), args.b())) - /// and, optionally, - /// args.setResultIsActive(g(args.aIsActive(), args.bIsActive())) - /// for some functions @c f and @c g - /// @param prune if true, prune the resulting tree one branch at a time (this is usually - /// more space-efficient than pruning the entire tree in one pass) - /// This variant passes not only the @em a and @em b values but also the active states - /// of the @em a and @em b values to the functor, which may then return, by calling - /// args.setResultIsActive(), a computed active state for the result value. - /// By default, the result is active if either the @em a or the @em b value is active. - /// - /// @throw TypeError if the B tree's configuration doesn't match this tree's - /// or if this tree's ValueType is not constructible from the B tree's ValueType. - /// - /// @see openvdb/Types.h for the definition of the CombineArgs struct. - /// - /// @par Example: - /// Compute the per-voxel maximum values of two single-precision floating-point trees, - /// @c aTree and @c bTree, and store the result in a third tree. Set the active state - /// of each output value to that of the larger of the two input values. - /// @code - /// { - /// struct Local { - /// static inline void max(CombineArgs& args) { - /// if (args.b() > args.a()) { - /// // Transfer the B value and its active state. - /// args.setResult(args.b()); - /// args.setResultIsActive(args.bIsActive()); - /// } else { - /// // Preserve the A value and its active state. - /// args.setResult(args.a()); - /// args.setResultIsActive(args.aIsActive()); - /// } - /// } - /// }; - /// FloatTree aTree = ...; - /// FloatTree bTree = ...; - /// FloatTree resultTree; - /// resultTree.combine2Extended(aTree, bTree, Local::max); - /// } - /// @endcode - /// - /// @par Example: - /// Compute the per-voxel maximum values of a double-precision and a single-precision - /// floating-point tree, @c aTree and @c bTree, and store the result in a third, - /// double-precision tree. Set the active state of each output value to that of - /// the larger of the two input values. - /// @code - /// { - /// struct Local { - /// static inline void max(CombineArgs& args) { - /// if (args.b() > args.a()) { - /// // Transfer the B value and its active state. - /// args.setResult(args.b()); - /// args.setResultIsActive(args.bIsActive()); - /// } else { - /// // Preserve the A value and its active state. - /// args.setResult(args.a()); - /// args.setResultIsActive(args.aIsActive()); - /// } - /// } - /// }; - /// DoubleTree aTree = ...; - /// FloatTree bTree = ...; - /// DoubleTree resultTree; - /// resultTree.combine2Extended(aTree, bTree, Local::max); - /// } - /// @endcode - template - void combine2Extended(const Tree& a, const OtherTreeType& b, ExtendedCombineOp& op, - bool prune = false); -#ifndef _MSC_VER - template - void combine2Extended(const Tree& a, const OtherTreeType& b, const ExtendedCombineOp&, - bool prune = false); -#endif - - /// @brief Use sparse traversal to call the given functor with bounding box - /// information for all active tiles and leaf nodes or active voxels in the tree. - /// - /// @note The bounding boxes are guaranteed to be non-overlapping. - /// @param op a functor with a templated call operator of the form - /// template void operator()(const CoordBBox& bbox), - /// where bbox is the bounding box of either an active tile - /// (if @c LEVEL > 0), a leaf node or an active voxel. - /// The functor must also provide a templated method of the form - /// template bool descent() that returns @c false - /// if bounding boxes below the specified tree level are not to be visited. - /// In such cases of early tree termination, a bounding box is instead - /// derived from each terminating child node. - /// - /// @par Example: - /// Visit and process all active tiles and leaf nodes in a tree, but don't - /// descend to the active voxels. The smallest bounding boxes that will be - /// visited are those of leaf nodes or level-1 active tiles. - /// @code - /// { - /// struct ProcessTilesAndLeafNodes { - /// // Descend to leaf nodes, but no further. - /// template inline bool descent() { return LEVEL > 0; } - /// // Use this version to descend to voxels: - /// //template inline bool descent() { return true; } - /// - /// template - /// inline void operator()(const CoordBBox &bbox) { - /// if (LEVEL > 0) { - /// // code to process an active tile - /// } else { - /// // code to process a leaf node - /// } - /// } - /// }; - /// ProcessTilesAndLeafNodes op; - /// aTree.visitActiveBBox(op); - /// } - /// @endcode - /// @see openvdb/unittest/TestTree.cc for another example. - template void visitActiveBBox(BBoxOp& op) const { mRoot.visitActiveBBox(op); } - - /// Traverse this tree in depth-first order, and at each node call the given functor - /// with a @c DenseIterator (see Iterator.h) that points to either a child node or a - /// tile value. If the iterator points to a child node and the functor returns true, - /// do not descend to the child node; instead, continue the traversal at the next - /// iterator position. - /// @param op a functor of the form template bool op(IterT&), - /// where @c IterT is either a RootNode::ChildAllIter, - /// an InternalNode::ChildAllIter or a LeafNode::ChildAllIter - /// - /// @note There is no iterator that points to a RootNode, so to visit the root node, - /// retrieve the @c parent() of a RootNode::ChildAllIter. - /// - /// @par Example: - /// Print information about the nodes and tiles of a tree, but not individual voxels. - /// @code - /// namespace { - /// template - /// struct PrintTreeVisitor - /// { - /// typedef typename TreeT::RootNodeType RootT; - /// bool visitedRoot; - /// - /// PrintTreeVisitor(): visitedRoot(false) {} - /// - /// template - /// inline bool operator()(IterT& iter) - /// { - /// if (!visitedRoot && iter.parent().getLevel() == RootT::LEVEL) { - /// visitedRoot = true; - /// std::cout << "Level-" << RootT::LEVEL << " node" << std::endl; - /// } - /// typename IterT::NonConstValueType value; - /// typename IterT::ChildNodeType* child = iter.probeChild(value); - /// if (child == NULL) { - /// std::cout << "Tile with value " << value << std::endl; - /// return true; // no child to visit, so stop descending - /// } - /// std::cout << "Level-" << child->getLevel() << " node" << std::endl; - /// return (child->getLevel() == 0); // don't visit leaf nodes - /// } - /// - /// // The generic method, above, calls iter.probeChild(), which is not defined - /// // for LeafNode::ChildAllIter. These overloads ensure that the generic - /// // method template doesn't get instantiated for LeafNode iterators. - /// bool operator()(typename TreeT::LeafNodeType::ChildAllIter&) { return true; } - /// bool operator()(typename TreeT::LeafNodeType::ChildAllCIter&) { return true; } - /// }; - /// } - /// { - /// PrintTreeVisitor visitor; - /// tree.visit(visitor); - /// } - /// @endcode - template void visit(VisitorOp& op); - template void visit(const VisitorOp& op); - - /// Like visit(), but using @c const iterators, i.e., with - /// @param op a functor of the form template bool op(IterT&), - /// where @c IterT is either a RootNode::ChildAllCIter, - /// an InternalNode::ChildAllCIter or a LeafNode::ChildAllCIter - template void visit(VisitorOp& op) const; - template void visit(const VisitorOp& op) const; - - /// Traverse this tree and another tree in depth-first order, and for corresponding - /// subregions of index space call the given functor with two @c DenseIterators - /// (see Iterator.h), each of which points to either a child node or a tile value - /// of this tree and the other tree. If the A iterator points to a child node - /// and the functor returns a nonzero value with bit 0 set (e.g., 1), do not descend - /// to the child node; instead, continue the traversal at the next A iterator position. - /// Similarly, if the B iterator points to a child node and the functor returns a value - /// with bit 1 set (e.g., 2), continue the traversal at the next B iterator position. - /// @note The other tree must have the same index space and fan-out factors as - /// this tree, but it may have a different @c ValueType and a different topology. - /// @param other a tree of the same type as this tree - /// @param op a functor of the form - /// template int op(AIterT&, BIterT&), - /// where @c AIterT and @c BIterT are any combination of a - /// RootNode::ChildAllIter, an InternalNode::ChildAllIter or a - /// LeafNode::ChildAllIter with an @c OtherTreeType::RootNode::ChildAllIter, - /// an @c OtherTreeType::InternalNode::ChildAllIter - /// or an @c OtherTreeType::LeafNode::ChildAllIter - /// - /// @par Example: - /// Given two trees of the same type, @c aTree and @c bTree, replace leaf nodes of - /// @c aTree with corresponding leaf nodes of @c bTree, leaving @c bTree partially empty. - /// @code - /// namespace { - /// template - /// inline int stealLeafNodes(AIterT& aIter, BIterT& bIter) - /// { - /// typename AIterT::NonConstValueType aValue; - /// typename AIterT::ChildNodeType* aChild = aIter.probeChild(aValue); - /// typename BIterT::NonConstValueType bValue; - /// typename BIterT::ChildNodeType* bChild = bIter.probeChild(bValue); - /// - /// const Index aLevel = aChild->getLevel(), bLevel = bChild->getLevel(); - /// if (aChild && bChild && aLevel == 0 && bLevel == 0) { // both are leaf nodes - /// aIter.setChild(bChild); // give B's child to A - /// bIter.setValue(bValue); // replace B's child with a constant tile value - /// } - /// // Don't iterate over leaf node voxels of either A or B. - /// int skipBranch = (aLevel == 0) ? 1 : 0; - /// if (bLevel == 0) skipBranch = skipBranch | 2; - /// return skipBranch; - /// } - /// } - /// { - /// aTree.visit2(bTree, stealLeafNodes); - /// } - /// @endcode - template - void visit2(OtherTreeType& other, VisitorOp& op); - template - void visit2(OtherTreeType& other, const VisitorOp& op); - - /// Like visit2(), but using @c const iterators, i.e., with - /// @param other a tree of the same type as this tree - /// @param op a functor of the form - /// template int op(AIterT&, BIterT&), - /// where @c AIterT and @c BIterT are any combination of a - /// RootNode::ChildAllCIter, an InternalNode::ChildAllCIter - /// or a LeafNode::ChildAllCIter with an - /// @c OtherTreeType::RootNode::ChildAllCIter, - /// an @c OtherTreeType::InternalNode::ChildAllCIter - /// or an @c OtherTreeType::LeafNode::ChildAllCIter - template - void visit2(OtherTreeType& other, VisitorOp& op) const; - template - void visit2(OtherTreeType& other, const VisitorOp& op) const; - - - // - // Iteration - // - //@{ - /// Return an iterator over children of the root node. - typename RootNodeType::ChildOnCIter beginRootChildren() const { return mRoot.cbeginChildOn(); } - typename RootNodeType::ChildOnCIter cbeginRootChildren() const { return mRoot.cbeginChildOn(); } - typename RootNodeType::ChildOnIter beginRootChildren() { return mRoot.beginChildOn(); } - //@} - - //@{ - /// Return an iterator over non-child entries of the root node's table. - typename RootNodeType::ChildOffCIter beginRootTiles() const { return mRoot.cbeginChildOff(); } - typename RootNodeType::ChildOffCIter cbeginRootTiles() const { return mRoot.cbeginChildOff(); } - typename RootNodeType::ChildOffIter beginRootTiles() { return mRoot.beginChildOff(); } - //@} - - //@{ - /// Return an iterator over all entries of the root node's table. - typename RootNodeType::ChildAllCIter beginRootDense() const { return mRoot.cbeginChildAll(); } - typename RootNodeType::ChildAllCIter cbeginRootDense() const { return mRoot.cbeginChildAll(); } - typename RootNodeType::ChildAllIter beginRootDense() { return mRoot.beginChildAll(); } - //@} - - - //@{ - /// Iterator over all nodes in this tree - typedef NodeIteratorBase NodeIter; - typedef NodeIteratorBase NodeCIter; - //@} - - //@{ - /// Iterator over all leaf nodes in this tree - typedef LeafIteratorBase LeafIter; - typedef LeafIteratorBase LeafCIter; - //@} - - //@{ - /// Return an iterator over all nodes in this tree. - NodeIter beginNode() { return NodeIter(*this); } - NodeCIter beginNode() const { return NodeCIter(*this); } - NodeCIter cbeginNode() const { return NodeCIter(*this); } - //@} - - //@{ - /// Return an iterator over all leaf nodes in this tree. - LeafIter beginLeaf() { return LeafIter(*this); } - LeafCIter beginLeaf() const { return LeafCIter(*this); } - LeafCIter cbeginLeaf() const { return LeafCIter(*this); } - //@} - - typedef TreeValueIteratorBase ValueAllIter; - typedef TreeValueIteratorBase ValueAllCIter; - typedef TreeValueIteratorBase ValueOnIter; - typedef TreeValueIteratorBase ValueOnCIter; - typedef TreeValueIteratorBase ValueOffIter; - typedef TreeValueIteratorBase ValueOffCIter; - - //@{ - /// Return an iterator over all values (tile and voxel) across all nodes. - ValueAllIter beginValueAll() { return ValueAllIter(*this); } - ValueAllCIter beginValueAll() const { return ValueAllCIter(*this); } - ValueAllCIter cbeginValueAll() const { return ValueAllCIter(*this); } - //@} - //@{ - /// Return an iterator over active values (tile and voxel) across all nodes. - ValueOnIter beginValueOn() { return ValueOnIter(*this); } - ValueOnCIter beginValueOn() const { return ValueOnCIter(*this); } - ValueOnCIter cbeginValueOn() const { return ValueOnCIter(*this); } - //@} - //@{ - /// Return an iterator over inactive values (tile and voxel) across all nodes. - ValueOffIter beginValueOff() { return ValueOffIter(*this); } - ValueOffCIter beginValueOff() const { return ValueOffCIter(*this); } - ValueOffCIter cbeginValueOff() const { return ValueOffCIter(*this); } - //@} - - /// @brief Return an iterator of type @c IterT (for example, begin() is - /// equivalent to beginValueOn()). - template IterT begin(); - /// @brief Return a const iterator of type CIterT (for example, cbegin() - /// is equivalent to cbeginValueOn()). - template CIterT cbegin() const; - - -protected: - typedef tbb::concurrent_hash_map*, bool> AccessorRegistry; - typedef tbb::concurrent_hash_map*, bool> ConstAccessorRegistry; - - // Disallow assignment of instances of this class. - Tree& operator=(const Tree&); - - /// @brief Notify all registered accessors, by calling ValueAccessor::release(), - /// that this tree is about to be deleted. - void releaseAllAccessors(); - - - // - // Data members - // - RootNodeType mRoot; // root node of the tree - mutable AccessorRegistry mAccessorRegistry; - mutable ConstAccessorRegistry mConstAccessorRegistry; - - static tbb::atomic sTreeTypeName; -}; // end of Tree class - -template -tbb::atomic Tree<_RootNodeType>::sTreeTypeName; - - -/// @brief Tree3::Type is the type of a three-level tree -/// (Root, Internal, Leaf) with value type T and -/// internal and leaf node log dimensions N1 and N2, respectively. -/// @note This is NOT the standard tree configuration (Tree4 is). -template -struct Tree3 { - typedef Tree, N1> > > Type; -}; - - -/// @brief Tree4::Type is the type of a four-level tree -/// (Root, Internal, Internal, Leaf) with value type T and -/// internal and leaf node log dimensions N1, N2 and N3, respectively. -/// @note This is the standard tree configuration. -template -struct Tree4 { - typedef Tree, N2>, N1> > > Type; -}; - - -/// @brief Tree5::Type is the type of a five-level tree -/// (Root, Internal, Internal, Internal, Leaf) with value type T and -/// internal and leaf node log dimensions N1, N2, N3 and N4, respectively. -/// @note This is NOT the standard tree configuration (Tree4 is). -template -struct Tree5 { - typedef Tree, N3>, N2>, N1> > > - Type; -}; - - -//////////////////////////////////////// - - -inline void -TreeBase::readTopology(std::istream& is, bool /*saveFloatAsHalf*/) -{ - int32_t bufferCount; - is.read(reinterpret_cast(&bufferCount), sizeof(int32_t)); - if (bufferCount != 1) OPENVDB_LOG_WARN("multi-buffer trees are no longer supported"); -} - - -inline void -TreeBase::writeTopology(std::ostream& os, bool /*saveFloatAsHalf*/) const -{ - int32_t bufferCount = 1; - os.write(reinterpret_cast(&bufferCount), sizeof(int32_t)); -} - - -inline void -TreeBase::print(std::ostream& os, int /*verboseLevel*/) const -{ - os << " Tree Type: " << type() - << " Active Voxel Count: " << activeVoxelCount() << std::endl - << " Inactive Voxel Count: " << inactiveVoxelCount() << std::endl - << " Leaf Node Count: " << leafCount() << std::endl - << " Non-leaf Node Count: " << nonLeafCount() << std::endl; -} - - -//////////////////////////////////////// - - -// -// Type traits for tree iterators -// - -/// @brief TreeIterTraits provides, for all tree iterators, a begin(tree) function -/// that returns an iterator over a tree of arbitrary type. -template struct TreeIterTraits; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildOnIter begin(TreeT& tree) { - return tree.beginRootChildren(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildOnCIter begin(const TreeT& tree) { - return tree.cbeginRootChildren(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildOffIter begin(TreeT& tree) { - return tree.beginRootTiles(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildOffCIter begin(const TreeT& tree) { - return tree.cbeginRootTiles(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildAllIter begin(TreeT& tree) { - return tree.beginRootDense(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::RootNodeType::ChildAllCIter begin(const TreeT& tree) { - return tree.cbeginRootDense(); - } -}; - -template struct TreeIterTraits { - static typename TreeT::NodeIter begin(TreeT& tree) { return tree.beginNode(); } -}; - -template struct TreeIterTraits { - static typename TreeT::NodeCIter begin(const TreeT& tree) { return tree.cbeginNode(); } -}; - -template struct TreeIterTraits { - static typename TreeT::LeafIter begin(TreeT& tree) { return tree.beginLeaf(); } -}; - -template struct TreeIterTraits { - static typename TreeT::LeafCIter begin(const TreeT& tree) { return tree.cbeginLeaf(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueOnIter begin(TreeT& tree) { return tree.beginValueOn(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueOnCIter begin(const TreeT& tree) { return tree.cbeginValueOn(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueOffIter begin(TreeT& tree) { return tree.beginValueOff(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueOffCIter begin(const TreeT& tree) { return tree.cbeginValueOff(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueAllIter begin(TreeT& tree) { return tree.beginValueAll(); } -}; - -template struct TreeIterTraits { - static typename TreeT::ValueAllCIter begin(const TreeT& tree) { return tree.cbeginValueAll(); } -}; - - -template -template -inline IterT -Tree::begin() -{ - return TreeIterTraits::begin(*this); -} - - -template -template -inline IterT -Tree::cbegin() const -{ - return TreeIterTraits::begin(*this); -} - - -//////////////////////////////////////// - - -template -void -Tree::readTopology(std::istream& is, bool saveFloatAsHalf) -{ - this->clearAllAccessors(); - TreeBase::readTopology(is, saveFloatAsHalf); - mRoot.readTopology(is, saveFloatAsHalf); -} - - -template -void -Tree::writeTopology(std::ostream& os, bool saveFloatAsHalf) const -{ - TreeBase::writeTopology(os, saveFloatAsHalf); - mRoot.writeTopology(os, saveFloatAsHalf); -} - - -template -inline void -Tree::readBuffers(std::istream &is, bool saveFloatAsHalf) -{ - this->clearAllAccessors(); - mRoot.readBuffers(is, saveFloatAsHalf); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE - -template -inline void -Tree::readBuffers(std::istream &is, const CoordBBox& bbox, bool saveFloatAsHalf) -{ - this->clearAllAccessors(); - mRoot.readBuffers(is, bbox, saveFloatAsHalf); -} - - -template -inline void -Tree::readNonresidentBuffers() const -{ - for (LeafCIter it = this->cbeginLeaf(); it; ++it) { - // Retrieving the value of a leaf voxel forces loading of the leaf node's voxel buffer. - it->getValue(Index(0)); - } -} - -#endif // !OPENVDB_2_ABI_COMPATIBLE - - -template -inline void -Tree::writeBuffers(std::ostream &os, bool saveFloatAsHalf) const -{ - mRoot.writeBuffers(os, saveFloatAsHalf); -} - - -//////////////////////////////////////// - - -template -inline void -Tree::attachAccessor(ValueAccessorBase& accessor) const -{ - typename AccessorRegistry::accessor a; - mAccessorRegistry.insert(a, &accessor); -} - - -template -inline void -Tree::attachAccessor(ValueAccessorBase& accessor) const -{ - typename ConstAccessorRegistry::accessor a; - mConstAccessorRegistry.insert(a, &accessor); -} - - -template -inline void -Tree::releaseAccessor(ValueAccessorBase& accessor) const -{ - mAccessorRegistry.erase(&accessor); -} - - -template -inline void -Tree::releaseAccessor(ValueAccessorBase& accessor) const -{ - mConstAccessorRegistry.erase(&accessor); -} - - -template -inline void -Tree::clearAllAccessors() -{ - for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin(); - it != mAccessorRegistry.end(); ++it) - { - if (it->first) it->first->clear(); - } - - for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin(); - it != mConstAccessorRegistry.end(); ++it) - { - if (it->first) it->first->clear(); - } -} - - -template -inline void -Tree::releaseAllAccessors() -{ - mAccessorRegistry.erase(NULL); - for (typename AccessorRegistry::iterator it = mAccessorRegistry.begin(); - it != mAccessorRegistry.end(); ++it) - { - it->first->release(); - } - mAccessorRegistry.clear(); - - mAccessorRegistry.erase(NULL); - for (typename ConstAccessorRegistry::iterator it = mConstAccessorRegistry.begin(); - it != mConstAccessorRegistry.end(); ++it) - { - it->first->release(); - } - mConstAccessorRegistry.clear(); -} - - -//////////////////////////////////////// - - -template -inline const typename RootNodeType::ValueType& -Tree::getValue(const Coord& xyz) const -{ - return mRoot.getValue(xyz); -} - - -template -template -inline const typename RootNodeType::ValueType& -Tree::getValue(const Coord& xyz, AccessT& accessor) const -{ - return accessor.getValue(xyz); -} - - -template -inline int -Tree::getValueDepth(const Coord& xyz) const -{ - return mRoot.getValueDepth(xyz); -} - - -template -inline void -Tree::setValueOff(const Coord& xyz) -{ - mRoot.setValueOff(xyz); -} - - -template -inline void -Tree::setValueOff(const Coord& xyz, const ValueType& value) -{ - mRoot.setValueOff(xyz, value); -} - - -template -inline void -Tree::setActiveState(const Coord& xyz, bool on) -{ - mRoot.setActiveState(xyz, on); -} - - -template -inline void -Tree::setValue(const Coord& xyz, const ValueType& value) -{ - mRoot.setValueOn(xyz, value); -} - -template -inline void -Tree::setValueOnly(const Coord& xyz, const ValueType& value) -{ - mRoot.setValueOnly(xyz, value); -} - -template -template -inline void -Tree::setValue(const Coord& xyz, const ValueType& value, AccessT& accessor) -{ - accessor.setValue(xyz, value); -} - - -template -inline void -Tree::setValueOn(const Coord& xyz) -{ - mRoot.setActiveState(xyz, true); -} - - -template -inline void -Tree::setValueOn(const Coord& xyz, const ValueType& value) -{ - mRoot.setValueOn(xyz, value); -} - - -template -template -inline void -Tree::modifyValue(const Coord& xyz, const ModifyOp& op) -{ - mRoot.modifyValue(xyz, op); -} - - -template -template -inline void -Tree::modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) -{ - mRoot.modifyValueAndActiveState(xyz, op); -} - - -template -inline bool -Tree::probeValue(const Coord& xyz, ValueType& value) const -{ - return mRoot.probeValue(xyz, value); -} - - -//////////////////////////////////////// - - -template -inline void -Tree::addTile(Index level, const Coord& xyz, - const ValueType& value, bool active) -{ - mRoot.addTile(level, xyz, value, active); -} - - -template -template -inline NodeT* -Tree::stealNode(const Coord& xyz, const ValueType& value, bool active) -{ - this->clearAllAccessors(); - return mRoot.template stealNode(xyz, value, active); -} - - -template -inline typename RootNodeType::LeafNodeType* -Tree::touchLeaf(const Coord& xyz) -{ - return mRoot.touchLeaf(xyz); -} - - -template -inline typename RootNodeType::LeafNodeType* -Tree::probeLeaf(const Coord& xyz) -{ - return mRoot.probeLeaf(xyz); -} - - -template -inline const typename RootNodeType::LeafNodeType* -Tree::probeConstLeaf(const Coord& xyz) const -{ - return mRoot.probeConstLeaf(xyz); -} - - -template -template -inline NodeType* -Tree::probeNode(const Coord& xyz) -{ - return mRoot.template probeNode(xyz); -} - - -template -template -inline const NodeType* -Tree::probeNode(const Coord& xyz) const -{ - return this->template probeConstNode(xyz); -} - - -template -template -inline const NodeType* -Tree::probeConstNode(const Coord& xyz) const -{ - return mRoot.template probeConstNode(xyz); -} - - -//////////////////////////////////////// - - -template -inline void -Tree::clip(const CoordBBox& bbox) -{ - this->clearAllAccessors(); - return mRoot.clip(bbox); -} - - -#ifndef OPENVDB_2_ABI_COMPATIBLE -template -inline void -Tree::clipUnallocatedNodes() -{ - this->clearAllAccessors(); - for (LeafIter it = this->beginLeaf(); it; ) { - const LeafNodeType* leaf = it.getLeaf(); - ++it; // advance the iterator before deleting the leaf node - if (!leaf->isAllocated()) { - this->addTile(/*level=*/0, leaf->origin(), this->background(), /*active=*/false); - } - } -} -#endif - - -template -inline void -Tree::fill(const CoordBBox& bbox, const ValueType& value, bool active) -{ - this->clearAllAccessors(); - return mRoot.fill(bbox, value, active); -} - - -template -Metadata::Ptr -Tree::getBackgroundValue() const -{ - Metadata::Ptr result; - if (Metadata::isRegisteredType(valueType())) { - typedef TypedMetadata MetadataT; - result = Metadata::createMetadata(valueType()); - if (MetadataT* m = dynamic_cast(result.get())) { - m->value() = mRoot.background(); - } - } - return result; -} - - -//////////////////////////////////////// - - -template -inline void -Tree::voxelizeActiveTiles() -{ - this->clearAllAccessors(); - mRoot.voxelizeActiveTiles(); -} - - -template -inline void -Tree::merge(Tree& other, MergePolicy policy) -{ - this->clearAllAccessors(); - other.clearAllAccessors(); - switch (policy) { - case MERGE_ACTIVE_STATES: - mRoot.template merge(other.mRoot); break; - case MERGE_NODES: - mRoot.template merge(other.mRoot); break; - case MERGE_ACTIVE_STATES_AND_NODES: - mRoot.template merge(other.mRoot); break; - } -} - - -template -template -inline void -Tree::topologyUnion(const Tree& other) -{ - this->clearAllAccessors(); - mRoot.topologyUnion(other.root()); -} - -template -template -inline void -Tree::topologyIntersection(const Tree& other) -{ - this->clearAllAccessors(); - mRoot.topologyIntersection(other.root()); -} - -template -template -inline void -Tree::topologyDifference(const Tree& other) -{ - this->clearAllAccessors(); - mRoot.topologyDifference(other.root()); -} - -//////////////////////////////////////// - - -/// @brief Helper class to adapt a three-argument (a, b, result) CombineOp functor -/// into a single-argument functor that accepts a CombineArgs struct -template -struct CombineOpAdapter -{ - CombineOpAdapter(CombineOp& _op): op(_op) {} - - void operator()(CombineArgs& args) const { - op(args.a(), args.b(), args.result()); - } - - CombineOp& op; -}; - - -template -template -inline void -Tree::combine(Tree& other, CombineOp& op, bool prune) -{ - CombineOpAdapter extendedOp(op); - this->combineExtended(other, extendedOp, prune); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: aTree.combine(bTree, MyCombineOp(...)). -#ifndef _MSC_VER -template -template -inline void -Tree::combine(Tree& other, const CombineOp& op, bool prune) -{ - CombineOpAdapter extendedOp(op); - this->combineExtended(other, extendedOp, prune); -} -#endif - - -template -template -inline void -Tree::combineExtended(Tree& other, ExtendedCombineOp& op, bool prune) -{ - this->clearAllAccessors(); - mRoot.combine(other.root(), op, prune); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: aTree.combineExtended(bTree, MyCombineOp(...)). -#ifndef _MSC_VER -template -template -inline void -Tree::combineExtended(Tree& other, const ExtendedCombineOp& op, bool prune) -{ - this->clearAllAccessors(); - mRoot.template combine(other.mRoot, op, prune); -} -#endif - - -template -template -inline void -Tree::combine2(const Tree& a, const OtherTreeType& b, CombineOp& op, bool prune) -{ - CombineOpAdapter extendedOp(op); - this->combine2Extended(a, b, extendedOp, prune); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: tree.combine2(aTree, bTree, MyCombineOp(...)). -#ifndef _MSC_VER -template -template -inline void -Tree::combine2(const Tree& a, const OtherTreeType& b, const CombineOp& op, bool prune) -{ - CombineOpAdapter extendedOp(op); - this->combine2Extended(a, b, extendedOp, prune); -} -#endif - - -template -template -inline void -Tree::combine2Extended(const Tree& a, const OtherTreeType& b, - ExtendedCombineOp& op, bool prune) -{ - this->clearAllAccessors(); - mRoot.combine2(a.root(), b.root(), op, prune); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like the following, where the functor argument is a temporary: -/// tree.combine2Extended(aTree, bTree, MyCombineOp(...)). -#ifndef _MSC_VER -template -template -inline void -Tree::combine2Extended(const Tree& a, const OtherTreeType& b, - const ExtendedCombineOp& op, bool prune) -{ - this->clearAllAccessors(); - mRoot.template combine2(a.root(), b.root(), op, prune); -} -#endif - - -//////////////////////////////////////// - - -template -template -inline void -Tree::visit(VisitorOp& op) -{ - this->clearAllAccessors(); - mRoot.template visit(op); -} - - -template -template -inline void -Tree::visit(VisitorOp& op) const -{ - mRoot.template visit(op); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: tree.visit(MyVisitorOp(...)). -template -template -inline void -Tree::visit(const VisitorOp& op) -{ - this->clearAllAccessors(); - mRoot.template visit(op); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: tree.visit(MyVisitorOp(...)). -template -template -inline void -Tree::visit(const VisitorOp& op) const -{ - mRoot.template visit(op); -} - - -//////////////////////////////////////// - - -template -template -inline void -Tree::visit2(OtherTreeType& other, VisitorOp& op) -{ - this->clearAllAccessors(); - typedef typename OtherTreeType::RootNodeType OtherRootNodeType; - mRoot.template visit2(other.root(), op); -} - - -template -template -inline void -Tree::visit2(OtherTreeType& other, VisitorOp& op) const -{ - typedef typename OtherTreeType::RootNodeType OtherRootNodeType; - mRoot.template visit2(other.root(), op); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: aTree.visit2(bTree, MyVisitorOp(...)). -template -template -inline void -Tree::visit2(OtherTreeType& other, const VisitorOp& op) -{ - this->clearAllAccessors(); - typedef typename OtherTreeType::RootNodeType OtherRootNodeType; - mRoot.template visit2(other.root(), op); -} - - -/// @internal This overload is needed (for ICC and GCC, but not for VC) to disambiguate -/// code like this: aTree.visit2(bTree, MyVisitorOp(...)). -template -template -inline void -Tree::visit2(OtherTreeType& other, const VisitorOp& op) const -{ - typedef typename OtherTreeType::RootNodeType OtherRootNodeType; - mRoot.template visit2(other.root(), op); -} - - -//////////////////////////////////////// - - -template -inline const Name& -Tree::treeType() -{ - if (sTreeTypeName == NULL) { - std::vector dims; - Tree::getNodeLog2Dims(dims); - std::ostringstream ostr; - ostr << "Tree_" << typeNameAsString(); - for (size_t i = 1, N = dims.size(); i < N; ++i) { // start from 1 to skip the RootNode - ostr << "_" << dims[i]; - } - Name* s = new Name(ostr.str()); - if (sTreeTypeName.compare_and_swap(s, NULL) != NULL) delete s; - } - return *sTreeTypeName; -} - - -template -template -inline bool -Tree::hasSameTopology(const Tree& other) const -{ - return mRoot.hasSameTopology(other.root()); -} - - -template -Index64 -Tree::inactiveVoxelCount() const -{ - Coord dim(0, 0, 0); - this->evalActiveVoxelDim(dim); - const Index64 - totalVoxels = dim.x() * dim.y() * dim.z(), - activeVoxels = this->activeVoxelCount(); - assert(totalVoxels >= activeVoxels); - return totalVoxels - activeVoxels; -} - - -template -inline bool -Tree::evalLeafBoundingBox(CoordBBox& bbox) const -{ - bbox.reset(); // default invalid bbox - - if (this->empty()) return false; // empty - - mRoot.evalActiveBoundingBox(bbox, false); - - return true;// not empty -} - -template -inline bool -Tree::evalActiveVoxelBoundingBox(CoordBBox& bbox) const -{ - bbox.reset(); // default invalid bbox - - if (this->empty()) return false; // empty - - mRoot.evalActiveBoundingBox(bbox, true); - - return true;// not empty -} - - -template -inline bool -Tree::evalActiveVoxelDim(Coord& dim) const -{ - CoordBBox bbox; - bool notEmpty = this->evalActiveVoxelBoundingBox(bbox); - dim = bbox.extents(); - return notEmpty; -} - - -template -inline bool -Tree::evalLeafDim(Coord& dim) const -{ - CoordBBox bbox; - bool notEmpty = this->evalLeafBoundingBox(bbox); - dim = bbox.extents(); - return notEmpty; -} - - -template -inline void -Tree::evalMinMax(ValueType& minVal, ValueType& maxVal) const -{ - minVal = maxVal = zeroVal(); - if (ValueOnCIter iter = this->cbeginValueOn()) { - minVal = maxVal = *iter; - for (++iter; iter; ++iter) { - const ValueType& val = *iter; - if (val < minVal) minVal = val; - if (val > maxVal) maxVal = val; - } - } -} - - -template -inline void -Tree::getNodeLog2Dims(std::vector& dims) -{ - dims.clear(); - RootNodeType::getNodeLog2Dims(dims); -} - - -template -inline void -Tree::print(std::ostream& os, int verboseLevel) const -{ - if (verboseLevel <= 0) return; - - /// @todo Consider using boost::io::ios_precision_saver instead. - struct OnExit { - std::ostream& os; - std::streamsize savedPrecision; - OnExit(std::ostream& _os): os(_os), savedPrecision(os.precision()) {} - ~OnExit() { os.precision(savedPrecision); } - }; - OnExit restorePrecision(os); - - std::vector dims; - Tree::getNodeLog2Dims(dims); - - os << "Information about Tree:\n" - << " Type: " << this->type() << "\n"; - - os << " Configuration:\n"; - - if (verboseLevel <= 1) { - // Print node types and sizes. - os << " Root(" << mRoot.getTableSize() << ")"; - if (dims.size() > 1) { - for (size_t i = 1, N = dims.size() - 1; i < N; ++i) { - os << ", Internal(" << (1 << dims[i]) << "^3)"; - } - os << ", Leaf(" << (1 << *dims.rbegin()) << "^3)\n"; - } - os << " Background value: " << mRoot.background() << "\n"; - return; - } - - // The following is tree information that is expensive to extract. - - ValueType minVal = zeroVal(), maxVal = zeroVal(); - if (verboseLevel > 3) { - // This forces loading of all non-resident nodes. - this->evalMinMax(minVal, maxVal); - } - - std::vector nodeCount(dims.size()); -#ifndef OPENVDB_2_ABI_COMPATIBLE - Index64 unallocatedLeafCount = 0; -#endif - for (NodeCIter it = cbeginNode(); it; ++it) { - ++(nodeCount[it.getDepth()]); - -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (it.getLevel() == 0) { - const LeafNodeType* leaf = NULL; - it.getNode(leaf); - if (leaf && !leaf->isAllocated()) ++unallocatedLeafCount; - } -#endif - } - Index64 totalNodeCount = 0; - for (size_t i = 0; i < nodeCount.size(); ++i) totalNodeCount += nodeCount[i]; - - // Print node types, counts and sizes. - os << " Root(1 x " << mRoot.getTableSize() << ")"; - if (dims.size() > 1) { - for (size_t i = 1, N = dims.size() - 1; i < N; ++i) { - os << ", Internal(" << util::formattedInt(nodeCount[i]); - os << " x " << (1 << dims[i]) << "^3)"; - } - os << ", Leaf(" << util::formattedInt(*nodeCount.rbegin()); - os << " x " << (1 << *dims.rbegin()) << "^3)\n"; - } - os << " Background value: " << mRoot.background() << "\n"; - - // Statistics of topology and values - - if (verboseLevel > 3) { - os << " Min value: " << minVal << "\n"; - os << " Max value: " << maxVal << "\n"; - } - - const uint64_t - leafCount = *nodeCount.rbegin(), - numActiveVoxels = this->activeVoxelCount(), - numActiveLeafVoxels = this->activeLeafVoxelCount(); - - os << " Number of active voxels: " << util::formattedInt(numActiveVoxels) << "\n"; - - Coord dim(0, 0, 0); - uint64_t totalVoxels = 0; - if (numActiveVoxels) { // nonempty - CoordBBox bbox; - this->evalActiveVoxelBoundingBox(bbox); - dim = bbox.extents(); - totalVoxels = dim.x() * uint64_t(dim.y()) * dim.z(); - - os << " Bounding box of active voxels: " << bbox << "\n"; - os << " Dimensions of active voxels: " - << dim[0] << " x " << dim[1] << " x " << dim[2] << "\n"; - - const double activeRatio = (100.0 * double(numActiveVoxels)) / double(totalVoxels); - os << " Percentage of active voxels: " << std::setprecision(3) << activeRatio << "%\n"; - - if (leafCount > 0) { - const double fillRatio = (100.0 * double(numActiveLeafVoxels)) - / (double(leafCount) * double(LeafNodeType::NUM_VOXELS)); - os << " Average leaf node fill ratio: " << fillRatio << "%\n"; - } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - if (verboseLevel > 2) { - os << " Number of unallocated nodes: " - << util::formattedInt(unallocatedLeafCount) << " (" - << (100.0 * double(unallocatedLeafCount) / double(totalNodeCount)) << "%)\n"; - } -#endif - } else { - os << " Tree is empty!\n"; - } - os << std::flush; - - if (verboseLevel == 2) return; - - // Memory footprint in bytes - const uint64_t - actualMem = this->memUsage(), - denseMem = sizeof(ValueType) * totalVoxels, - voxelsMem = sizeof(ValueType) * numActiveLeafVoxels; - ///< @todo not accurate for BoolTree (and probably should count tile values) - - os << "Memory footprint:\n"; - util::printBytes(os, actualMem, " Actual: "); - util::printBytes(os, voxelsMem, " Active leaf voxels: "); - - if (numActiveVoxels) { - util::printBytes(os, denseMem, " Dense equivalent: "); - os << " Actual footprint is " << (100.0 * double(actualMem) / double(denseMem)) - << "% of an equivalent dense volume\n"; - os << " Leaf voxel footprint is " << (100.0 * double(voxelsMem) / double(actualMem)) - << "% of actual footprint\n"; - } -} - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_TREE_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/TreeIterator.h b/openvdb_3_0_0_library/tree/TreeIterator.h deleted file mode 100755 index 9aee38e..0000000 --- a/openvdb_3_0_0_library/tree/TreeIterator.h +++ /dev/null @@ -1,1405 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file TreeIterator.h - -#ifndef OPENVDB_TREE_TREEITERATOR_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_TREEITERATOR_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Prior to 0.96.1, depth-bounded value iterators always descended to the leaf level -// and iterated past leaf nodes. Now, they never descend past the maximum depth. -// Comment out the following line to restore the older, less-efficient behavior: -#define ENABLE_TREE_VALUE_DEPTH_BOUND_OPTIMIZATION - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -/// CopyConstness::Type is either const T2 or T2 with no const qualifier, -/// depending on whether T1 is const. For example, -/// - CopyConstness::Type is int -/// - CopyConstness::Type is int -/// - CopyConstness::Type is const int -/// - CopyConstness::Type is const int -template struct CopyConstness { - typedef typename boost::remove_const::type Type; -}; -template struct CopyConstness { - typedef const ToType Type; -}; - - -//////////////////////////////////////// - - -namespace iter { - -template -struct InvertedTree { - typedef typename InvertedTree::Type SubtreeT; - typedef typename boost::mpl::push_back::type Type; -}; -template -struct InvertedTree { - typedef typename boost::mpl::vector::type Type; -}; - -} // namespace iter - - -//////////////////////////////////////// - - -/// IterTraits provides the following for iterators of the standard types, -/// i.e., for {Child,Value}{On,Off,All}{Iter,CIter}: -/// - a NodeConverter template to convert an iterator for one type of node -/// to an iterator of the same type for another type of node; for example, -/// IterTraits::NodeConverter::Type -/// is synonymous with LeafNode::ValueOnIter. -/// - a begin(node) function that returns a begin iterator for a node of arbitrary type; -/// for example, IterTraits::begin(leaf) returns -/// leaf.beginValueOn() -/// - a getChild() function that returns a pointer to the child node to which the iterator -/// is currently pointing (always NULL if the iterator is a Value iterator) -template -struct IterTraits -{ - template static ChildT* getChild(const IterT&) { return NULL; } -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildOnIter IterT; - static IterT begin(NodeT& node) { return node.beginChildOn(); } - template static ChildT* getChild(const IterT& iter) { - return &iter.getValue(); - } - template struct NodeConverter { - typedef typename OtherNodeT::ChildOnIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildOnCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginChildOn(); } - template static const ChildT* getChild(const IterT& iter) { - return &iter.getValue(); - } - template struct NodeConverter { - typedef typename OtherNodeT::ChildOnCIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildOffIter IterT; - static IterT begin(NodeT& node) { return node.beginChildOff(); } - template struct NodeConverter { - typedef typename OtherNodeT::ChildOffIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildOffCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginChildOff(); } - template struct NodeConverter { - typedef typename OtherNodeT::ChildOffCIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildAllIter IterT; - static IterT begin(NodeT& node) { return node.beginChildAll(); } - template static ChildT* getChild(const IterT& iter) { - typename IterT::NonConstValueType val; - return iter.probeChild(val); - } - template struct NodeConverter { - typedef typename OtherNodeT::ChildAllIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ChildAllCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginChildAll(); } - template static ChildT* getChild(const IterT& iter) { - typename IterT::NonConstValueType val; - return iter.probeChild(val); - } - template struct NodeConverter { - typedef typename OtherNodeT::ChildAllCIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueOnIter IterT; - static IterT begin(NodeT& node) { return node.beginValueOn(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueOnIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueOnCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginValueOn(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueOnCIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueOffIter IterT; - static IterT begin(NodeT& node) { return node.beginValueOff(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueOffIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueOffCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginValueOff(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueOffCIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueAllIter IterT; - static IterT begin(NodeT& node) { return node.beginValueAll(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueAllIter Type; - }; -}; - -template -struct IterTraits -{ - typedef typename NodeT::ValueAllCIter IterT; - static IterT begin(const NodeT& node) { return node.cbeginValueAll(); } - template struct NodeConverter { - typedef typename OtherNodeT::ValueAllCIter Type; - }; -}; - - -//////////////////////////////////////// - - -/// @brief An IterListItem is an element of a compile-time linked list of iterators -/// to nodes of different types. -/// -/// The list is constructed by traversing the template hierarchy of a Tree in reverse order, -/// so typically the elements will be a LeafNode iterator of some type (e.g., ValueOnCIter), -/// followed by one or more InternalNode iterators of the same type, followed by a RootNode -/// iterator of the same type. -/// -/// The length of the list is fixed at compile time, and because it is implemented using -/// nested, templated classes, much of the list traversal logic can be optimized away. -template -class IterListItem -{ -public: - /// The type of iterator stored in the previous list item - typedef typename PrevItemT::IterT PrevIterT; - /// The type of node (non-const) whose iterator is stored in this list item - typedef typename boost::mpl::front::type _NodeT; - /// The type of iterator stored in this list item (e.g., InternalNode::ValueOnCIter) - typedef typename IterTraits::template - NodeConverter<_NodeT>::Type IterT; - - /// The type of node (const or non-const) over which IterT iterates (e.g., const RootNode<...>) - typedef typename IterT::NodeType NodeT; - /// The type of the node with const qualifiers removed ("Non-Const") - typedef typename IterT::NonConstNodeType NCNodeT; - /// The type of value (with const qualifiers removed) to which the iterator points - typedef typename IterT::NonConstValueType NCValueT; - /// NodeT's child node type, with the same constness (e.g., const InternalNode<...>) - typedef typename CopyConstness::Type ChildT; - /// NodeT's child node type with const qualifiers removed - typedef typename CopyConstness::Type NCChildT; - typedef IterTraits ITraits; - /// NodeT's level in its tree (0 = LeafNode) - static const Index Level = _Level; - - IterListItem(PrevItemT* prev): mNext(this), mPrev(prev) {} - - IterListItem(const IterListItem& other): mIter(other.mIter), mNext(other.mNext), mPrev(NULL) {} - IterListItem& operator=(const IterListItem& other) - { - if (&other != this) { - mIter = other.mIter; - mNext = other.mNext; - mPrev = NULL; ///< @note external call to updateBackPointers() required - } - return *this; - } - - void updateBackPointers(PrevItemT* prev) { mPrev = prev; mNext.updateBackPointers(this); } - - void setIter(const IterT& iter) { mIter = iter; } - template - void setIter(const OtherIterT& iter) { mNext.setIter(iter); } - - /// Return the node over which this list element's iterator iterates. - void getNode(Index lvl, NodeT*& node) const - { - node = (lvl <= Level) ? mIter.getParentNode() : NULL; - } - /// Return the node over which one of the following list elements' iterator iterates. - template - void getNode(Index lvl, OtherNodeT*& node) const { mNext.getNode(lvl, node); } - - /// @brief Initialize the iterator for level @a lvl of the tree with the node - /// over which the corresponding iterator of @a otherListItem is iterating. - /// - /// For example, if @a otherListItem contains a LeafNode::ValueOnIter, - /// initialize this list's leaf iterator with the same LeafNode. - template - void initLevel(Index lvl, OtherIterListItemT& otherListItem) - { - if (lvl == Level) { - const NodeT* node = NULL; - otherListItem.getNode(lvl, node); - mIter = (node == NULL) ? IterT() : ITraits::begin(*const_cast(node)); - } else { - // Forward to one of the following list elements. - mNext.initLevel(lvl, otherListItem); - } - } - - /// Return The table offset of the iterator at level @a lvl of the tree. - Index pos(Index lvl) const { return (lvl == Level) ? mIter.pos() : mNext.pos(lvl); } - - /// Return @c true if the iterator at level @a lvl of the tree has not yet reached its end. - bool test(Index lvl) const { return (lvl == Level) ? mIter.test() : mNext.test(lvl); } - - /// Increment the iterator at level @a lvl of the tree. - bool next(Index lvl) { return (lvl == Level) ? mIter.next() : mNext.next(lvl); } - - /// @brief If the iterator at level @a lvl of the tree points to a child node, - /// initialize the next iterator in this list with that child node. - bool down(Index lvl) - { - if (lvl == Level && mPrev != NULL && mIter) { - if (ChildT* child = ITraits::template getChild(mIter)) { - mPrev->setIter(PrevItemT::ITraits::begin(*child)); - return true; - } - } - return (lvl > Level) ? mNext.down(lvl) : false; - } - - /// @brief Return the global coordinates of the voxel or tile to which the iterator - /// at level @a lvl of the tree is currently pointing. - Coord getCoord(Index lvl) const - { - return (lvl == Level) ? mIter.getCoord() : mNext.getCoord(lvl); - } - Index getChildDim(Index lvl) const - { - return (lvl == Level) ? NodeT::getChildDim() : mNext.getChildDim(lvl); - } - /// Return the number of (virtual) voxels spanned by a tile value or child node - Index64 getVoxelCount(Index lvl) const - { - return (lvl == Level) ? ChildT::NUM_VOXELS : mNext.getVoxelCount(lvl); - } - - /// Return @c true if the iterator at level @a lvl of the tree points to an active value. - bool isValueOn(Index lvl) const - { - return (lvl == Level) ? mIter.isValueOn() : mNext.isValueOn(lvl); - } - - /// Return the value to which the iterator at level @a lvl of the tree points. - const NCValueT& getValue(Index lvl) const - { - if (lvl == Level) return mIter.getValue(); - return mNext.getValue(lvl); - } - - /// @brief Set the value (to @a val) to which the iterator at level @a lvl - /// of the tree points and mark the value as active. - /// @note Not valid when @c IterT is a const iterator type - void setValue(Index lvl, const NCValueT& val) const - { - if (lvl == Level) mIter.setValue(val); else mNext.setValue(lvl, val); - } - /// @brief Set the value (to @a val) to which the iterator at level @a lvl of the tree - /// points and mark the value as active if @a on is @c true, or inactive otherwise. - /// @note Not valid when @c IterT is a const iterator type - void setValueOn(Index lvl, bool on = true) const - { - if (lvl == Level) mIter.setValueOn(on); else mNext.setValueOn(lvl, on); - } - /// @brief Mark the value to which the iterator at level @a lvl of the tree points - /// as inactive. - /// @note Not valid when @c IterT is a const iterator type - void setValueOff(Index lvl) const - { - if (lvl == Level) mIter.setValueOff(); else mNext.setValueOff(lvl); - } - - /// @brief Apply a functor to the item to which this iterator is pointing. - /// @note Not valid when @c IterT is a const iterator type - template - void modifyValue(Index lvl, const ModifyOp& op) const - { - if (lvl == Level) mIter.modifyValue(op); else mNext.modifyValue(lvl, op); - } - -private: - typedef typename boost::mpl::pop_front::type RestT; // NodeVecT minus its first item - typedef IterListItem NextItem; - - IterT mIter; - NextItem mNext; - PrevItemT* mPrev; -}; - - -/// The initial element of a compile-time linked list of iterators to nodes of different types -template -class IterListItem -{ -public: - /// The type of iterator stored in the previous list item - typedef typename PrevItemT::IterT PrevIterT; - /// The type of node (non-const) whose iterator is stored in this list item - typedef typename boost::mpl::front::type _NodeT; - /// The type of iterator stored in this list item (e.g., InternalNode::ValueOnCIter) - typedef typename IterTraits::template - NodeConverter<_NodeT>::Type IterT; - - /// The type of node (const or non-const) over which IterT iterates (e.g., const RootNode<...>) - typedef typename IterT::NodeType NodeT; - /// The type of the node with const qualifiers removed ("Non-Const") - typedef typename IterT::NonConstNodeType NCNodeT; - /// The type of value (with const qualifiers removed) to which the iterator points - typedef typename IterT::NonConstValueType NCValueT; - typedef IterTraits ITraits; - /// NodeT's level in its tree (0 = LeafNode) - static const Index Level = 0; - - IterListItem(PrevItemT*): mNext(this), mPrev(NULL) {} - - IterListItem(const IterListItem& other): mIter(other.mIter), mNext(other.mNext), mPrev(NULL) {} - IterListItem& operator=(const IterListItem& other) - { - if (&other != this) { - mIter = other.mIter; - mNext = other.mNext; - mPrev = NULL; - } - return *this; - } - - void updateBackPointers(PrevItemT* = NULL) { mPrev = NULL; mNext.updateBackPointers(this); } - - void setIter(const IterT& iter) { mIter = iter; } - template - void setIter(const OtherIterT& iter) { mNext.setIter(iter); } - - void getNode(Index lvl, NodeT*& node) const - { - node = (lvl == 0) ? mIter.getParentNode() : NULL; - } - template - void getNode(Index lvl, OtherNodeT*& node) const { mNext.getNode(lvl, node); } - - template - void initLevel(Index lvl, OtherIterListItemT& otherListItem) - { - if (lvl == 0) { - const NodeT* node = NULL; - otherListItem.getNode(lvl, node); - mIter = (node == NULL) ? IterT() : ITraits::begin(*const_cast(node)); - } else { - mNext.initLevel(lvl, otherListItem); - } - } - - Index pos(Index lvl) const { return (lvl == 0) ? mIter.pos() : mNext.pos(lvl); } - - bool test(Index lvl) const { return (lvl == 0) ? mIter.test() : mNext.test(lvl); } - - bool next(Index lvl) { return (lvl == 0) ? mIter.next() : mNext.next(lvl); } - - bool down(Index lvl) { return (lvl == 0) ? false : mNext.down(lvl); } - - Coord getCoord(Index lvl) const - { - return (lvl == 0) ? mIter.getCoord() : mNext.getCoord(lvl); - } - Index getChildDim(Index lvl) const - { - return (lvl == 0) ? NodeT::getChildDim() : mNext.getChildDim(lvl); - } - - Index64 getVoxelCount(Index lvl) const - { - return (lvl == 0) ? 1 : mNext.getVoxelCount(lvl); - } - - bool isValueOn(Index lvl) const - { - return (lvl == 0) ? mIter.isValueOn() : mNext.isValueOn(lvl); - } - - const NCValueT& getValue(Index lvl) const - { - if (lvl == 0) return mIter.getValue(); - return mNext.getValue(lvl); - } - - void setValue(Index lvl, const NCValueT& val) const - { - if (lvl == 0) mIter.setValue(val); else mNext.setValue(lvl, val); - } - void setValueOn(Index lvl, bool on = true) const - { - if (lvl == 0) mIter.setValueOn(on); else mNext.setValueOn(lvl, on); - } - void setValueOff(Index lvl) const - { - if (lvl == 0) mIter.setValueOff(); else mNext.setValueOff(lvl); - } - - template - void modifyValue(Index lvl, const ModifyOp& op) const - { - if (lvl == 0) mIter.modifyValue(op); else mNext.modifyValue(lvl, op); - } - -private: - typedef typename boost::mpl::pop_front::type RestT; // NodeVecT minus its first item - typedef IterListItem NextItem; - - IterT mIter; - NextItem mNext; - PrevItemT* mPrev; -}; - - -/// The final element of a compile-time linked list of iterators to nodes of different types -template -class IterListItem -{ -public: - typedef typename boost::mpl::front::type _NodeT; - /// The type of iterator stored in the previous list item - typedef typename PrevItemT::IterT PrevIterT; - /// The type of iterator stored in this list item (e.g., RootNode::ValueOnCIter) - typedef typename IterTraits::template - NodeConverter<_NodeT>::Type IterT; - - /// The type of node over which IterT iterates (e.g., const RootNode<...>) - typedef typename IterT::NodeType NodeT; - /// The type of the node with const qualifiers removed ("Non-Const") - typedef typename IterT::NonConstNodeType NCNodeT; - /// The type of value (with const qualifiers removed) to which the iterator points - typedef typename IterT::NonConstValueType NCValueT; - /// NodeT's child node type, with the same constness (e.g., const InternalNode<...>) - typedef typename CopyConstness::Type ChildT; - /// NodeT's child node type with const qualifiers removed - typedef typename CopyConstness::Type NCChildT; - typedef IterTraits ITraits; - /// NodeT's level in its tree (0 = LeafNode) - static const Index Level = _Level; - - IterListItem(PrevItemT* prev): mPrev(prev) {} - - IterListItem(const IterListItem& other): mIter(other.mIter), mPrev(NULL) {} - IterListItem& operator=(const IterListItem& other) - { - if (&other != this) { - mIter = other.mIter; - mPrev = NULL; ///< @note external call to updateBackPointers() required - } - return *this; - } - - void updateBackPointers(PrevItemT* prev) { mPrev = prev; } - - // The following method specializations differ from the default template - // implementations mainly in that they don't forward. - - void setIter(const IterT& iter) { mIter = iter; } - - void getNode(Index lvl, NodeT*& node) const - { - node = (lvl <= Level) ? mIter.getParentNode() : NULL; - } - - template - void initLevel(Index lvl, OtherIterListItemT& otherListItem) - { - if (lvl == Level) { - const NodeT* node = NULL; - otherListItem.getNode(lvl, node); - mIter = (node == NULL) ? IterT() : ITraits::begin(*const_cast(node)); - } - } - - Index pos(Index lvl) const { return (lvl == Level) ? mIter.pos() : Index(-1); } - - bool test(Index lvl) const { return (lvl == Level) ? mIter.test() : false; } - - bool next(Index lvl) { return (lvl == Level) ? mIter.next() : false; } - - bool down(Index lvl) - { - if (lvl == Level && mPrev != NULL && mIter) { - if (ChildT* child = ITraits::template getChild(mIter)) { - mPrev->setIter(PrevItemT::ITraits::begin(*child)); - return true; - } - } - return false; - } - - Coord getCoord(Index lvl) const { return (lvl == Level) ? mIter.getCoord() : Coord(); } - Index getChildDim(Index lvl) const { return (lvl == Level) ? NodeT::getChildDim() : 0; } - Index64 getVoxelCount(Index lvl) const { return (lvl == Level) ? ChildT::NUM_VOXELS : 0; } - - bool isValueOn(Index lvl) const { return (lvl == Level) ? mIter.isValueOn() : false; } - - const NCValueT& getValue(Index lvl) const - { - assert(lvl == Level); - (void)lvl; // avoid unused variable warning in optimized builds - return mIter.getValue(); - } - - void setValue(Index lvl, const NCValueT& val) const { if (lvl == Level) mIter.setValue(val); } - void setValueOn(Index lvl, bool on = true) const { if (lvl == Level) mIter.setValueOn(on); } - void setValueOff(Index lvl) const { if (lvl == Level) mIter.setValueOff(); } - - template - void modifyValue(Index lvl, const ModifyOp& op) const - { - if (lvl == Level) mIter.modifyValue(op); - } - -private: - IterT mIter; - PrevItemT* mPrev; -}; - - -//////////////////////////////////////// - - -//#define DEBUG_TREE_VALUE_ITERATOR - -/// @brief Base class for tree-traversal iterators over tile and voxel values -template -class TreeValueIteratorBase -{ -public: - typedef _TreeT TreeT; - typedef _ValueIterT ValueIterT; - typedef typename ValueIterT::NodeType NodeT; - typedef typename ValueIterT::NonConstValueType ValueT; - typedef typename NodeT::ChildOnCIter ChildOnIterT; - static const Index ROOT_LEVEL = NodeT::LEVEL; - BOOST_STATIC_ASSERT(ValueIterT::NodeType::LEVEL == ROOT_LEVEL); - static const Index LEAF_LEVEL = 0, ROOT_DEPTH = 0, LEAF_DEPTH = ROOT_LEVEL; - - TreeValueIteratorBase(TreeT&); - - TreeValueIteratorBase(const TreeValueIteratorBase& other); - TreeValueIteratorBase& operator=(const TreeValueIteratorBase& other); - - /// Specify the depth of the highest level of the tree to which to ascend (depth 0 = root). - void setMinDepth(Index minDepth); - /// Return the depth of the highest level of the tree to which this iterator ascends. - Index getMinDepth() const { return ROOT_LEVEL - Index(mMaxLevel); } - /// Specify the depth of the lowest level of the tree to which to descend (depth 0 = root). - void setMaxDepth(Index maxDepth); - /// Return the depth of the lowest level of the tree to which this iterator ascends. - Index getMaxDepth() const { return ROOT_LEVEL - Index(mMinLevel); } - - //@{ - /// Return @c true if this iterator is not yet exhausted. - bool test() const { return mValueIterList.test(mLevel); } - operator bool() const { return this->test(); } - //@} - - /// @brief Advance to the next tile or voxel value. - /// Return @c true if this iterator is not yet exhausted. - bool next(); - /// Advance to the next tile or voxel value. - TreeValueIteratorBase& operator++() { this->next(); return *this; } - - /// @brief Return the level in the tree (0 = leaf) of the node to which - /// this iterator is currently pointing. - Index getLevel() const { return mLevel; } - /// @brief Return the depth in the tree (0 = root) of the node to which - /// this iterator is currently pointing. - Index getDepth() const { return ROOT_LEVEL - mLevel; } - static Index getLeafDepth() { return LEAF_DEPTH; } - - /// @brief Return in @a node a pointer to the node over which this iterator is - /// currently iterating or one of that node's parents, as determined by @a NodeType. - /// @return a null pointer if @a NodeType specifies a node at a lower level - /// of the tree than that given by getLevel(). - template - void getNode(NodeType*& node) const { mValueIterList.getNode(mLevel, node); } - - /// @brief Return the global coordinates of the voxel or tile to which - /// this iterator is currently pointing. - Coord getCoord() const { return mValueIterList.getCoord(mLevel); } - /// @brief Return in @a bbox the axis-aligned bounding box of - /// the voxel or tile to which this iterator is currently pointing. - /// @return false if the bounding box is empty. - bool getBoundingBox(CoordBBox&) const; - /// @brief Return the axis-aligned bounding box of the voxel or tile to which - /// this iterator is currently pointing. - CoordBBox getBoundingBox() const { CoordBBox b; this->getBoundingBox(b); return b; } - - /// Return the number of (virtual) voxels corresponding to the value - Index64 getVoxelCount() const { return mValueIterList.getVoxelCount(mLevel);} - - /// Return @c true if this iterator is currently pointing to a (non-leaf) tile value. - bool isTileValue() const { return mLevel != 0 && this->test(); } - /// Return @c true if this iterator is currently pointing to a (leaf) voxel value. - bool isVoxelValue() const { return mLevel == 0 && this->test(); } - /// Return @c true if the value to which this iterator is currently pointing is active. - bool isValueOn() const { return mValueIterList.isValueOn(mLevel); } - - //@{ - /// Return the tile or voxel value to which this iterator is currently pointing. - const ValueT& getValue() const { return mValueIterList.getValue(mLevel); } - const ValueT& operator*() const { return this->getValue(); } - const ValueT* operator->() const { return &(this->operator*()); } - //@} - - /// @brief Change the tile or voxel value to which this iterator is currently pointing - /// and mark it as active. - void setValue(const ValueT& val) const { mValueIterList.setValue(mLevel, val); } - /// @brief Change the active/inactive state of the tile or voxel value to which - /// this iterator is currently pointing. - void setActiveState(bool on) const { mValueIterList.setValueOn(mLevel, on); } - /// Mark the tile or voxel value to which this iterator is currently pointing as inactive. - void setValueOff() const { mValueIterList.setValueOff(mLevel); } - - /// @brief Apply a functor to the item to which this iterator is pointing. - /// (Not valid for const iterators.) - /// @param op a functor of the form void op(ValueType&) const that modifies - /// its argument in place - /// @see Tree::modifyValue() - template - void modifyValue(const ModifyOp& op) const { mValueIterList.modifyValue(mLevel, op); } - - /// Return a pointer to the tree over which this iterator is iterating. - TreeT* getTree() const { return mTree; } - - /// Return a string (for debugging, mainly) describing this iterator's current state. - std::string summary() const; - -private: - bool advance(bool dontIncrement = false); - - typedef typename iter::InvertedTree::Type InvTreeT; - struct PrevChildItem { typedef ChildOnIterT IterT; }; - struct PrevValueItem { typedef ValueIterT IterT; }; - - IterListItem mChildIterList; - IterListItem mValueIterList; - Index mLevel; - int mMinLevel, mMaxLevel; - TreeT* mTree; -}; // class TreeValueIteratorBase - - -template -inline -TreeValueIteratorBase::TreeValueIteratorBase(TreeT& tree): - mChildIterList(NULL), - mValueIterList(NULL), - mLevel(ROOT_LEVEL), - mMinLevel(int(LEAF_LEVEL)), - mMaxLevel(int(ROOT_LEVEL)), - mTree(&tree) -{ - mChildIterList.setIter(IterTraits::begin(tree.root())); - mValueIterList.setIter(IterTraits::begin(tree.root())); - this->advance(/*dontIncrement=*/true); -} - - -template -inline -TreeValueIteratorBase::TreeValueIteratorBase(const TreeValueIteratorBase& other): - mChildIterList(other.mChildIterList), - mValueIterList(other.mValueIterList), - mLevel(other.mLevel), - mMinLevel(other.mMinLevel), - mMaxLevel(other.mMaxLevel), - mTree(other.mTree) -{ - mChildIterList.updateBackPointers(); - mValueIterList.updateBackPointers(); -} - - -template -inline TreeValueIteratorBase& -TreeValueIteratorBase::operator=(const TreeValueIteratorBase& other) -{ - if (&other != this) { - mChildIterList = other.mChildIterList; - mValueIterList = other.mValueIterList; - mLevel = other.mLevel; - mMinLevel = other.mMinLevel; - mMaxLevel = other.mMaxLevel; - mTree = other.mTree; - mChildIterList.updateBackPointers(); - mValueIterList.updateBackPointers(); - } - return *this; -} - - -template -inline void -TreeValueIteratorBase::setMinDepth(Index minDepth) -{ - mMaxLevel = int(ROOT_LEVEL - minDepth); // level = ROOT_LEVEL - depth - if (int(mLevel) > mMaxLevel) this->next(); -} - - -template -inline void -TreeValueIteratorBase::setMaxDepth(Index maxDepth) -{ - // level = ROOT_LEVEL - depth - mMinLevel = int(ROOT_LEVEL - std::min(maxDepth, this->getLeafDepth())); - if (int(mLevel) < mMinLevel) this->next(); -} - - -template -inline bool -TreeValueIteratorBase::next() -{ - do { - if (!this->advance()) return false; - } while (int(mLevel) < mMinLevel || int(mLevel) > mMaxLevel); - return true; -} - - -template -inline bool -TreeValueIteratorBase::advance(bool dontIncrement) -{ - bool recurse = false; - do { - recurse = false; - Index - vPos = mValueIterList.pos(mLevel), - cPos = mChildIterList.pos(mLevel); - if (vPos == cPos && mChildIterList.test(mLevel)) { - /// @todo Once ValueOff iterators properly skip child pointers, remove this block. - mValueIterList.next(mLevel); - vPos = mValueIterList.pos(mLevel); - } - if (vPos < cPos) { - if (dontIncrement) return true; - if (mValueIterList.next(mLevel)) { - if (mValueIterList.pos(mLevel) == cPos && mChildIterList.test(mLevel)) { - /// @todo Once ValueOff iterators properly skip child pointers, - /// remove this block. - mValueIterList.next(mLevel); - } - // If there is a next value and it precedes the next child, return. - if (mValueIterList.pos(mLevel) < cPos) return true; - } - } else { - // Advance to the next child, which may or may not precede the next value. - if (!dontIncrement) mChildIterList.next(mLevel); - } -#ifdef DEBUG_TREE_VALUE_ITERATOR - std::cout << "\n" << this->summary() << std::flush; -#endif - - // Descend to the lowest level at which the next value precedes the next child. - while (mChildIterList.pos(mLevel) < mValueIterList.pos(mLevel)) { -#ifdef ENABLE_TREE_VALUE_DEPTH_BOUND_OPTIMIZATION - if (int(mLevel) == mMinLevel) { - // If the current node lies at the lowest allowed level, none of its - // children can be visited, so just advance its child iterator. - mChildIterList.next(mLevel); - if (mValueIterList.pos(mLevel) == mChildIterList.pos(mLevel) - && mChildIterList.test(mLevel)) - { - /// @todo Once ValueOff iterators properly skip child pointers, - /// remove this block. - mValueIterList.next(mLevel); - } - } else -#endif - if (mChildIterList.down(mLevel)) { - --mLevel; // descend one level - mValueIterList.initLevel(mLevel, mChildIterList); - if (mValueIterList.pos(mLevel) == mChildIterList.pos(mLevel) - && mChildIterList.test(mLevel)) - { - /// @todo Once ValueOff iterators properly skip child pointers, - /// remove this block. - mValueIterList.next(mLevel); - } - } else break; -#ifdef DEBUG_TREE_VALUE_ITERATOR - std::cout << "\n" << this->summary() << std::flush; -#endif - } - // Ascend to the nearest level at which one of the iterators is not yet exhausted. - while (!mChildIterList.test(mLevel) && !mValueIterList.test(mLevel)) { - if (mLevel == ROOT_LEVEL) return false; - ++mLevel; - mChildIterList.next(mLevel); - dontIncrement = true; - recurse = true; - } - } while (recurse); - return true; -} - - -template -inline bool -TreeValueIteratorBase::getBoundingBox(CoordBBox& bbox) const -{ - if (!this->test()) { - bbox = CoordBBox(); - return false; - } - bbox.min() = mValueIterList.getCoord(mLevel); - bbox.max() = bbox.min().offsetBy(mValueIterList.getChildDim(mLevel) - 1); - return true; -} - - -template -inline std::string -TreeValueIteratorBase::summary() const -{ - std::ostringstream ostr; - for (int lvl = int(ROOT_LEVEL); lvl >= 0 && lvl >= int(mLevel); --lvl) { - if (lvl == 0) ostr << "leaf"; - else if (lvl == int(ROOT_LEVEL)) ostr << "root"; - else ostr << "int" << (ROOT_LEVEL - lvl); - ostr << " v" << mValueIterList.pos(lvl) - << " c" << mChildIterList.pos(lvl); - if (lvl > int(mLevel)) ostr << " / "; - } - if (this->test() && mValueIterList.pos(mLevel) < mChildIterList.pos(mLevel)) { - if (mLevel == 0) { - ostr << " " << this->getCoord(); - } else { - ostr << " " << this->getBoundingBox(); - } - } - return ostr.str(); -} - - -//////////////////////////////////////// - - -/// @brief Base class for tree-traversal iterators over all nodes -template -class NodeIteratorBase -{ -public: - typedef _TreeT TreeT; - typedef RootChildOnIterT RootIterT; - typedef typename RootIterT::NodeType RootNodeT; - typedef typename RootIterT::NonConstNodeType NCRootNodeT; - static const Index ROOT_LEVEL = RootNodeT::LEVEL; - typedef typename iter::InvertedTree::Type InvTreeT; - static const Index LEAF_LEVEL = 0, ROOT_DEPTH = 0, LEAF_DEPTH = ROOT_LEVEL; - - typedef IterTraits RootIterTraits; - - NodeIteratorBase(); - NodeIteratorBase(TreeT&); - - NodeIteratorBase(const NodeIteratorBase& other); - NodeIteratorBase& operator=(const NodeIteratorBase& other); - - /// Specify the depth of the highest level of the tree to which to ascend (depth 0 = root). - void setMinDepth(Index minDepth); - /// Return the depth of the highest level of the tree to which this iterator ascends. - Index getMinDepth() const { return ROOT_LEVEL - Index(mMaxLevel); } - /// Specify the depth of the lowest level of the tree to which to descend (depth 0 = root). - void setMaxDepth(Index maxDepth); - /// Return the depth of the lowest level of the tree to which this iterator ascends. - Index getMaxDepth() const { return ROOT_LEVEL - Index(mMinLevel); } - - //@{ - /// Return @c true if this iterator is not yet exhausted. - bool test() const { return !mDone; } - operator bool() const { return this->test(); } - //@} - - /// @brief Advance to the next tile or voxel value. - /// @return @c true if this iterator is not yet exhausted. - bool next(); - /// Advance the iterator to the next leaf node. - void increment() { this->next(); } - NodeIteratorBase& operator++() { this->increment(); return *this; } - /// Increment the iterator n times. - void increment(Index n) { for (Index i = 0; i < n && this->next(); ++i) {} } - - /// @brief Return the level in the tree (0 = leaf) of the node to which - /// this iterator is currently pointing. - Index getLevel() const { return mLevel; } - /// @brief Return the depth in the tree (0 = root) of the node to which - /// this iterator is currently pointing. - Index getDepth() const { return ROOT_LEVEL - mLevel; } - static Index getLeafDepth() { return LEAF_DEPTH; } - - /// @brief Return the global coordinates of the voxel or tile to which - /// this iterator is currently pointing. - Coord getCoord() const; - /// @brief Return in @a bbox the axis-aligned bounding box of - /// the voxel or tile to which this iterator is currently pointing. - /// @return false if the bounding box is empty. - bool getBoundingBox(CoordBBox& bbox) const; - /// @brief Return the axis-aligned bounding box of the voxel or tile to which - /// this iterator is currently pointing. - CoordBBox getBoundingBox() const { CoordBBox b; this->getBoundingBox(b); return b; } - - //@{ - /// @brief Return the node to which the iterator is pointing. - /// @note This iterator doesn't have the usual dereference operators (* and ->), - /// because they would have to be overloaded by the returned node type. - template - void getNode(NodeT*& node) const { node = NULL; mIterList.getNode(mLevel, node); } - template - void getNode(const NodeT*& node) const { node = NULL; mIterList.getNode(mLevel, node); } - //@} - - TreeT* getTree() const { return mTree; } - - std::string summary() const; - -private: - struct PrevItem { typedef RootIterT IterT; }; - - IterListItem mIterList; - Index mLevel; - int mMinLevel, mMaxLevel; - bool mDone; - TreeT* mTree; -}; // class NodeIteratorBase - - -template -inline -NodeIteratorBase::NodeIteratorBase(): - mIterList(NULL), - mLevel(ROOT_LEVEL), - mMinLevel(int(LEAF_LEVEL)), - mMaxLevel(int(ROOT_LEVEL)), - mDone(true), - mTree(NULL) -{ -} - - -template -inline -NodeIteratorBase::NodeIteratorBase(TreeT& tree): - mIterList(NULL), - mLevel(ROOT_LEVEL), - mMinLevel(int(LEAF_LEVEL)), - mMaxLevel(int(ROOT_LEVEL)), - mDone(false), - mTree(&tree) -{ - mIterList.setIter(RootIterTraits::begin(tree.root())); -} - - -template -inline -NodeIteratorBase::NodeIteratorBase(const NodeIteratorBase& other): - mIterList(other.mIterList), - mLevel(other.mLevel), - mMinLevel(other.mMinLevel), - mMaxLevel(other.mMaxLevel), - mDone(other.mDone), - mTree(other.mTree) -{ - mIterList.updateBackPointers(); -} - - -template -inline NodeIteratorBase& -NodeIteratorBase::operator=(const NodeIteratorBase& other) -{ - if (&other != this) { - mLevel = other.mLevel; - mMinLevel = other.mMinLevel; - mMaxLevel = other.mMaxLevel; - mDone = other.mDone; - mTree = other.mTree; - mIterList = other.mIterList; - mIterList.updateBackPointers(); - } - return *this; -} - - -template -inline void -NodeIteratorBase::setMinDepth(Index minDepth) -{ - mMaxLevel = int(ROOT_LEVEL - minDepth); // level = ROOT_LEVEL - depth - if (int(mLevel) > mMaxLevel) this->next(); -} - - -template -inline void -NodeIteratorBase::setMaxDepth(Index maxDepth) -{ - // level = ROOT_LEVEL - depth - mMinLevel = int(ROOT_LEVEL - std::min(maxDepth, this->getLeafDepth())); - if (int(mLevel) < mMinLevel) this->next(); -} - - -template -inline bool -NodeIteratorBase::next() -{ - do { - if (mDone) return false; - - // If the iterator over the current node points to a child, - // descend to the child (depth-first traversal). - if (int(mLevel) > mMinLevel && mIterList.test(mLevel)) { - if (!mIterList.down(mLevel)) return false; - --mLevel; - } else { - // Ascend to the nearest ancestor that has other children. - while (!mIterList.test(mLevel)) { - if (mLevel == ROOT_LEVEL) { - // Can't ascend higher than the root. - mDone = true; - return false; - } - ++mLevel; // ascend one level - mIterList.next(mLevel); // advance to the next child, if there is one - } - // Descend to the child. - if (!mIterList.down(mLevel)) return false; - --mLevel; - } - } while (int(mLevel) < mMinLevel || int(mLevel) > mMaxLevel); - return true; -} - - -template -inline Coord -NodeIteratorBase::getCoord() const -{ - if (mLevel != ROOT_LEVEL) return mIterList.getCoord(mLevel + 1); - RootNodeT* root = NULL; - this->getNode(root); - return root ? root->getMinIndex() : Coord::min(); -} - - -template -inline bool -NodeIteratorBase::getBoundingBox(CoordBBox& bbox) const -{ - if (mLevel == ROOT_LEVEL) { - RootNodeT* root = NULL; - this->getNode(root); - if (root == NULL) { - bbox = CoordBBox(); - return false; - } - root->getIndexRange(bbox); - return true; - } - bbox.min() = mIterList.getCoord(mLevel + 1); - bbox.max() = bbox.min().offsetBy(mIterList.getChildDim(mLevel + 1) - 1); - return true; -} - - -template -inline std::string -NodeIteratorBase::summary() const -{ - std::ostringstream ostr; - for (int lvl = int(ROOT_LEVEL); lvl >= 0 && lvl >= int(mLevel); --lvl) { - if (lvl == 0) ostr << "leaf"; - else if (lvl == int(ROOT_LEVEL)) ostr << "root"; - else ostr << "int" << (ROOT_LEVEL - lvl); - ostr << " c" << mIterList.pos(lvl); - if (lvl > int(mLevel)) ostr << " / "; - } - CoordBBox bbox; - this->getBoundingBox(bbox); - ostr << " " << bbox; - return ostr.str(); -} - - -//////////////////////////////////////// - - -/// @brief Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) -template -class LeafIteratorBase -{ -public: - typedef RootChildOnIterT RootIterT; - typedef typename RootIterT::NodeType RootNodeT; - typedef typename RootIterT::NonConstNodeType NCRootNodeT; - static const Index ROOT_LEVEL = RootNodeT::LEVEL; - typedef typename iter::InvertedTree::Type InvTreeT; - typedef typename boost::mpl::front::type NCLeafNodeT; - typedef typename CopyConstness::Type LeafNodeT; - static const Index LEAF_LEVEL = 0, LEAF_PARENT_LEVEL = LEAF_LEVEL + 1; - - typedef IterTraits RootIterTraits; - - LeafIteratorBase(): mIterList(NULL), mTree(NULL) {} - - LeafIteratorBase(TreeT& tree): mIterList(NULL), mTree(&tree) - { - // Initialize the iterator list with a root node iterator. - mIterList.setIter(RootIterTraits::begin(tree.root())); - // Descend along the first branch, initializing the node iterator at each level. - Index lvl = ROOT_LEVEL; - for ( ; lvl > 0 && mIterList.down(lvl); --lvl) {} - // If the first branch terminated above the leaf level, backtrack to the next branch. - if (lvl > 0) this->next(); - } - - LeafIteratorBase(const LeafIteratorBase& other): mIterList(other.mIterList), mTree(other.mTree) - { - mIterList.updateBackPointers(); - } - LeafIteratorBase& operator=(const LeafIteratorBase& other) - { - if (&other != this) { - mTree = other.mTree; - mIterList = other.mIterList; - mIterList.updateBackPointers(); - } - return *this; - } - - //@{ - /// Return the leaf node to which the iterator is pointing. - LeafNodeT* getLeaf() const { LeafNodeT* n = NULL; mIterList.getNode(LEAF_LEVEL, n); return n; } - LeafNodeT& operator*() const { return *this->getLeaf(); } - LeafNodeT* operator->() const { return this->getLeaf(); } - //@} - - bool test() const { return mIterList.test(LEAF_PARENT_LEVEL); } - operator bool() const { return this->test(); } - - //@{ - /// Advance the iterator to the next leaf node. - bool next(); - void increment() { this->next(); } - LeafIteratorBase& operator++() { this->increment(); return *this; } - //@} - /// Increment the iterator n times. - void increment(Index n) { for (Index i = 0; i < n && this->next(); ++i) {} } - - TreeT* getTree() const { return mTree; } - -private: - struct PrevItem { typedef RootIterT IterT; }; - - /// @note Even though a LeafIterator doesn't iterate over leaf voxels, - /// the first item of this linked list of node iterators is a leaf node iterator, - /// whose purpose is only to provide access to its parent leaf node. - IterListItem mIterList; - TreeT* mTree; -}; // class LeafIteratorBase - - -template -inline bool -LeafIteratorBase::next() -{ - // If the iterator is valid for the current node one level above the leaf level, - // advance the iterator to the node's next child. - if (mIterList.test(LEAF_PARENT_LEVEL) && mIterList.next(LEAF_PARENT_LEVEL)) { - mIterList.down(LEAF_PARENT_LEVEL); // initialize the leaf iterator - return true; - } - - Index lvl = LEAF_PARENT_LEVEL; - while (!mIterList.test(LEAF_PARENT_LEVEL)) { - if (mIterList.test(lvl)) { - mIterList.next(lvl); - } else { - do { - // Ascend to the nearest level at which - // one of the iterators is not yet exhausted. - if (lvl == ROOT_LEVEL) return false; - ++lvl; - if (mIterList.test(lvl)) mIterList.next(lvl); - } while (!mIterList.test(lvl)); - } - // Descend to the lowest child, but not as far as the leaf iterator. - while (lvl > LEAF_PARENT_LEVEL && mIterList.down(lvl)) --lvl; - } - mIterList.down(LEAF_PARENT_LEVEL); // initialize the leaf iterator - return true; -} - - -//////////////////////////////////////// - - -/// An IteratorRange wraps a tree or node iterator, giving the iterator TBB -/// splittable range semantics. -template -class IteratorRange -{ -public: - IteratorRange(const IterT& iter, size_t grainSize = 8): - mIter(iter), - mGrainSize(grainSize), - mSize(0) - { - mSize = this->size(); - } - IteratorRange(IteratorRange& other, tbb::split): - mIter(other.mIter), - mGrainSize(other.mGrainSize), - mSize(other.mSize >> 1) - { - other.increment(mSize); - } - - /// @brief Return a reference to this range's iterator. - /// @note The reference is const, because the iterator should not be - /// incremented directly. Use this range object's increment() instead. - const IterT& iterator() const { return mIter; } - - bool empty() const { return mSize == 0 || !mIter.test(); } - bool test() const { return !this->empty(); } - operator bool() const { return !this->empty(); } - - /// @brief Return @c true if this range is splittable (i.e., if the iterator - /// can be advanced more than mGrainSize times). - bool is_divisible() const { return mSize > mGrainSize; } - - /// Advance the iterator @a n times. - void increment(Index n = 1) { for ( ; n > 0 && mSize > 0; --n, --mSize, ++mIter) {} } - /// Advance the iterator to the next item. - IteratorRange& operator++() { this->increment(); return *this; } - /// @brief Advance the iterator to the next item. - /// @return @c true if the iterator is not yet exhausted. - bool next() { this->increment(); return this->test(); } - -private: - Index size() const { Index n = 0; for (IterT it(mIter); it.test(); ++n, ++it) {} return n; } - - IterT mIter; - size_t mGrainSize; - /// @note mSize is only an estimate of the number of times mIter can be incremented - /// before it is exhausted (because the topology of the underlying tree could change - /// during iteration). For the purpose of range splitting, though, that should be - /// sufficient, since the two halves need not be of exactly equal size. - Index mSize; -}; - - -//////////////////////////////////////// - - -/// @brief Base class for tree-traversal iterators over real and virtual voxel values -/// @todo class TreeVoxelIteratorBase; - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_TREEITERATOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/tree/ValueAccessor.h b/openvdb_3_0_0_library/tree/ValueAccessor.h deleted file mode 100755 index 5f58666..0000000 --- a/openvdb_3_0_0_library/tree/ValueAccessor.h +++ /dev/null @@ -1,2616 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file ValueAccessor.h -/// -/// When traversing a grid in a spatially coherent pattern (e.g., iterating -/// over neighboring voxels), request a @c ValueAccessor from the grid -/// (with Grid::getAccessor()) and use the accessor's @c getValue() and -/// @c setValue() methods. These will typically be significantly faster -/// than accessing voxels directly in the grid's tree. -/// -/// @par Example: -/// -/// @code -/// FloatGrid grid; -/// FloatGrid::Accessor acc = grid.getAccessor(); -/// // First access is slow: -/// acc.setValue(Coord(0, 0, 0), 100); -/// // Subsequent nearby accesses are fast, since the accessor now holds pointers -/// // to nodes that contain (0, 0, 0) along the path from the root of the grid's -/// // tree to the leaf: -/// acc.setValue(Coord(0, 0, 1), 100); -/// acc.getValue(Coord(0, 2, 0), 100); -/// // Slow, because the accessor must be repopulated: -/// acc.getValue(Coord(-1, -1, -1)); -/// // Fast: -/// acc.getValue(Coord(-1, -1, -2)); -/// acc.setValue(Coord(-1, -2, 0), -100); -/// @endcode - -#ifndef OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED -#define OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace tree { - -// Forward declarations of local classes that are not intended for general use -template class ValueAccessor0; -template class ValueAccessor1; -template class ValueAccessor2; -template class ValueAccessor3; -template class CacheItem; - - -/// @brief This base class for ValueAccessors manages registration of an accessor -/// with a tree so that the tree can automatically clear the accessor whenever -/// one of its nodes is deleted. -/// @internal A base class is needed because ValueAccessor is templated on both -/// a Tree type and a mutex type. The various instantiations of the template -/// are distinct, unrelated types, so they can't easily be stored in a container -/// such as the Tree's CacheRegistry. This base class, in contrast, is templated -/// only on the Tree type, so for any given Tree, only two distinct instantiations -/// are possible, ValueAccessorBase and ValueAccessorBase. -template -class ValueAccessorBase -{ -public: - static const bool IsConstTree = boost::is_const::value; - - ValueAccessorBase(TreeType& tree): mTree(&tree) { tree.attachAccessor(*this); } - - virtual ~ValueAccessorBase() { if (mTree) mTree->releaseAccessor(*this); } - - /// @brief Return a pointer to the tree associated with this accessor. - /// @details The pointer will be null only if the tree from which this accessor - /// was constructed was subsequently deleted (which generally leaves the - /// accessor in an unsafe state). - TreeType* getTree() const { return mTree; } - /// Return a reference to the tree associated with this accessor. - TreeType& tree() const { assert(mTree); return *mTree; } - - ValueAccessorBase(const ValueAccessorBase& other): mTree(other.mTree) - { - if (mTree) mTree->attachAccessor(*this); - } - - ValueAccessorBase& operator=(const ValueAccessorBase& other) - { - if (&other != this) { - if (mTree) mTree->releaseAccessor(*this); - mTree = other.mTree; - if (mTree) mTree->attachAccessor(*this); - } - return *this; - } - - virtual void clear() = 0; - -protected: - // Allow trees to deregister themselves. - template friend class Tree; - - virtual void release() { mTree = NULL; } - - TreeType* mTree; -}; // class ValueAccessorBase - - -//////////////////////////////////////// - - -/// When traversing a grid in a spatially coherent pattern (e.g., iterating -/// over neighboring voxels), request a @c ValueAccessor from the grid -/// (with Grid::getAccessor()) and use the accessor's @c getValue() and -/// @c setValue() methods. These will typically be significantly faster -/// than accessing voxels directly in the grid's tree. -/// -/// A ValueAccessor caches pointers to tree nodes along the path to a voxel (x, y, z). -/// A subsequent access to voxel (x', y', z') starts from the cached leaf node and -/// moves up until a cached node that encloses (x', y', z') is found, then traverses -/// down the tree from that node to a leaf, updating the cache with the new path. -/// This leads to significant acceleration of spatially-coherent accesses. -/// -/// @param _TreeType the type of the tree to be accessed [required] -/// @param CacheLevels the number of nodes to be cached, starting from the leaf level -/// and not including the root (i.e., CacheLevels < DEPTH), -/// and defaulting to all non-root nodes -/// @param MutexType the type of mutex to use (see note) -/// -/// @note If @c MutexType is a TBB-compatible mutex, then multiple threads may -/// safely access a single, shared accessor. However, it is highly recommended -/// that, instead, each thread be assigned its own, non-mutex-protected accessor. -template -class ValueAccessor: public ValueAccessorBase<_TreeType> -{ -public: - BOOST_STATIC_ASSERT(CacheLevels < _TreeType::DEPTH); - - typedef _TreeType TreeType; - typedef typename TreeType::RootNodeType RootNodeT; - typedef typename TreeType::LeafNodeType LeafNodeT; - typedef typename RootNodeT::ValueType ValueType; - typedef ValueAccessorBase BaseT; - typedef typename MutexType::scoped_lock LockT; - using BaseT::IsConstTree; - - ValueAccessor(TreeType& tree): BaseT(tree), mCache(*this) - { - mCache.insert(Coord(), &tree.root()); - } - - ValueAccessor(const ValueAccessor& other): BaseT(other), mCache(*this, other.mCache) {} - - ValueAccessor& operator=(const ValueAccessor& other) - { - if (&other != this) { - this->BaseT::operator=(other); - mCache.copy(*this, other.mCache); - } - return *this; - } - virtual ~ValueAccessor() {} - - /// Return the number of cache levels employed by this accessor. - static Index numCacheLevels() { return CacheLevels; } - - /// Return @c true if nodes along the path to the given voxel have been cached. - bool isCached(const Coord& xyz) const { LockT lock(mMutex); return mCache.isCached(xyz); } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const - { - LockT lock(mMutex); - return mCache.getValue(xyz); - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) const { LockT lock(mMutex); return mCache.isValueOn(xyz); } - - /// Return the active state of the voxel as well as its value - bool probeValue(const Coord& xyz, ValueType& value) const - { - LockT lock(mMutex); - return mCache.probeValue(xyz,value); - } - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides, - /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is - /// implicitly a background voxel). - int getValueDepth(const Coord& xyz) const - { - LockT lock(mMutex); - return mCache.getValueDepth(xyz); - } - - /// Return @c true if the value of voxel (x, y, z) resides at the leaf level - /// of the tree, i.e., if it is not a tile value. - bool isVoxel(const Coord& xyz) const { LockT lock(mMutex); return mCache.isVoxel(xyz); } - - //@{ - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - LockT lock(mMutex); - mCache.setValue(xyz, value); - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - //@} - - /// Set the value of the voxel at the given coordinate but don't change its active state. - void setValueOnly(const Coord& xyz, const ValueType& value) - { - LockT lock(mMutex); - mCache.setValueOnly(xyz, value); - } - - /// Set the value of the voxel at the given coordinates and mark the voxel - /// as active. [Experimental] - void newSetValue(const Coord& xyz, const ValueType& value) - { - LockT lock(mMutex); - mCache.newSetValue(xyz, value); - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - LockT lock(mMutex); - mCache.setValueOff(xyz, value); - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - LockT lock(mMutex); - mCache.modifyValue(xyz, op); - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - LockT lock(mMutex); - mCache.modifyValueAndActiveState(xyz, op); - } - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on = true) - { - LockT lock(mMutex); - mCache.setActiveState(xyz, on); - } - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); } - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); } - - /// Return the cached node of type @a NodeType. [Mainly for internal use] - template - NodeType* getNode() - { - LockT lock(mMutex); - NodeType* node = NULL; - mCache.getNode(node); - return node; - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). [Mainly for internal use] - template - void insertNode(const Coord& xyz, NodeType& node) - { - LockT lock(mMutex); - mCache.insert(xyz, &node); - } - - /// If a node of the given type exists in the cache, remove it, so that - /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in - /// that node. [Mainly for internal use] - template - void eraseNode() { LockT lock(mMutex); NodeType* node = NULL; mCache.erase(node); } - - /// @brief Add the specified leaf to this tree, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeT* leaf) - { - LockT lock(mMutex); - mCache.addLeaf(leaf); - } - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly deleting existing nodes or creating new nodes in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - LockT lock(mMutex); - mCache.addTile(level, xyz, value, state); - } - - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z). - /// If no such node exists, create one, but preserve the values and - /// active states of all voxels. - /// @details Use this method to preallocate a static tree topology - /// over which to safely perform multithreaded processing. - LeafNodeT* touchLeaf(const Coord& xyz) - { - LockT lock(mMutex); - return mCache.touchLeaf(xyz); - } - - //@{ - /// @brief Return a pointer to the node of the specified type that contains - /// voxel (x, y, z), or NULL if no such node exists. - template - NodeT* probeNode(const Coord& xyz) - { - LockT lock(mMutex); - return mCache.template probeNode(xyz); - } - template - const NodeT* probeConstNode(const Coord& xyz) const - { - LockT lock(mMutex); - return mCache.template probeConstNode(xyz); - } - template - const NodeT* probeNode(const Coord& xyz) const - { - return this->template probeConstNode(xyz); - } - //@} - - //@{ - /// @brief Return a pointer to the leaf node that contains voxel (x, y, z), - /// or NULL if no such node exists. - LeafNodeT* probeLeaf(const Coord& xyz) - { - LockT lock(mMutex); - return mCache.probeLeaf(xyz); - } - const LeafNodeT* probeConstLeaf(const Coord& xyz) const - { - LockT lock(mMutex); - return mCache.probeConstLeaf(xyz); - } - const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); } - //@} - - /// Remove all nodes from this cache, then reinsert the root node. - virtual void clear() - { - LockT lock(mMutex); - mCache.clear(); - if (this->mTree) mCache.insert(Coord(), &(this->mTree->root())); - } - -private: - // Allow nodes to insert themselves into the cache. - template friend class RootNode; - template friend class InternalNode; - template friend class LeafNode; - // Allow trees to deregister themselves. - template friend class Tree; - - /// Prevent this accessor from calling Tree::releaseCache() on a tree that - /// no longer exists. (Called by mTree when it is destroyed.) - virtual void release() - { - LockT lock(mMutex); - this->BaseT::release(); - mCache.clear(); - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). - /// @note This operation is not mutex-protected and is intended to be called - /// only by nodes and only in the context of a getValue() or setValue() call. - template - void insert(const Coord& xyz, NodeType* node) { mCache.insert(xyz, node); } - - // Define a list of all tree node types from LeafNode to RootNode - typedef typename RootNodeT::NodeChainType InvTreeT; - // Remove all tree node types that are excluded from the cache - typedef typename boost::mpl::begin::type BeginT; - typedef typename boost::mpl::advance >::type FirstT; - typedef typename boost::mpl::find::type LastT; - typedef typename boost::mpl::erase::type SubtreeT; - typedef CacheItem::value==1> CacheItemT; - - // Private member data - mutable CacheItemT mCache; - mutable MutexType mMutex; - -}; // class ValueAccessor - - -/// @brief Template specialization of the ValueAccessor with no mutex and no cache levels -/// @details This specialization is provided mainly for benchmarking. -/// Accessors with caching will almost always be faster. -template -class ValueAccessor: public ValueAccessor0 -{ -public: - ValueAccessor(TreeType& tree): ValueAccessor0(tree) {} - ValueAccessor(const ValueAccessor& other): ValueAccessor0(other) {} - virtual ~ValueAccessor() {} -}; - - -/// Template specialization of the ValueAccessor with no mutex and one cache level -template -class ValueAccessor: public ValueAccessor1 -{ -public: - ValueAccessor(TreeType& tree): ValueAccessor1(tree) {} - ValueAccessor(const ValueAccessor& other): ValueAccessor1(other) {} - virtual ~ValueAccessor() {} -}; - - -/// Template specialization of the ValueAccessor with no mutex and two cache levels -template -class ValueAccessor: public ValueAccessor2 -{ -public: - ValueAccessor(TreeType& tree): ValueAccessor2(tree) {} - ValueAccessor(const ValueAccessor& other): ValueAccessor2(other) {} - virtual ~ValueAccessor() {} -}; - - -/// Template specialization of the ValueAccessor with no mutex and three cache levels -template -class ValueAccessor: public ValueAccessor3 -{ -public: - ValueAccessor(TreeType& tree): ValueAccessor3(tree) {} - ValueAccessor(const ValueAccessor& other): ValueAccessor3(other) {} - virtual ~ValueAccessor() {} -}; - - -//////////////////////////////////////// - - -/// @brief This accessor is thread-safe (at the cost of speed) for both reading and -/// writing to a tree. That is, multiple threads may safely access a single, -/// shared ValueAccessorRW. -/// -/// @warning Since the mutex-locking employed by the ValueAccessorRW -/// can seriously impair performance of multithreaded applications, it -/// is recommended that, instead, each thread be assigned its own -/// (non-mutex protected) accessor. -template -class ValueAccessorRW: public ValueAccessor -{ -public: - ValueAccessorRW(TreeType& tree) - : ValueAccessor(tree) - { - } -}; - - -//////////////////////////////////////// - - -// -// The classes below are for internal use and should rarely be used directly. -// - -// An element of a compile-time linked list of node pointers, ordered from LeafNode to RootNode -template -class CacheItem -{ -public: - typedef typename boost::mpl::front::type NodeType; - typedef typename NodeType::ValueType ValueType; - typedef typename NodeType::LeafNodeType LeafNodeType; - typedef std::numeric_limits CoordLimits; - - CacheItem(TreeCacheT& parent): - mParent(&parent), - mHash(CoordLimits::max()), - mNode(NULL), - mNext(parent) - { - } - - //@{ - /// Copy another CacheItem's node pointers and hash keys, but not its parent pointer. - CacheItem(TreeCacheT& parent, const CacheItem& other): - mParent(&parent), - mHash(other.mHash), - mNode(other.mNode), - mNext(parent, other.mNext) - { - } - - CacheItem& copy(TreeCacheT& parent, const CacheItem& other) - { - mParent = &parent; - mHash = other.mHash; - mNode = other.mNode; - mNext.copy(parent, other.mNext); - return *this; - } - //@} - - bool isCached(const Coord& xyz) const - { - return (this->isHashed(xyz) || mNext.isCached(xyz)); - } - - /// Cache the given node at this level. - void insert(const Coord& xyz, const NodeType* node) - { - mHash = (node != NULL) ? xyz & ~(NodeType::DIM-1) : Coord::max(); - mNode = node; - } - /// Forward the given node to another level of the cache. - template - void insert(const Coord& xyz, const OtherNodeType* node) { mNext.insert(xyz, node); } - - /// Erase the node at this level. - void erase(const NodeType*) { mHash = Coord::max(); mNode = NULL; } - /// Erase the node at another level of the cache. - template - void erase(const OtherNodeType* node) { mNext.erase(node); } - - /// Erase the nodes at this and lower levels of the cache. - void clear() { mHash = Coord::max(); mNode = NULL; mNext.clear(); } - - /// Return the cached node (if any) at this level. - void getNode(const NodeType*& node) const { node = mNode; } - void getNode(const NodeType*& node) { node = mNode; } - void getNode(NodeType*& node) - { - // This combination of a static assertion and a const_cast might not be elegant, - // but it is a lot simpler than specializing TreeCache for const Trees. - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - node = const_cast(mNode); - } - /// Forward the request to another level of the cache. - template - void getNode(OtherNodeType*& node) { mNext.getNode(node); } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) - { - if (this->isHashed(xyz)) { - assert(mNode); - return mNode->getValueAndCache(xyz, *mParent); - } - return mNext.getValue(xyz); - } - - void addLeaf(LeafNodeType* leaf) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - if (NodeType::LEVEL == 0) return; - if (this->isHashed(leaf->origin())) { - assert(mNode); - return const_cast(mNode)->addLeafAndCache(leaf, *mParent); - } - mNext.addLeaf(leaf); - } - - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - if (NodeType::LEVEL < level) return; - if (this->isHashed(xyz)) { - assert(mNode); - return const_cast(mNode)->addTileAndCache( - level, xyz, value, state, *mParent); - } - mNext.addTile(level, xyz, value, state); - } - - LeafNodeType* touchLeaf(const Coord& xyz) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode); - return const_cast(mNode)->touchLeafAndCache(xyz, *mParent); - } - return mNext.touchLeaf(xyz); - } - - LeafNodeType* probeLeaf(const Coord& xyz) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode); - return const_cast(mNode)->probeLeafAndCache(xyz, *mParent); - } - return mNext.probeLeaf(xyz); - } - - const LeafNodeType* probeConstLeaf(const Coord& xyz) - { - if (this->isHashed(xyz)) { - assert(mNode); - return mNode->probeConstLeafAndCache(xyz, *mParent); - } - return mNext.probeConstLeaf(xyz); - } - - template - NodeT* probeNode(const Coord& xyz) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (this->isHashed(xyz)) { - if ((boost::is_same::value)) { - assert(mNode); - return reinterpret_cast(const_cast(mNode)); - } - return const_cast(mNode)->template probeNodeAndCache(xyz, *mParent); - } - return mNext.template probeNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - template - const NodeT* probeConstNode(const Coord& xyz) - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if (this->isHashed(xyz)) { - if ((boost::is_same::value)) { - assert(mNode); - return reinterpret_cast(mNode); - } - return mNode->template probeConstNodeAndCache(xyz, *mParent); - } - return mNext.template probeConstNode(xyz); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) - { - if (this->isHashed(xyz)) { - assert(mNode); - return mNode->isValueOnAndCache(xyz, *mParent); - } - return mNext.isValueOn(xyz); - } - - /// Return the active state and value of the voxel at the given coordinates. - bool probeValue(const Coord& xyz, ValueType& value) - { - if (this->isHashed(xyz)) { - assert(mNode); - return mNode->probeValueAndCache(xyz, value, *mParent); - } - return mNext.probeValue(xyz, value); - } - - int getValueDepth(const Coord& xyz) - { - if (this->isHashed(xyz)) { - assert(mNode); - return static_cast(TreeCacheT::RootNodeT::LEVEL) - - static_cast(mNode->getValueLevelAndCache(xyz, *mParent)); - } else { - return mNext.getValueDepth(xyz); - } - } - - bool isVoxel(const Coord& xyz) - { - if (this->isHashed(xyz)) { - assert(mNode); - return mNode->getValueLevelAndCache(xyz, *mParent)==0; - } else { - return mNext.isVoxel(xyz); - } - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->setValueAndCache(xyz, value, *mParent); - } else { - mNext.setValue(xyz, value); - } - } - void setValueOnly(const Coord& xyz, const ValueType& value) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->setValueOnlyAndCache(xyz, value, *mParent); - } else { - mNext.setValueOnly(xyz, value); - } - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->modifyValueAndCache(xyz, op, *mParent); - } else { - mNext.modifyValue(xyz, op); - } - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->modifyValueAndActiveStateAndCache(xyz, op, *mParent); - } else { - mNext.modifyValueAndActiveState(xyz, op); - } - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->setValueOffAndCache(xyz, value, *mParent); - } else { - mNext.setValueOff(xyz, value); - } - } - - /// Set the active state of the voxel at the given coordinates. - void setActiveState(const Coord& xyz, bool on) - { - if (this->isHashed(xyz)) { - assert(mNode); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mNode)->setActiveStateAndCache(xyz, on, *mParent); - } else { - mNext.setActiveState(xyz, on); - } - } - -private: - CacheItem(const CacheItem&); - CacheItem& operator=(const CacheItem&); - - bool isHashed(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[0] - && (xyz[1] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[1] - && (xyz[2] & ~Coord::ValueType(NodeType::DIM-1)) == mHash[2]; - } - - TreeCacheT* mParent; - Coord mHash; - const NodeType* mNode; - typedef typename boost::mpl::pop_front::type RestT; // NodeVecT minus its first item - CacheItem::value == 1> mNext; -};// end of CacheItem - - -/// The tail of a compile-time list of cached node pointers, ordered from LeafNode to RootNode -template -class CacheItem -{ -public: - typedef typename boost::mpl::front::type RootNodeType; - typedef typename RootNodeType::ValueType ValueType; - typedef typename RootNodeType::LeafNodeType LeafNodeType; - - CacheItem(TreeCacheT& parent): mParent(&parent), mRoot(NULL) {} - CacheItem(TreeCacheT& parent, const CacheItem& other): mParent(&parent), mRoot(other.mRoot) {} - - CacheItem& copy(TreeCacheT& parent, const CacheItem& other) - { - mParent = &parent; - mRoot = other.mRoot; - return *this; - } - - bool isCached(const Coord& xyz) const { return this->isHashed(xyz); } - - void insert(const Coord&, const RootNodeType* root) { mRoot = root; } - - // Needed for node types that are not cached - template - void insert(const Coord&, const OtherNodeType*) {} - - void erase(const RootNodeType*) { mRoot = NULL; } - - void clear() { mRoot = NULL; } - - void getNode(RootNodeType*& node) - { - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - node = const_cast(mRoot); - } - void getNode(const RootNodeType*& node) const { node = mRoot; } - - void addLeaf(LeafNodeType* leaf) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->addLeafAndCache(leaf, *mParent); - } - - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->addTileAndCache(level, xyz, value, state, *mParent); - } - - LeafNodeType* touchLeaf(const Coord& xyz) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - return const_cast(mRoot)->touchLeafAndCache(xyz, *mParent); - } - - LeafNodeType* probeLeaf(const Coord& xyz) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - return const_cast(mRoot)->probeLeafAndCache(xyz, *mParent); - } - - const LeafNodeType* probeConstLeaf(const Coord& xyz) - { - assert(mRoot); - return mRoot->probeConstLeafAndCache(xyz, *mParent); - } - - template - NodeType* probeNode(const Coord& xyz) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - return const_cast(mRoot)->template probeNodeAndCache(xyz, *mParent); - } - - template - const NodeType* probeConstNode(const Coord& xyz) - { - assert(mRoot); - return mRoot->template probeConstNodeAndCache(xyz, *mParent); - } - - int getValueDepth(const Coord& xyz) - { - assert(mRoot); - return mRoot->getValueDepthAndCache(xyz, *mParent); - } - bool isValueOn(const Coord& xyz) - { - assert(mRoot); - return mRoot->isValueOnAndCache(xyz, *mParent); - } - - bool probeValue(const Coord& xyz, ValueType& value) - { - assert(mRoot); - return mRoot->probeValueAndCache(xyz, value, *mParent); - } - bool isVoxel(const Coord& xyz) - { - assert(mRoot); - return mRoot->getValueDepthAndCache(xyz, *mParent) == - static_cast(RootNodeType::LEVEL); - } - const ValueType& getValue(const Coord& xyz) - { - assert(mRoot); - return mRoot->getValueAndCache(xyz, *mParent); - } - - void setValue(const Coord& xyz, const ValueType& value) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->setValueAndCache(xyz, value, *mParent); - } - void setValueOnly(const Coord& xyz, const ValueType& value) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->setValueOnlyAndCache(xyz, value, *mParent); - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->modifyValueAndCache(xyz, op, *mParent); - } - - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->modifyValueAndActiveStateAndCache(xyz, op, *mParent); - } - - void setValueOff(const Coord& xyz, const ValueType& value) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->setValueOffAndCache(xyz, value, *mParent); - } - - void setActiveState(const Coord& xyz, bool on) - { - assert(mRoot); - BOOST_STATIC_ASSERT(!TreeCacheT::IsConstTree); - const_cast(mRoot)->setActiveStateAndCache(xyz, on, *mParent); - } - -private: - CacheItem(const CacheItem&); - CacheItem& operator=(const CacheItem&); - - bool isHashed(const Coord&) const { return false; } - - TreeCacheT* mParent; - const RootNodeType* mRoot; -};// end of CacheItem specialized for RootNode - - -//////////////////////////////////////// - - -/// @brief ValueAccessor with no mutex and no node caching. -/// @details This specialization is provided mainly for benchmarking. -/// Accessors with caching will almost always be faster. -template -class ValueAccessor0: public ValueAccessorBase<_TreeType> -{ -public: - typedef _TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename TreeType::RootNodeType RootNodeT; - typedef typename TreeType::LeafNodeType LeafNodeT; - typedef ValueAccessorBase BaseT; - - ValueAccessor0(TreeType& tree): BaseT(tree) {} - - ValueAccessor0(const ValueAccessor0& other): BaseT(other) {} - - /// Return the number of cache levels employed by this accessor. - static Index numCacheLevels() { return 0; } - - ValueAccessor0& operator=(const ValueAccessor0& other) - { - if (&other != this) this->BaseT::operator=(other); - return *this; - } - - virtual ~ValueAccessor0() {} - - /// Return @c true if nodes along the path to the given voxel have been cached. - bool isCached(const Coord&) const { return false; } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const - { - assert(BaseT::mTree); - return BaseT::mTree->getValue(xyz); - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) const - { - assert(BaseT::mTree); - return BaseT::mTree->isValueOn(xyz); - } - - /// Return the active state and, in @a value, the value of the voxel at the given coordinates. - bool probeValue(const Coord& xyz, ValueType& value) const - { - assert(BaseT::mTree); - return BaseT::mTree->probeValue(xyz, value); - } - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides, - /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is - /// implicitly a background voxel). - int getValueDepth(const Coord& xyz) const - { - assert(BaseT::mTree); - return BaseT::mTree->getValueDepth(xyz); - } - - /// Return @c true if the value of voxel (x, y, z) resides at the leaf level - /// of the tree, i.e., if it is not a tile value. - bool isVoxel(const Coord& xyz) const - { - assert(BaseT::mTree); - return BaseT::mTree->getValueDepth(xyz) == static_cast(RootNodeT::LEVEL); - } - - //@{ - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->setValue(xyz, value); - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - //@} - - /// Set the value of the voxel at the given coordinate but don't change its active state. - void setValueOnly(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->setValueOnly(xyz, value); - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->root().setValueOff(xyz, value); - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->modifyValue(xyz, op); - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->modifyValueAndActiveState(xyz, op); - } - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on = true) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->setActiveState(xyz, on); - } - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); } - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); } - - /// Return the cached node of type @a NodeType. [Mainly for internal use] - template NodeT* getNode() { return NULL; } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). [Mainly for internal use] - template void insertNode(const Coord&, NodeT&) {} - - /// @brief Add the specified leaf to this tree, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeT* leaf) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->root().addLeaf(leaf); - } - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly deleting existing nodes or creating new nodes in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->root().addTile(level, xyz, value, state); - } - - /// If a node of the given type exists in the cache, remove it, so that - /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in - /// that node. [Mainly for internal use] - template void eraseNode() {} - - LeafNodeT* touchLeaf(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - return BaseT::mTree->touchLeaf(xyz); - } - - template - NodeT* probeNode(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - return BaseT::mTree->template probeNode(xyz); - } - - template - const NodeT* probeConstNode(const Coord& xyz) const - { - assert(BaseT::mTree); - return BaseT::mTree->template probeConstNode(xyz); - } - - LeafNodeT* probeLeaf(const Coord& xyz) - { - return this->template probeNode(xyz); - } - - const LeafNodeT* probeConstLeaf(const Coord& xyz) const - { - return this->template probeConstNode(xyz); - } - - const LeafNodeT* probeLeaf(const Coord& xyz) const - { - return this->probeConstLeaf(xyz); - } - - /// Remove all nodes from this cache, then reinsert the root node. - virtual void clear() {} - -private: - // Allow trees to deregister themselves. - template friend class Tree; - - /// Prevent this accessor from calling Tree::releaseCache() on a tree that - /// no longer exists. (Called by mTree when it is destroyed.) - virtual void release() { this->BaseT::release(); } - -}; // ValueAccessor0 - - -/// @brief Value accessor with one level of node caching. -/// @details The node cache level is specified by L0 with the default value 0 -/// (defined in the forward declaration) corresponding to a LeafNode. -/// -/// @note This class is for experts only and should rarely be used -/// directly. Instead use ValueAccessor with its default template arguments. -template -class ValueAccessor1 : public ValueAccessorBase<_TreeType> -{ -public: - BOOST_STATIC_ASSERT(_TreeType::DEPTH >= 2); - BOOST_STATIC_ASSERT( L0 < _TreeType::RootNodeType::LEVEL ); - typedef _TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename TreeType::RootNodeType RootNodeT; - typedef typename TreeType::LeafNodeType LeafNodeT; - typedef ValueAccessorBase BaseT; - typedef typename RootNodeT::NodeChainType InvTreeT; - typedef typename boost::mpl::at >::type NodeT0; - - /// Constructor from a tree - ValueAccessor1(TreeType& tree) : BaseT(tree), mKey0(Coord::max()), mNode0(NULL) - { - } - - /// Copy constructor - ValueAccessor1(const ValueAccessor1& other) : BaseT(other) { this->copy(other); } - - /// Return the number of cache levels employed by this ValueAccessor - static Index numCacheLevels() { return 1; } - - /// Asignment operator - ValueAccessor1& operator=(const ValueAccessor1& other) - { - if (&other != this) { - this->BaseT::operator=(other); - this->copy(other); - } - return *this; - } - - /// Virtual destructor - virtual ~ValueAccessor1() {} - - /// Return @c true if any of the nodes along the path to the given - /// voxel have been cached. - bool isCached(const Coord& xyz) const - { - assert(BaseT::mTree); - return this->isHashed(xyz); - } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return mNode0->getValueAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return mNode0->isValueOnAndCache(xyz, this->self()); - } - return BaseT::mTree->root().isValueOnAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel as well as its value - bool probeValue(const Coord& xyz, ValueType& value) const - { - assert(BaseT::mTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return mNode0->probeValueAndCache(xyz, value, this->self()); - } - return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self()); - } - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides, - /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is - /// implicitly a background voxel). - int getValueDepth(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()); - } - - /// Return @c true if the value of voxel (x, y, z) resides at the leaf level - /// of the tree, i.e., if it is not a tile value. - bool isVoxel(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return mNode0->getValueLevelAndCache(xyz, this->self()) == 0; - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) == - static_cast(RootNodeT::LEVEL); - } - - //@{ - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueAndCache(xyz, value, *this); - } - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - //@} - - /// Set the value of the voxel at the given coordinate but preserves its active state. - void setValueOnly(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOnlyAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this); - } - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOffAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOffAndCache(xyz, value, *this); - } - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndCache(xyz, op, *this); - } - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this); - } - } - - /// Set the active state of the voxel at the given coordinates but don't change its value. - void setActiveState(const Coord& xyz, bool on = true) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - const_cast(mNode0)->setActiveStateAndCache(xyz, on, *this); - } else { - BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this); - } - } - /// Mark the voxel at the given coordinates as active but don't change its value. - void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); } - /// Mark the voxel at the given coordinates as inactive but don't change its value. - void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); } - - /// Return the cached node of type @a NodeType. [Mainly for internal use] - template - NodeT* getNode() - { - const NodeT* node = NULL; - this->getNode(node); - return const_cast(node); - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). [Mainly for internal use] - template - void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); } - - /// If a node of the given type exists in the cache, remove it, so that - /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in - /// that node. [Mainly for internal use] - template - void eraseNode() - { - const NodeT* node = NULL; - this->eraseNode(node); - } - - /// @brief Add the specified leaf to this tree, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeT* leaf) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->root().addLeaf(leaf); - } - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly deleting existing nodes or creating new nodes in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - BaseT::mTree->root().addTile(level, xyz, value, state); - } - - /// @brief @return the leaf node that contains voxel (x, y, z) and - /// if it doesn't exist, create it, but preserve the values and - /// active states of all voxels. - /// - /// Use this method to preallocate a static tree topology over which to - /// safely perform multithreaded processing. - LeafNodeT* touchLeaf(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed(xyz)) { - assert(mNode0); - return const_cast(mNode0)->touchLeafAndCache(xyz, *this); - } - return BaseT::mTree->root().touchLeafAndCache(xyz, *this); - } - - /// @brief @return a pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - NodeT* probeNode(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed(xyz)) { - assert(mNode0); - return reinterpret_cast(const_cast(mNode0)); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - LeafNodeT* probeLeaf(const Coord& xyz) - { - return this->template probeNode(xyz); - } - - /// @brief @return a const pointer to the nodeof the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - const NodeT* probeConstNode(const Coord& xyz) const - { - assert(BaseT::mTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed(xyz)) { - assert(mNode0); - return reinterpret_cast(mNode0); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - const LeafNodeT* probeConstLeaf(const Coord& xyz) const - { - return this->template probeConstNode(xyz); - } - const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); } - - /// Remove all the cached nodes and invalidate the corresponding hash-keys. - virtual void clear() - { - mKey0 = Coord::max(); - mNode0 = NULL; - } - -private: - // Allow nodes to insert themselves into the cache. - template friend class RootNode; - template friend class InternalNode; - template friend class LeafNode; - // Allow trees to deregister themselves. - template friend class Tree; - - // This private method is merely for convenience. - inline ValueAccessor1& self() const { return const_cast(*this); } - - void getNode(const NodeT0*& node) { node = mNode0; } - void getNode(const RootNodeT*& node) - { - node = (BaseT::mTree ? &BaseT::mTree->root() : NULL); - } - template void getNode(const OtherNodeType*& node) { node = NULL; } - void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = NULL; } - template void eraseNode(const OtherNodeType*) {} - - /// Private copy method - inline void copy(const ValueAccessor1& other) - { - mKey0 = other.mKey0; - mNode0 = other.mNode0; - } - - /// Prevent this accessor from calling Tree::releaseCache() on a tree that - /// no longer exists. (Called by mTree when it is destroyed.) - virtual void release() - { - this->BaseT::release(); - this->clear(); - } - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). - /// @note This operation is not mutex-protected and is intended to be called - /// only by nodes and only in the context of a getValue() or setValue() call. - inline void insert(const Coord& xyz, const NodeT0* node) - { - assert(node); - mKey0 = xyz & ~(NodeT0::DIM-1); - mNode0 = node; - } - - /// No-op in case a tree traversal attemps to insert a node that - /// is not cached by the ValueAccessor - template inline void insert(const Coord&, const OtherNodeType*) {} - - inline bool isHashed(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0] - && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1] - && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2]; - } - mutable Coord mKey0; - mutable const NodeT0* mNode0; -}; // ValueAccessor1 - - -/// @brief Value accessor with two levels of node caching. -/// @details The node cache levels are specified by L0 and L1 -/// with the default values 0 and 1 (defined in the forward declaration) -/// corresponding to a LeafNode and its parent InternalNode. -/// -/// @note This class is for experts only and should rarely be used directly. -/// Instead use ValueAccessor with its default template arguments. -template -class ValueAccessor2 : public ValueAccessorBase<_TreeType> -{ -public: - BOOST_STATIC_ASSERT(_TreeType::DEPTH >= 3); - BOOST_STATIC_ASSERT( L0 < L1 && L1 < _TreeType::RootNodeType::LEVEL ); - typedef _TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename TreeType::RootNodeType RootNodeT; - typedef typename TreeType::LeafNodeType LeafNodeT; - typedef ValueAccessorBase BaseT; - typedef typename RootNodeT::NodeChainType InvTreeT; - typedef typename boost::mpl::at >::type NodeT0; - typedef typename boost::mpl::at >::type NodeT1; - - /// Constructor from a tree - ValueAccessor2(TreeType& tree) : BaseT(tree), - mKey0(Coord::max()), mNode0(NULL), - mKey1(Coord::max()), mNode1(NULL) {} - - /// Copy constructor - ValueAccessor2(const ValueAccessor2& other) : BaseT(other) { this->copy(other); } - - /// Return the number of cache levels employed by this ValueAccessor - static Index numCacheLevels() { return 2; } - - /// Asignment operator - ValueAccessor2& operator=(const ValueAccessor2& other) - { - if (&other != this) { - this->BaseT::operator=(other); - this->copy(other); - } - return *this; - } - - /// Virtual destructor - virtual ~ValueAccessor2() {} - - /// Return @c true if any of the nodes along the path to the given - /// voxel have been cached. - bool isCached(const Coord& xyz) const - { - assert(BaseT::mTree); - return this->isHashed1(xyz) || this->isHashed0(xyz); - } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->getValueAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->getValueAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->isValueOnAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->isValueOnAndCache(xyz, this->self()); - } - return BaseT::mTree->root().isValueOnAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel as well as its value - bool probeValue(const Coord& xyz, ValueType& value) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->probeValueAndCache(xyz, value, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->probeValueAndCache(xyz, value, this->self()); - } - return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self()); - } - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides, - /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is - /// implicitly a background voxel). - int getValueDepth(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()); - } - - /// Return @c true if the value of voxel (x, y, z) resides at the leaf level - /// of the tree, i.e., if it is not a tile value. - bool isVoxel(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->getValueLevelAndCache(xyz, this->self())==0; - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->getValueLevelAndCache(xyz, this->self())==0; - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) == - static_cast(RootNodeT::LEVEL); - } - - //@{ - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueAndCache(xyz, value, *this); - } - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - //@} - - /// Set the value of the voxel at the given coordinate but preserves its active state. - void setValueOnly(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOnlyAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueOnlyAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this); - } - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOffAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueOffAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOffAndCache(xyz, value, *this); - } - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndCache(xyz, op, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->modifyValueAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndCache(xyz, op, *this); - } - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this); - } - } - - /// Set the active state of the voxel at the given coordinates without changing its value. - void setActiveState(const Coord& xyz, bool on = true) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setActiveStateAndCache(xyz, on, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setActiveStateAndCache(xyz, on, *this); - } else { - BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this); - } - } - /// Mark the voxel at the given coordinates as active without changing its value. - void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); } - /// Mark the voxel at the given coordinates as inactive without changing its value. - void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); } - - /// Return the cached node of type @a NodeType. [Mainly for internal use] - template - NodeT* getNode() - { - const NodeT* node = NULL; - this->getNode(node); - return const_cast(node); - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). [Mainly for internal use] - template - void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); } - - /// If a node of the given type exists in the cache, remove it, so that - /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in - /// that node. [Mainly for internal use] - template - void eraseNode() - { - const NodeT* node = NULL; - this->eraseNode(node); - } - - /// @brief Add the specified leaf to this tree, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeT* leaf) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed1(leaf->origin())) { - assert(mNode1); - return const_cast(mNode1)->addLeafAndCache(leaf, *this); - } - BaseT::mTree->root().addLeafAndCache(leaf, *this); - } - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly deleting existing nodes or creating new nodes in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->addTileAndCache(level, xyz, value, state, *this); - } - BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this); - } - - /// @brief @return the leaf node that contains voxel (x, y, z) and - /// if it doesn't exist, create it, but preserve the values and - /// active states of all voxels. - /// - /// Use this method to preallocate a static tree topology over which to - /// safely perform multithreaded processing. - LeafNodeT* touchLeaf(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return const_cast(mNode0)->touchLeafAndCache(xyz, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->touchLeafAndCache(xyz, *this); - } - return BaseT::mTree->root().touchLeafAndCache(xyz, *this); - } - /// @brief @return a pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - NodeT* probeNode(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed0(xyz)) { - assert(mNode0); - return reinterpret_cast(const_cast(mNode0)); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->template probeNodeAndCache(xyz, *this); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } else if ((boost::is_same::value)) { - if (this->isHashed1(xyz)) { - assert(mNode1); - return reinterpret_cast(const_cast(mNode1)); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - /// @brief @return a pointer to the leaf node that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode(xyz); } - - /// @brief @return a const pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - const NodeT* probeConstLeaf(const Coord& xyz) const - { - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed0(xyz)) { - assert(mNode0); - return reinterpret_cast(mNode0); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->template probeConstNodeAndCache(xyz, this->self()); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } else if ((boost::is_same::value)) { - if (this->isHashed1(xyz)) { - assert(mNode1); - return reinterpret_cast(mNode1); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - /// @brief @return a const pointer to the leaf node that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - const LeafNodeT* probeConstLeaf(const Coord& xyz) const - { - return this->template probeConstNode(xyz); - } - const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); } - - /// @brief @return a const pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - const NodeT* probeConstNode(const Coord& xyz) const - { - assert(BaseT::mTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed0(xyz)) { - assert(mNode0); - return reinterpret_cast(mNode0); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->template probeConstNodeAndCache(xyz, this->self()); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } else if ((boost::is_same::value)) { - if (this->isHashed1(xyz)) { - assert(mNode1); - return reinterpret_cast(mNode1); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - - /// Remove all the cached nodes and invalidate the corresponding hash-keys. - virtual void clear() - { - mKey0 = Coord::max(); - mNode0 = NULL; - mKey1 = Coord::max(); - mNode1 = NULL; - } - -private: - // Allow nodes to insert themselves into the cache. - template friend class RootNode; - template friend class InternalNode; - template friend class LeafNode; - // Allow trees to deregister themselves. - template friend class Tree; - - // This private method is merely for convenience. - inline ValueAccessor2& self() const { return const_cast(*this); } - - void getNode(const NodeT0*& node) { node = mNode0; } - void getNode(const NodeT1*& node) { node = mNode1; } - void getNode(const RootNodeT*& node) - { - node = (BaseT::mTree ? &BaseT::mTree->root() : NULL); - } - template void getNode(const OtherNodeType*& node) { node = NULL; } - - void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = NULL; } - void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = NULL; } - template void eraseNode(const OtherNodeType*) {} - - /// Private copy method - inline void copy(const ValueAccessor2& other) - { - mKey0 = other.mKey0; - mNode0 = other.mNode0; - mKey1 = other.mKey1; - mNode1 = other.mNode1; - } - - /// Prevent this accessor from calling Tree::releaseCache() on a tree that - /// no longer exists. (Called by mTree when it is destroyed.) - virtual void release() - { - this->BaseT::release(); - this->clear(); - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). - /// @note This operation is not mutex-protected and is intended to be called - /// only by nodes and only in the context of a getValue() or setValue() call. - inline void insert(const Coord& xyz, const NodeT0* node) - { - assert(node); - mKey0 = xyz & ~(NodeT0::DIM-1); - mNode0 = node; - } - inline void insert(const Coord& xyz, const NodeT1* node) - { - assert(node); - mKey1 = xyz & ~(NodeT1::DIM-1); - mNode1 = node; - } - /// No-op in case a tree traversal attemps to insert a node that - /// is not cached by the ValueAccessor - template inline void insert(const Coord&, const NodeT*) {} - - inline bool isHashed0(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0] - && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1] - && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2]; - } - inline bool isHashed1(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0] - && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1] - && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2]; - } - mutable Coord mKey0; - mutable const NodeT0* mNode0; - mutable Coord mKey1; - mutable const NodeT1* mNode1; -}; // ValueAccessor2 - - -/// @brief Value accessor with three levels of node caching. -/// @details The node cache levels are specified by L0, L1, and L2 -/// with the default values 0, 1 and 2 (defined in the forward declaration) -/// corresponding to a LeafNode, its parent InternalNode, and its parent InternalNode. -/// Since the default configuration of all typed trees and grids, e.g., -/// FloatTree or FloatGrid, has a depth of four, this value accessor is the one -/// used by default. -/// -/// @note This class is for experts only and should rarely be used -/// directly. Instead use ValueAccessor with its default template arguments -template -class ValueAccessor3 : public ValueAccessorBase<_TreeType> -{ -public: - BOOST_STATIC_ASSERT(_TreeType::DEPTH >= 4); - BOOST_STATIC_ASSERT(L0 < L1 && L1 < L2 && L2 < _TreeType::RootNodeType::LEVEL); - typedef _TreeType TreeType; - typedef typename TreeType::ValueType ValueType; - typedef typename TreeType::RootNodeType RootNodeT; - typedef typename TreeType::LeafNodeType LeafNodeT; - typedef ValueAccessorBase BaseT; - typedef typename RootNodeT::NodeChainType InvTreeT; - typedef typename boost::mpl::at >::type NodeT0; - typedef typename boost::mpl::at >::type NodeT1; - typedef typename boost::mpl::at >::type NodeT2; - - /// Constructor from a tree - ValueAccessor3(TreeType& tree) : BaseT(tree), - mKey0(Coord::max()), mNode0(NULL), - mKey1(Coord::max()), mNode1(NULL), - mKey2(Coord::max()), mNode2(NULL) {} - - /// Copy constructor - ValueAccessor3(const ValueAccessor3& other) : BaseT(other) { this->copy(other); } - - /// Asignment operator - ValueAccessor3& operator=(const ValueAccessor3& other) - { - if (&other != this) { - this->BaseT::operator=(other); - this->copy(other); - } - return *this; - } - - /// Return the number of cache levels employed by this ValueAccessor - static Index numCacheLevels() { return 3; } - - /// Virtual destructor - virtual ~ValueAccessor3() {} - - /// Return @c true if any of the nodes along the path to the given - /// voxel have been cached. - bool isCached(const Coord& xyz) const - { - assert(BaseT::mTree); - return this->isHashed2(xyz) || this->isHashed1(xyz) || this->isHashed0(xyz); - } - - /// Return the value of the voxel at the given coordinates. - const ValueType& getValue(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->getValueAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->getValueAndCache(xyz, this->self()); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->getValueAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel at the given coordinates. - bool isValueOn(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->isValueOnAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->isValueOnAndCache(xyz, this->self()); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->isValueOnAndCache(xyz, this->self()); - } - return BaseT::mTree->root().isValueOnAndCache(xyz, this->self()); - } - - /// Return the active state of the voxel as well as its value - bool probeValue(const Coord& xyz, ValueType& value) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->probeValueAndCache(xyz, value, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->probeValueAndCache(xyz, value, this->self()); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->probeValueAndCache(xyz, value, this->self()); - } - return BaseT::mTree->root().probeValueAndCache(xyz, value, this->self()); - } - - /// Return the tree depth (0 = root) at which the value of voxel (x, y, z) resides, - /// or -1 if (x, y, z) isn't explicitly represented in the tree (i.e., if it is - /// implicitly a background voxel). - int getValueDepth(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return RootNodeT::LEVEL - mNode0->getValueLevelAndCache(xyz, this->self()); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return RootNodeT::LEVEL - mNode1->getValueLevelAndCache(xyz, this->self()); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return RootNodeT::LEVEL - mNode2->getValueLevelAndCache(xyz, this->self()); - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()); - } - - /// Return @c true if the value of voxel (x, y, z) resides at the leaf level - /// of the tree, i.e., if it is not a tile value. - bool isVoxel(const Coord& xyz) const - { - assert(BaseT::mTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return mNode0->getValueLevelAndCache(xyz, this->self())==0; - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->getValueLevelAndCache(xyz, this->self())==0; - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->getValueLevelAndCache(xyz, this->self())==0; - } - return BaseT::mTree->root().getValueDepthAndCache(xyz, this->self()) == - static_cast(RootNodeT::LEVEL); - } - - //@{ - /// Set the value of the voxel at the given coordinates and mark the voxel as active. - void setValue(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueAndCache(xyz, value, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->setValueAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueAndCache(xyz, value, *this); - } - } - void setValueOn(const Coord& xyz, const ValueType& value) { this->setValue(xyz, value); } - //@} - - /// Set the value of the voxel at the given coordinate but preserves its active state. - void setValueOnly(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOnlyAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueOnlyAndCache(xyz, value, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->setValueOnlyAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOnlyAndCache(xyz, value, *this); - } - } - - /// Set the value of the voxel at the given coordinates and mark the voxel as inactive. - void setValueOff(const Coord& xyz, const ValueType& value) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setValueOffAndCache(xyz, value, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setValueOffAndCache(xyz, value, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->setValueOffAndCache(xyz, value, *this); - } else { - BaseT::mTree->root().setValueOffAndCache(xyz, value, *this); - } - } - - /// @brief Apply a functor to the value of the voxel at the given coordinates - /// and mark the voxel as active. - /// @details See Tree::modifyValue() for details. - template - void modifyValue(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndCache(xyz, op, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->modifyValueAndCache(xyz, op, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->modifyValueAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndCache(xyz, op, *this); - } - } - - /// @brief Apply a functor to the voxel at the given coordinates. - /// @details See Tree::modifyValueAndActiveState() for details. - template - void modifyValueAndActiveState(const Coord& xyz, const ModifyOp& op) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->modifyValueAndActiveStateAndCache(xyz, op, *this); - } else { - BaseT::mTree->root().modifyValueAndActiveStateAndCache(xyz, op, *this); - } - } - - /// Set the active state of the voxel at the given coordinates without changing its value. - void setActiveState(const Coord& xyz, bool on = true) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - const_cast(mNode0)->setActiveStateAndCache(xyz, on, *this); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - const_cast(mNode1)->setActiveStateAndCache(xyz, on, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - const_cast(mNode2)->setActiveStateAndCache(xyz, on, *this); - } else { - BaseT::mTree->root().setActiveStateAndCache(xyz, on, *this); - } - } - /// Mark the voxel at the given coordinates as active without changing its value. - void setValueOn(const Coord& xyz) { this->setActiveState(xyz, true); } - /// Mark the voxel at the given coordinates as inactive without changing its value. - void setValueOff(const Coord& xyz) { this->setActiveState(xyz, false); } - - /// Return the cached node of type @a NodeType. [Mainly for internal use] - template - NodeT* getNode() - { - const NodeT* node = NULL; - this->getNode(node); - return const_cast(node); - } - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). [Mainly for internal use] - template - void insertNode(const Coord& xyz, NodeT& node) { this->insert(xyz, &node); } - - /// If a node of the given type exists in the cache, remove it, so that - /// isCached(xyz) returns @c false for any voxel (x, y, z) contained in - /// that node. [Mainly for internal use] - template - void eraseNode() - { - const NodeT* node = NULL; - this->eraseNode(node); - } - - /// @brief Add the specified leaf to this tree, possibly creating a child branch - /// in the process. If the leaf node already exists, replace it. - void addLeaf(LeafNodeT* leaf) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed1(leaf->origin())) { - assert(mNode1); - return const_cast(mNode1)->addLeafAndCache(leaf, *this); - } else if (this->isHashed2(leaf->origin())) { - assert(mNode2); - return const_cast(mNode2)->addLeafAndCache(leaf, *this); - } - BaseT::mTree->root().addLeafAndCache(leaf, *this); - } - - /// @brief Add a tile at the specified tree level that contains voxel (x, y, z), - /// possibly deleting existing nodes or creating new nodes in the process. - void addTile(Index level, const Coord& xyz, const ValueType& value, bool state) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->addTileAndCache(level, xyz, value, state, *this); - } if (this->isHashed2(xyz)) { - assert(mNode2); - return const_cast(mNode2)->addTileAndCache(level, xyz, value, state, *this); - } - BaseT::mTree->root().addTileAndCache(level, xyz, value, state, *this); - } - - /// @brief @return the leaf node that contains voxel (x, y, z) and - /// if it doesn't exist, create it, but preserve the values and - /// active states of all voxels. - /// - /// Use this method to preallocate a static tree topology over which to - /// safely perform multithreaded processing. - LeafNodeT* touchLeaf(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - if (this->isHashed0(xyz)) { - assert(mNode0); - return const_cast(mNode0); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->touchLeafAndCache(xyz, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return const_cast(mNode2)->touchLeafAndCache(xyz, *this); - } - return BaseT::mTree->root().touchLeafAndCache(xyz, *this); - } - /// @brief @return a pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - NodeT* probeNode(const Coord& xyz) - { - assert(BaseT::mTree); - BOOST_STATIC_ASSERT(!BaseT::IsConstTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed0(xyz)) { - assert(mNode0); - return reinterpret_cast(const_cast(mNode0)); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return const_cast(mNode1)->template probeNodeAndCache(xyz, *this); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return const_cast(mNode2)->template probeNodeAndCache(xyz, *this); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } else if ((boost::is_same::value)) { - if (this->isHashed1(xyz)) { - assert(mNode1); - return reinterpret_cast(const_cast(mNode1)); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return const_cast(mNode2)->template probeNodeAndCache(xyz, *this); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } else if ((boost::is_same::value)) { - if (this->isHashed2(xyz)) { - assert(mNode2); - return reinterpret_cast(const_cast(mNode2)); - } - return BaseT::mTree->root().template probeNodeAndCache(xyz, *this); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - /// @brief @return a pointer to the leaf node that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - LeafNodeT* probeLeaf(const Coord& xyz) { return this->template probeNode(xyz); } - - /// @brief @return a const pointer to the node of the specified type that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - template - const NodeT* probeConstNode(const Coord& xyz) const - { - assert(BaseT::mTree); - OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN - if ((boost::is_same::value)) { - if (this->isHashed0(xyz)) { - assert(mNode0); - return reinterpret_cast(mNode0); - } else if (this->isHashed1(xyz)) { - assert(mNode1); - return mNode1->template probeConstNodeAndCache(xyz, this->self()); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->template probeConstNodeAndCache(xyz, this->self()); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } else if ((boost::is_same::value)) { - if (this->isHashed1(xyz)) { - assert(mNode1); - return reinterpret_cast(mNode1); - } else if (this->isHashed2(xyz)) { - assert(mNode2); - return mNode2->template probeConstNodeAndCache(xyz, this->self()); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } else if ((boost::is_same::value)) { - if (this->isHashed2(xyz)) { - assert(mNode2); - return reinterpret_cast(mNode2); - } - return BaseT::mTree->root().template probeConstNodeAndCache(xyz, this->self()); - } - return NULL; - OPENVDB_NO_UNREACHABLE_CODE_WARNING_END - } - /// @brief @return a const pointer to the leaf node that contains - /// voxel (x, y, z) and if it doesn't exist, return NULL. - const LeafNodeT* probeConstLeaf(const Coord& xyz) const - { - return this->template probeConstNode(xyz); - } - const LeafNodeT* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); } - - /// Remove all the cached nodes and invalidate the corresponding hash-keys. - virtual void clear() - { - mKey0 = Coord::max(); - mNode0 = NULL; - mKey1 = Coord::max(); - mNode1 = NULL; - mKey2 = Coord::max(); - mNode2 = NULL; - } - -private: - // Allow nodes to insert themselves into the cache. - template friend class RootNode; - template friend class InternalNode; - template friend class LeafNode; - // Allow trees to deregister themselves. - template friend class Tree; - - // This private method is merely for convenience. - inline ValueAccessor3& self() const { return const_cast(*this); } - - /// Private copy method - inline void copy(const ValueAccessor3& other) - { - mKey0 = other.mKey0; - mNode0 = other.mNode0; - mKey1 = other.mKey1; - mNode1 = other.mNode1; - mKey2 = other.mKey2; - mNode2 = other.mNode2; - } - - /// Prevent this accessor from calling Tree::releaseCache() on a tree that - /// no longer exists. (Called by mTree when it is destroyed.) - virtual void release() - { - this->BaseT::release(); - this->clear(); - } - void getNode(const NodeT0*& node) { node = mNode0; } - void getNode(const NodeT1*& node) { node = mNode1; } - void getNode(const NodeT2*& node) { node = mNode2; } - void getNode(const RootNodeT*& node) - { - node = (BaseT::mTree ? &BaseT::mTree->root() : NULL); - } - template void getNode(const OtherNodeType*& node) { node = NULL; } - - void eraseNode(const NodeT0*) { mKey0 = Coord::max(); mNode0 = NULL; } - void eraseNode(const NodeT1*) { mKey1 = Coord::max(); mNode1 = NULL; } - void eraseNode(const NodeT2*) { mKey2 = Coord::max(); mNode2 = NULL; } - template void eraseNode(const OtherNodeType*) {} - - /// Cache the given node, which should lie along the path from the root node to - /// the node containing voxel (x, y, z). - /// @note This operation is not mutex-protected and is intended to be called - /// only by nodes and only in the context of a getValue() or setValue() call. - inline void insert(const Coord& xyz, const NodeT0* node) - { - assert(node); - mKey0 = xyz & ~(NodeT0::DIM-1); - mNode0 = node; - } - inline void insert(const Coord& xyz, const NodeT1* node) - { - assert(node); - mKey1 = xyz & ~(NodeT1::DIM-1); - mNode1 = node; - } - inline void insert(const Coord& xyz, const NodeT2* node) - { - assert(node); - mKey2 = xyz & ~(NodeT2::DIM-1); - mNode2 = node; - } - /// No-op in case a tree traversal attemps to insert a node that - /// is not cached by the ValueAccessor - template - inline void insert(const Coord&, const OtherNodeType*) - { - } - inline bool isHashed0(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[0] - && (xyz[1] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[1] - && (xyz[2] & ~Coord::ValueType(NodeT0::DIM-1)) == mKey0[2]; - } - inline bool isHashed1(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[0] - && (xyz[1] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[1] - && (xyz[2] & ~Coord::ValueType(NodeT1::DIM-1)) == mKey1[2]; - } - inline bool isHashed2(const Coord& xyz) const - { - return (xyz[0] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[0] - && (xyz[1] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[1] - && (xyz[2] & ~Coord::ValueType(NodeT2::DIM-1)) == mKey2[2]; - } - mutable Coord mKey0; - mutable const NodeT0* mNode0; - mutable Coord mKey1; - mutable const NodeT1* mNode1; - mutable Coord mKey2; - mutable const NodeT2* mNode2; -}; // ValueAccessor3 - -} // namespace tree -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_TREE_VALUEACCESSOR_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestBBox.cc b/openvdb_3_0_0_library/unittest/TestBBox.cc deleted file mode 100755 index 6f285a0..0000000 --- a/openvdb_3_0_0_library/unittest/TestBBox.cc +++ /dev/null @@ -1,126 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -typedef float Real; - -class TestBBox: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestBBox); - CPPUNIT_TEST(testBBox); - CPPUNIT_TEST(testCenter); - CPPUNIT_TEST(testExtent); - CPPUNIT_TEST_SUITE_END(); - - void testBBox(); - void testCenter(); - void testExtent(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestBBox); - - -void -TestBBox::testBBox() -{ - typedef openvdb::Vec3R Vec3R; - typedef openvdb::math::BBox BBoxType; - - { - BBoxType B(Vec3R(1,1,1),Vec3R(2,2,2)); - - CPPUNIT_ASSERT(B.isSorted()); - CPPUNIT_ASSERT(B.isInside(Vec3R(1.5,2,2))); - CPPUNIT_ASSERT(!B.isInside(Vec3R(2,3,2))); - B.expand(Vec3R(3,3,3)); - CPPUNIT_ASSERT(B.isInside(Vec3R(3,3,3))); - } - - { - BBoxType B; - CPPUNIT_ASSERT(B.empty()); - const Vec3R expected(1); - B.expand(expected); - CPPUNIT_ASSERT_EQUAL(expected, B.min()); - CPPUNIT_ASSERT_EQUAL(expected, B.max()); - } -} - - -void -TestBBox::testCenter() -{ - using namespace openvdb::math; - - const Vec3 expected(1.5); - - BBox fbox(openvdb::Vec3R(1.0), openvdb::Vec3R(2.0)); - CPPUNIT_ASSERT_EQUAL(expected, fbox.getCenter()); - - BBox ibox(openvdb::Vec3i(1), openvdb::Vec3i(2)); - CPPUNIT_ASSERT_EQUAL(expected, ibox.getCenter()); - - openvdb::CoordBBox cbox(openvdb::Coord(1), openvdb::Coord(2)); - CPPUNIT_ASSERT_EQUAL(expected, cbox.getCenter()); -} - -void -TestBBox::testExtent() -{ - typedef openvdb::Vec3R Vec3R; - typedef openvdb::math::BBox BBoxType; - - { - BBoxType B(Vec3R(-20,0,1),Vec3R(2,2,2)); - CPPUNIT_ASSERT_EQUAL(size_t(2), B.minExtent()); - CPPUNIT_ASSERT_EQUAL(size_t(0), B.maxExtent()); - } - { - BBoxType B(Vec3R(1,0,1),Vec3R(2,21,20)); - CPPUNIT_ASSERT_EQUAL(size_t(0), B.minExtent()); - CPPUNIT_ASSERT_EQUAL(size_t(1), B.maxExtent()); - } - { - BBoxType B(Vec3R(1,0,1),Vec3R(3,1.5,20)); - CPPUNIT_ASSERT_EQUAL(size_t(1), B.minExtent()); - CPPUNIT_ASSERT_EQUAL(size_t(2), B.maxExtent()); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestCoord.cc b/openvdb_3_0_0_library/unittest/TestCoord.cc deleted file mode 100755 index 3f60ca2..0000000 --- a/openvdb_3_0_0_library/unittest/TestCoord.cc +++ /dev/null @@ -1,262 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include // for tbb::split - - -class TestCoord: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestCoord); - CPPUNIT_TEST(testCoord); - CPPUNIT_TEST(testConversion); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testCoordBBox); - CPPUNIT_TEST_SUITE_END(); - - void testCoord(); - void testConversion(); - void testIO(); - void testCoordBBox(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestCoord); - - -void -TestCoord::testCoord() -{ - using openvdb::Coord; - - Coord xyz(-1, 2, 4); - Coord xyz2 = -xyz; - CPPUNIT_ASSERT_EQUAL(Coord(1, -2, -4), xyz2); - - xyz2 = -xyz2; - CPPUNIT_ASSERT_EQUAL(xyz, xyz2); - - xyz.setX(-xyz.x()); - CPPUNIT_ASSERT_EQUAL(Coord(1, 2, 4), xyz); - - xyz2 = xyz >> 1; - CPPUNIT_ASSERT_EQUAL(Coord(0, 1, 2), xyz2); - - xyz2 |= 1; - CPPUNIT_ASSERT_EQUAL(Coord(1, 1, 3), xyz2); - - CPPUNIT_ASSERT(xyz2 != xyz); - CPPUNIT_ASSERT(xyz2 < xyz); - CPPUNIT_ASSERT(xyz2 <= xyz); - - xyz2 -= xyz2; - CPPUNIT_ASSERT_EQUAL(Coord(), xyz2); - - xyz2.reset(0, 4, 4); - xyz2.offset(-1); - CPPUNIT_ASSERT_EQUAL(Coord(-1, 3, 3), xyz2); - - // xyz = (1, 2, 4), xyz2 = (-1, 3, 3) - CPPUNIT_ASSERT_EQUAL(Coord(-1, 2, 3), Coord::minComponent(xyz, xyz2)); - CPPUNIT_ASSERT_EQUAL(Coord(1, 3, 4), Coord::maxComponent(xyz, xyz2)); -} - - -void -TestCoord::testConversion() -{ - using openvdb::Coord; - - openvdb::Vec3I iv(1, 2, 4); - Coord xyz(iv); - CPPUNIT_ASSERT_EQUAL(Coord(1, 2, 4), xyz); - CPPUNIT_ASSERT_EQUAL(iv, xyz.asVec3I()); - CPPUNIT_ASSERT_EQUAL(openvdb::Vec3i(1, 2, 4), xyz.asVec3i()); - - iv = (xyz + iv) + xyz; - CPPUNIT_ASSERT_EQUAL(openvdb::Vec3I(3, 6, 12), iv); - iv = iv - xyz; - CPPUNIT_ASSERT_EQUAL(openvdb::Vec3I(2, 4, 8), iv); - - openvdb::Vec3s fv = xyz.asVec3s(); - CPPUNIT_ASSERT(openvdb::math::isExactlyEqual(openvdb::Vec3s(1, 2, 4), fv)); -} - - -void -TestCoord::testIO() -{ - using openvdb::Coord; - - Coord xyz(-1, 2, 4), xyz2; - - std::ostringstream os(std::ios_base::binary); - CPPUNIT_ASSERT_NO_THROW(xyz.write(os)); - - std::istringstream is(os.str(), std::ios_base::binary); - CPPUNIT_ASSERT_NO_THROW(xyz2.read(is)); - - CPPUNIT_ASSERT_EQUAL(xyz, xyz2); - - os.str(""); - os << xyz; - CPPUNIT_ASSERT_EQUAL(std::string("[-1, 2, 4]"), os.str()); -} - -void -TestCoord::testCoordBBox() -{ - {// Empty constructor - openvdb::CoordBBox b; - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::max(), b.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::min(), b.max()); - CPPUNIT_ASSERT(b.empty()); - } - {// Construct bbox from min and max - const openvdb::Coord min(-1,-2,30), max(20,30,55); - openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(min, b.min()); - CPPUNIT_ASSERT_EQUAL(max, b.max()); - } - {// tbb::split constructor - const openvdb::Coord min(-1,-2,30), max(20,30,55); - openvdb::CoordBBox a(min, max), b(a, tbb::split()); - CPPUNIT_ASSERT_EQUAL(min, b.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(20, 14, 55), b.max()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-1, 15, 30), a.min()); - CPPUNIT_ASSERT_EQUAL(max, a.max()); - } - {// createCube - const openvdb::Coord min(0,8,16); - const openvdb::CoordBBox b = openvdb::CoordBBox::createCube(min, 8); - CPPUNIT_ASSERT_EQUAL(min, b.min()); - CPPUNIT_ASSERT_EQUAL(min + openvdb::Coord(8-1), b.max()); - } - {// inf - const openvdb::CoordBBox b = openvdb::CoordBBox::inf(); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::min(), b.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::max(), b.max()); - } - {// empty, hasVolume and volume - const openvdb::Coord c(1,2,3); - const openvdb::CoordBBox a(c, c), b(c, c.offsetBy(0,-1,0)); - CPPUNIT_ASSERT( a.hasVolume() && !a.empty()); - CPPUNIT_ASSERT(!b.hasVolume() && b.empty()); - CPPUNIT_ASSERT_EQUAL(uint64_t(1), a.volume()); - CPPUNIT_ASSERT_EQUAL(uint64_t(0), b.volume()); - } - {// volume and split constructor - const openvdb::Coord min(-1,-2,30), max(20,30,55); - const openvdb::CoordBBox bbox(min,max); - openvdb::CoordBBox a(bbox), b(a, tbb::split()); - CPPUNIT_ASSERT_EQUAL(bbox.volume(), a.volume() + b.volume()); - openvdb::CoordBBox c(b, tbb::split()); - CPPUNIT_ASSERT_EQUAL(bbox.volume(), a.volume() + b.volume() + c.volume()); - } - {// getCenter - const openvdb::Coord min(1,2,3), max(6,10,15); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(openvdb::Vec3d(3.5, 6.0, 9.0), b.getCenter()); - } - {// a volume that overflows Int32. - typedef openvdb::Int32 Int32; - Int32 maxInt32 = std::numeric_limits::max(); - const openvdb::Coord min(Int32(0), Int32(0), Int32(0)); - const openvdb::Coord max(maxInt32-Int32(2), Int32(2), Int32(2)); - - const openvdb::CoordBBox b(min, max); - uint64_t volume = UINT64_C(19327352814); - CPPUNIT_ASSERT_EQUAL(volume, b.volume()); - } - {// minExtent and maxExtent - const openvdb::Coord min(1,2,3); - { - const openvdb::Coord max = min + openvdb::Coord(1,2,3); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 0); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 2); - } - { - const openvdb::Coord max = min + openvdb::Coord(1,3,2); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 0); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 1); - } - { - const openvdb::Coord max = min + openvdb::Coord(2,1,3); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 1); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 2); - } - { - const openvdb::Coord max = min + openvdb::Coord(2,3,1); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 2); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 1); - } - { - const openvdb::Coord max = min + openvdb::Coord(3,1,2); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 1); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 0); - } - { - const openvdb::Coord max = min + openvdb::Coord(3,2,1); - const openvdb::CoordBBox b(min, max); - CPPUNIT_ASSERT_EQUAL(int(b.minExtent()), 2); - CPPUNIT_ASSERT_EQUAL(int(b.maxExtent()), 0); - } - } - - {//reset - openvdb::CoordBBox b; - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::max(), b.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::min(), b.max()); - CPPUNIT_ASSERT(b.empty()); - - const openvdb::Coord min(-1,-2,30), max(20,30,55); - b.reset(min, max); - CPPUNIT_ASSERT_EQUAL(min, b.min()); - CPPUNIT_ASSERT_EQUAL(max, b.max()); - CPPUNIT_ASSERT(!b.empty()); - - b.reset(); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::max(), b.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord::min(), b.max()); - CPPUNIT_ASSERT(b.empty()); - } - -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestCpt.cc b/openvdb_3_0_0_library/unittest/TestCpt.cc deleted file mode 100755 index 16298a3..0000000 --- a/openvdb_3_0_0_library/unittest/TestCpt.cc +++ /dev/null @@ -1,565 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include // for old GradientStencil -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestCpt: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestCpt); - CPPUNIT_TEST(testCpt); // Cpt in World Space - CPPUNIT_TEST(testCptStencil); - CPPUNIT_TEST(testCptTool); // Cpt tool - CPPUNIT_TEST(testCptMaskedTool); - CPPUNIT_TEST(testOldStyleStencils); // old stencil impl - CPPUNIT_TEST_SUITE_END(); - - void testCpt(); - void testCptStencil(); - void testCptTool(); - void testCptMaskedTool(); - void testOldStyleStencils(); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestCpt); - -void -TestCpt::testCpt() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - - { // unit voxel size tests - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - const FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64,64,64); - const Vec3f center(35.0, 30.0f, 40.0f); - const float radius=0;//point at {35,30,40} - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - - AccessorType inAccessor = grid->getConstAccessor(); - // this uses the gradient. Only test for a few maps, since the gradient is - // tested elsewhere - - Coord xyz(35,30,30); - - math::TranslationMap translate; - // Note the CPT::result is in continuous index space - Vec3f P = math::CPT::result(translate, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - // CPT_RANGE::result is in the range of the map - // CPT_RANGE::result = map.applyMap(CPT::result()) - // for our tests, the map is an identity so in this special case - // the two versions of the Cpt should exactly agree - P = math::CPT_RANGE::result(translate, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - xyz.reset(35,30,35); - - P = math::CPT::result(translate, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - - P = math::CPT_RANGE::result(translate, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - } - { - // NON-UNIT VOXEL SIZE - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - AccessorType inAccessor = grid->getConstAccessor(); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10;//i.e. (16,8,10) and (6,8,0) are on the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - - Coord xyz(20,16,20);//i.e. (10,8,10) in world space or 6 world units inside the sphere - math::AffineMap affine(voxel_size*math::Mat3d::identity()); - - Vec3f P = math::CPT::result(affine, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(32,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20,P[2]); - - - P = math::CPT_RANGE::result(affine, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(10,P[2]); - - xyz.reset(12,16,10); - - P = math::CPT::result(affine, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(12,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - - P = math::CPT_RANGE::result(affine, inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(6,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - } - { - // NON-UNIFORM SCALING - Vec3d voxel_sizes(0.5, 1, 0.5); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::Ptr(new math::Transform(base_map))); - - CPPUNIT_ASSERT(grid->empty()); - AccessorType inAccessor = grid->getConstAccessor(); - - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10;//i.e. (16,8,10) and (6,8,0) are on the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - - Coord ijk = grid->transform().worldToIndexNodeCentered(Vec3d(10,8,10)); - - //Coord xyz(20,16,20);//i.e. (10,8,10) in world space or 6 world units inside the sphere - math::ScaleMap scale(voxel_sizes); - Vec3f P; - P = math::CPT::result(scale, inAccessor, ijk); - ASSERT_DOUBLES_EXACTLY_EQUAL(32,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20,P[2]); - - - // world space result - P = math::CPT_RANGE::result(scale, inAccessor, ijk); - CPPUNIT_ASSERT_DOUBLES_EQUAL(16,P[0], 0.02 ); - CPPUNIT_ASSERT_DOUBLES_EQUAL(8, P[1], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(10,P[2], 0.02); - - //xyz.reset(12,16,10); - ijk = grid->transform().worldToIndexNodeCentered(Vec3d(6,8,5)); - - P = math::CPT::result(scale, inAccessor, ijk); - ASSERT_DOUBLES_EXACTLY_EQUAL(12,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - - P = math::CPT_RANGE::result(scale, inAccessor, ijk); - CPPUNIT_ASSERT_DOUBLES_EQUAL(6,P[0], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(8,P[1], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0,P[2], 0.02); - - } - -} - - -void -TestCpt::testCptStencil() -{ - using namespace openvdb; - - { // UNIT VOXEL TEST - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - const FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - // this uses the gradient. Only test for a few maps, since the gradient is - // tested elsewhere - - math::SevenPointStencil sevenpt(*grid); - math::SecondOrderDenseStencil dense_2nd(*grid); - - - Coord xyz(35,30,30); - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - sevenpt.moveTo(xyz); - dense_2nd.moveTo(xyz); - - math::TranslationMap translate; - // Note the CPT::result is in continuous index space - Vec3f P = math::CPT::result(translate, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - // CPT_RANGE::result_stencil is in the range of the map - // CPT_RANGE::result_stencil = map.applyMap(CPT::result_stencil()) - // for our tests, the map is an identity so in this special case - // the two versions of the Cpt should exactly agree - P = math::CPT_RANGE::result(translate, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - xyz.reset(35,30,35); - - sevenpt.moveTo(xyz); - dense_2nd.moveTo(xyz); - - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - P = math::CPT::result(translate, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - - P = math::CPT_RANGE::result(translate, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - - xyz.reset(35,30,30); - - sevenpt.moveTo(xyz); - dense_2nd.moveTo(xyz); - - math::AffineMap affine; - - P = math::CPT::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - - P = math::CPT_RANGE::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - xyz.reset(35,30,35); - - sevenpt.moveTo(xyz); - dense_2nd.moveTo(xyz); - - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - P = math::CPT::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - P = math::CPT_RANGE::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - } - { - // NON-UNIT VOXEL SIZE - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10;//i.e. (16,8,10) and (6,8,0) are on the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - - - math::SecondOrderDenseStencil dense_2nd(*grid); - - - Coord xyz(20,16,20);//i.e. (10,8,10) in world space or 6 world units inside the sphere - math::AffineMap affine(voxel_size*math::Mat3d::identity()); - dense_2nd.moveTo(xyz); - - Vec3f P = math::CPT::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(32,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20,P[2]); - - - P = math::CPT_RANGE::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(10,P[2]); - - xyz.reset(12,16,10); - dense_2nd.moveTo(xyz); - - P = math::CPT::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(12,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - - P = math::CPT_RANGE::result(affine, dense_2nd); - ASSERT_DOUBLES_EXACTLY_EQUAL(6,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - } - { - // NON-UNIFORM SCALING - Vec3d voxel_sizes(0.5, 1, 0.5); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::Ptr(new math::Transform(base_map))); - - CPPUNIT_ASSERT(grid->empty()); - - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10;//i.e. (16,8,10) and (6,8,0) are on the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - - Coord ijk = grid->transform().worldToIndexNodeCentered(Vec3d(10,8,10)); - math::SevenPointStencil sevenpt(*grid); - - sevenpt.moveTo(ijk); - - //Coord xyz(20,16,20);//i.e. (10,8,10) in world space or 6 world units inside the sphere - math::ScaleMap scale(voxel_sizes); - Vec3f P; - P = math::CPT::result(scale, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(32,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20,P[2]); - - - // world space result - P = math::CPT_RANGE::result(scale, sevenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(16,P[0], 0.02 ); - CPPUNIT_ASSERT_DOUBLES_EQUAL(8, P[1], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(10,P[2], 0.02); - - //xyz.reset(12,16,10); - ijk = grid->transform().worldToIndexNodeCentered(Vec3d(6,8,5)); - sevenpt.moveTo(ijk); - P = math::CPT::result(scale, sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(12,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(8,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0,P[2]); - - - P = math::CPT_RANGE::result(scale, sevenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(6,P[0], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(8,P[1], 0.02); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0,P[2], 0.02); - - } - - -} - -void -TestCpt::testCptTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - const FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - // run the tool - typedef openvdb::tools::Cpt FloatCpt; - FloatCpt cpt(*grid); - FloatCpt::OutGridType::Ptr cptGrid = - cpt.process(true/*threaded*/, false/*use world transform*/); - - FloatCpt::OutGridType::ConstAccessor cptAccessor = cptGrid->getConstAccessor(); - - Coord xyz(35,30,30); - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - Vec3f P = cptAccessor.getValue(xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); - - xyz.reset(35,30,35); - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - P = cptAccessor.getValue(xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0],P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1],P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2],P[2]); -} - -void -TestCpt::testCptMaskedTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - const FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - BoolGrid::Ptr maskGrid = BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - // run the tool - typedef openvdb::tools::Cpt FloatCpt; - FloatCpt cpt(*grid, *maskGrid); - FloatCpt::OutGridType::Ptr cptGrid = - cpt.process(true/*threaded*/, false/*use world transform*/); - - FloatCpt::OutGridType::ConstAccessor cptAccessor = cptGrid->getConstAccessor(); - - // inside the masked region - Coord xyz(35,30,30); - CPPUNIT_ASSERT(tree.isValueOn(xyz)); - - Vec3f P = cptAccessor.getValue(xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[0], P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[1], P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(center[2], P[2]); - - // outside the masked region - xyz.reset(42,42,42); - CPPUNIT_ASSERT(!cptAccessor.isValueOn(xyz)); -} - -void -TestCpt::testOldStyleStencils() -{ - using namespace openvdb; - - {// test of level set to sphere at (6,8,10) with R=10 and dx=0.5 - - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(/*voxel size=*/0.5)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f,8.0f,10.0f);//i.e. (12,16,20) in index space - const float radius=10;//i.e. (16,8,10) and (6,8,0) are on the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - math::GradStencil gs(*grid); - - Coord xyz(20,16,20);//i.e. (10,8,10) in world space or 6 world units inside the sphere - gs.moveTo(xyz); - float dist = gs.getValue();//signed closest distance to sphere in world coordinates - Vec3f P = gs.cpt();//closes point to sphere in index space - ASSERT_DOUBLES_EXACTLY_EQUAL(dist,-6); - ASSERT_DOUBLES_EXACTLY_EQUAL(32,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20,P[2]); - - xyz.reset(12,16,10);//i.e. (6,8,5) in world space or 15 world units inside the sphere - gs.moveTo(xyz); - dist = gs.getValue();//signed closest distance to sphere in world coordinates - P = gs.cpt();//closes point to sphere in index space - ASSERT_DOUBLES_EXACTLY_EQUAL(-5,dist); - ASSERT_DOUBLES_EXACTLY_EQUAL(12,P[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(16,P[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0,P[2]); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestCurl.cc b/openvdb_3_0_0_library/unittest/TestCurl.cc deleted file mode 100755 index a9bbfa8..0000000 --- a/openvdb_3_0_0_library/unittest/TestCurl.cc +++ /dev/null @@ -1,592 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/1e-6); - -namespace { -const int GRID_DIM = 10; -} - - -class TestCurl: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestCurl); - CPPUNIT_TEST(testISCurl); // Gradient in Index Space - CPPUNIT_TEST(testISCurlStencil); - CPPUNIT_TEST(testWSCurl); // Gradient in World Space - CPPUNIT_TEST(testWSCurlStencil); - CPPUNIT_TEST(testCurlTool); // Gradient tool - CPPUNIT_TEST(testCurlMaskedTool); // Gradient tool - - CPPUNIT_TEST_SUITE_END(); - - void testISCurl(); - void testISCurlStencil(); - void testWSCurl(); - void testWSCurlStencil(); - void testCurlTool(); - void testCurlMaskedTool(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestCurl); - - -void -TestCurl::testCurlTool() -{ - using namespace openvdb; - - VectorGrid::Ptr inGrid = VectorGrid::create(); - const VectorTree& inTree = inGrid->tree(); - CPPUNIT_ASSERT(inTree.empty()); - - VectorGrid::Accessor inAccessor = inGrid->getAccessor(); - int dim = GRID_DIM; - for (int x = -dim; xactiveVoxelCount())); - - VectorGrid::ConstAccessor curlAccessor = curl_grid->getConstAccessor(); - --dim;//ignore boundary curl vectors - for (int x = -dim; x -#include -#include -#include -#include -#include -#ifdef BENCHMARK_TEST -#include -#endif - - -class TestDense: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestDense); - - CPPUNIT_TEST(testDenseZYX); - CPPUNIT_TEST(testDenseXYZ); - - CPPUNIT_TEST(testCopyZYX); - CPPUNIT_TEST(testCopyXYZ); - - CPPUNIT_TEST(testCopyBoolZYX); - CPPUNIT_TEST(testCopyBoolXYZ); - - CPPUNIT_TEST(testCopyFromDenseWithOffsetZYX); - CPPUNIT_TEST(testCopyFromDenseWithOffsetXYZ); - - CPPUNIT_TEST(testDense2SparseZYX); - CPPUNIT_TEST(testDense2SparseXYZ); - - CPPUNIT_TEST(testDense2Sparse2ZYX); - CPPUNIT_TEST(testDense2Sparse2XYZ); - - CPPUNIT_TEST(testInvalidBBoxZYX); - CPPUNIT_TEST(testInvalidBBoxXYZ); - - CPPUNIT_TEST(testDense2Sparse2DenseZYX); - CPPUNIT_TEST(testDense2Sparse2DenseXYZ); - CPPUNIT_TEST_SUITE_END(); - - void testDenseZYX(); - void testDenseXYZ(); - - template - void testCopy(); - void testCopyZYX() { this->testCopy(); } - void testCopyXYZ() { this->testCopy(); } - - template - void testCopyBool(); - void testCopyBoolZYX() { this->testCopyBool(); } - void testCopyBoolXYZ() { this->testCopyBool(); } - - template - void testCopyFromDenseWithOffset(); - void testCopyFromDenseWithOffsetZYX() { - this->testCopyFromDenseWithOffset(); - } - void testCopyFromDenseWithOffsetXYZ() { - this->testCopyFromDenseWithOffset(); - } - - template - void testDense2Sparse(); - void testDense2SparseZYX() { this->testDense2Sparse(); } - void testDense2SparseXYZ() { this->testDense2Sparse(); } - - template - void testDense2Sparse2(); - void testDense2Sparse2ZYX() { this->testDense2Sparse2(); } - void testDense2Sparse2XYZ() { this->testDense2Sparse2(); } - - template - void testInvalidBBox(); - void testInvalidBBoxZYX() { this->testInvalidBBox(); } - void testInvalidBBoxXYZ() { this->testInvalidBBox(); } - - template - void testDense2Sparse2Dense(); - void testDense2Sparse2DenseZYX() { this->testDense2Sparse2Dense(); } - void testDense2Sparse2DenseXYZ() { this->testDense2Sparse2Dense(); } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestDense); - - -void -TestDense::testDenseZYX() -{ - const openvdb::CoordBBox bbox(openvdb::Coord(-40,-5, 6), - openvdb::Coord(-11, 7,22)); - openvdb::tools::Dense dense(bbox);//LayoutZYX is the default - - // Check Dense::valueCount - const int size = static_cast(dense.valueCount()); - CPPUNIT_ASSERT_EQUAL(30*13*17, size); - - // Check Dense::fill(float) and Dense::getValue(size_t) - const float v = 0.234f; - dense.fill(v); - for (int i=0; i dense(bbox); - - // Check Dense::valueCount - const int size = static_cast(dense.valueCount()); - CPPUNIT_ASSERT_EQUAL(30*13*17, size); - - // Check Dense::fill(float) and Dense::getValue(size_t) - const float v = 0.234f; - dense.fill(v); - for (int i=0; i > -class CheckDense -{ -public: - typedef typename TreeT::ValueType ValueT; - - CheckDense() : mTree(NULL), mDense(NULL) - { - CPPUNIT_ASSERT(DenseT::memoryLayout() == openvdb::tools::LayoutZYX || - DenseT::memoryLayout() == openvdb::tools::LayoutXYZ ); - } - - void check(const TreeT& tree, const DenseT& dense) - { - mTree = &tree; - mDense = &dense; - tbb::parallel_for(dense.bbox(), *this); - } - void operator()(const openvdb::CoordBBox& bbox) const - { - openvdb::tree::ValueAccessor acc(*mTree); - - if (DenseT::memoryLayout() == openvdb::tools::LayoutZYX) {//resolved at compiletime - for (openvdb::Coord P(bbox.min()); P[0] <= bbox.max()[0]; ++P[0]) { - for (P[1] = bbox.min()[1]; P[1] <= bbox.max()[1]; ++P[1]) { - for (P[2] = bbox.min()[2]; P[2] <= bbox.max()[2]; ++P[2]) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(acc.getValue(P), mDense->getValue(P), - /*tolerance=*/0.0001); - } - } - } - } else { - for (openvdb::Coord P(bbox.min()); P[2] <= bbox.max()[2]; ++P[2]) { - for (P[1] = bbox.min()[1]; P[1] <= bbox.max()[1]; ++P[1]) { - for (P[0] = bbox.min()[0]; P[0] <= bbox.max()[0]; ++P[0]) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(acc.getValue(P), mDense->getValue(P), - /*tolerance=*/0.0001); - } - } - } - } - } -private: - const TreeT* mTree; - const DenseT* mDense; -};// CheckDense - -template -void -TestDense::testCopy() -{ - using namespace openvdb; - - //std::cerr << "\nTesting testCopy with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef tools::Dense DenseT; - CheckDense checkDense; - const float radius = 10.0f, tolerance = 0.00001f; - const Vec3f center(0.0f); - // decrease the voxelSize to test larger grids -#ifdef BENCHMARK_TEST - const float voxelSize = 0.05f, width = 5.0f; -#else - const float voxelSize = 0.5f, width = 5.0f; -#endif - - // Create a VDB containing a level set of a sphere - FloatGrid::Ptr grid = - tools::createLevelSetSphere(radius, center, voxelSize, width); - FloatTree& tree0 = grid->tree(); - - // Create an empty dense grid - DenseT dense(grid->evalActiveVoxelBoundingBox()); -#ifdef BENCHMARK_TEST - std::cerr << "\nBBox = " << grid->evalActiveVoxelBoundingBox() << std::endl; -#endif - - {//check Dense::fill - dense.fill(voxelSize); -#ifndef BENCHMARK_TEST - checkDense.check(FloatTree(voxelSize), dense); -#endif - } - - {// parallel convert to dense -#ifdef BENCHMARK_TEST - util::CpuTimer ts; - ts.start("CopyToDense"); -#endif - tools::copyToDense(*grid, dense); -#ifdef BENCHMARK_TEST - ts.stop(); -#else - checkDense.check(tree0, dense); -#endif - } - - {// Parallel create from dense -#ifdef BENCHMARK_TEST - util::CpuTimer ts; - ts.start("CopyFromDense"); -#endif - FloatTree tree1(tree0.background()); - tools::copyFromDense(dense, tree1, tolerance); -#ifdef BENCHMARK_TEST - ts.stop(); -#else - checkDense.check(tree1, dense); -#endif - } -} - -template -void -TestDense::testCopyBool() -{ - using namespace openvdb; - - //std::cerr << "\nTesting testCopyBool with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - const Coord bmin(-1), bmax(8); - const CoordBBox bbox(bmin, bmax); - - BoolGrid::Ptr grid = createGrid(false); - BoolGrid::ConstAccessor acc = grid->getConstAccessor(); - - typedef openvdb::tools::Dense DenseT; - DenseT dense(bbox); - dense.fill(false); - - // Start with sparse and dense grids both filled with false. - Coord xyz; - int &x = xyz[0], &y = xyz[1], &z = xyz[2]; - for (x = bmin.x(); x <= bmax.x(); ++x) { - for (y = bmin.y(); y <= bmax.y(); ++y) { - for (z = bmin.z(); z <= bmax.z(); ++z) { - CPPUNIT_ASSERT_EQUAL(false, dense.getValue(xyz)); - CPPUNIT_ASSERT_EQUAL(false, acc.getValue(xyz)); - } - } - } - - // Fill the dense grid with true. - dense.fill(true); - // Copy the contents of the dense grid to the sparse grid. - tools::copyFromDense(dense, *grid, /*tolerance=*/false); - - // Verify that both sparse and dense grids are now filled with true. - for (x = bmin.x(); x <= bmax.x(); ++x) { - for (y = bmin.y(); y <= bmax.y(); ++y) { - for (z = bmin.z(); z <= bmax.z(); ++z) { - CPPUNIT_ASSERT_EQUAL(true, dense.getValue(xyz)); - CPPUNIT_ASSERT_EQUAL(true, acc.getValue(xyz)); - } - } - } - - // Fill the dense grid with false. - dense.fill(false); - // Copy the contents (= true) of the sparse grid to the dense grid. - tools::copyToDense(*grid, dense); - - // Verify that the dense grid is now filled with true. - for (x = bmin.x(); x <= bmax.x(); ++x) { - for (y = bmin.y(); y <= bmax.y(); ++y) { - for (z = bmin.z(); z <= bmax.z(); ++z) { - CPPUNIT_ASSERT_EQUAL(true, dense.getValue(xyz)); - } - } - } -} - - -// Test copying from a dense grid to a sparse grid with various bounding boxes. -template -void -TestDense::testCopyFromDenseWithOffset() -{ - using namespace openvdb; - - //std::cerr << "\nTesting testCopyFromDenseWithOffset with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef openvdb::tools::Dense DenseT; - - const int DIM = 20, COUNT = DIM * DIM * DIM; - const float FOREGROUND = 99.0f, BACKGROUND = 5000.0f; - - const int OFFSET[] = { 1, -1, 1001, -1001 }; - for (int offsetIdx = 0; offsetIdx < 4; ++offsetIdx) { - - const int offset = OFFSET[offsetIdx]; - const CoordBBox bbox = CoordBBox::createCube(Coord(offset), DIM); - - DenseT dense(bbox, FOREGROUND); - CPPUNIT_ASSERT_EQUAL(bbox, dense.bbox()); - - FloatGrid grid(BACKGROUND); - tools::copyFromDense(dense, grid, /*tolerance=*/0.0); - - const CoordBBox gridBBox = grid.evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT_EQUAL(bbox, gridBBox); - CPPUNIT_ASSERT_EQUAL(COUNT, int(grid.activeVoxelCount())); - - FloatGrid::ConstAccessor acc = grid.getConstAccessor(); - for (int i = gridBBox.min()[0], ie = gridBBox.max()[0]; i < ie; ++i) { - for (int j = gridBBox.min()[1], je = gridBBox.max()[1]; j < je; ++j) { - for (int k = gridBBox.min()[2], ke = gridBBox.max()[2]; k < ke; ++k) { - const Coord ijk(i, j, k); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - FOREGROUND, acc.getValue(ijk), /*tolerance=*/0.0); - CPPUNIT_ASSERT(acc.isValueOn(ijk)); - } - } - } - } -} - -template -void -TestDense::testDense2Sparse() -{ - // The following test revealed a bug in v2.0.0b2 - using namespace openvdb; - - //std::cerr << "\nTesting testDense2Sparse with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef tools::Dense DenseT; - - // Test Domain Resolution - size_t sizeX = 8; - size_t sizeY = 8; - size_t sizeZ = 9; - - // Define a dense grid - DenseT dense(Coord(sizeX, sizeY, sizeZ)); - const CoordBBox bboxD = dense.bbox(); - // std::cerr << "\nDense bbox" << bboxD << std::endl; - - // Verify that the CoordBBox is truely used as [inclusive, inclusive] - CPPUNIT_ASSERT(dense.valueCount() == sizeX * sizeY * sizeZ ); - - // Fill the dense grid with constant value 1. - dense.fill(1.0f); - - // Create two empty float grids - FloatGrid::Ptr gridS = FloatGrid::create(0.0f /*background*/); - FloatGrid::Ptr gridP = FloatGrid::create(0.0f /*background*/); - - // Convert in serial and parallel modes - tools::copyFromDense(dense, *gridS, /*tolerance*/0.0f, /*serial = */ true); - tools::copyFromDense(dense, *gridP, /*tolerance*/0.0f, /*serial = */ false); - - float minS, maxS; - float minP, maxP; - - gridS->evalMinMax(minS, maxS); - gridP->evalMinMax(minP, maxP); - - const float tolerance = 0.0001f; - - CPPUNIT_ASSERT_DOUBLES_EQUAL(minS, minP, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(maxS, maxP, tolerance); - CPPUNIT_ASSERT_EQUAL(gridP->activeVoxelCount(), Index64(sizeX * sizeY * sizeZ)); - - const FloatTree& treeS = gridS->tree(); - const FloatTree& treeP = gridP->tree(); - - // Values in Test Domain are correct - for (Coord ijk(bboxD.min()); ijk[0] <= bboxD.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxD.min()[1]; ijk[1] <= bboxD.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxD.min()[2]; ijk[2] <= bboxD.max()[2]; ++ijk[2]) { - - const float expected = bboxD.isInside(ijk) ? 1.f : 0.f; - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, 1.f, tolerance); - - const float& vS = treeS.getValue(ijk); - const float& vP = treeP.getValue(ijk); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vS, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vP, tolerance); - } - } - } - - CoordBBox bboxP = gridP->evalActiveVoxelBoundingBox(); - const Index64 voxelCountP = gridP->activeVoxelCount(); - //std::cerr << "\nParallel: bbox=" << bboxP << " voxels=" << voxelCountP << std::endl; - CPPUNIT_ASSERT( bboxP == bboxD ); - CPPUNIT_ASSERT_EQUAL( dense.valueCount(), voxelCountP); - - CoordBBox bboxS = gridS->evalActiveVoxelBoundingBox(); - const Index64 voxelCountS = gridS->activeVoxelCount(); - //std::cerr << "\nSerial: bbox=" << bboxS << " voxels=" << voxelCountS << std::endl; - CPPUNIT_ASSERT( bboxS == bboxD ); - CPPUNIT_ASSERT_EQUAL( dense.valueCount(), voxelCountS); - - // Topology - CPPUNIT_ASSERT( bboxS.isInside(bboxS) ); - CPPUNIT_ASSERT( bboxP.isInside(bboxP) ); - CPPUNIT_ASSERT( bboxS.isInside(bboxP) ); - CPPUNIT_ASSERT( bboxP.isInside(bboxS) ); - - /// Check that the two grids agree - for (Coord ijk(bboxS.min()); ijk[0] <= bboxS.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxS.min()[1]; ijk[1] <= bboxS.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxS.min()[2]; ijk[2] <= bboxS.max()[2]; ++ijk[2]) { - - const float& vS = treeS.getValue(ijk); - const float& vP = treeP.getValue(ijk); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(vS, vP, tolerance); - - // the value we should get based on the original domain - const float expected = bboxD.isInside(ijk) ? 1.f : 0.f; - - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vP, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vS, tolerance); - } - } - } - - - // Verify the tree topology matches. - - CPPUNIT_ASSERT_EQUAL(gridP->activeVoxelCount(), gridS->activeVoxelCount()); - CPPUNIT_ASSERT(gridP->evalActiveVoxelBoundingBox() == gridS->evalActiveVoxelBoundingBox()); - CPPUNIT_ASSERT(treeP.hasSameTopology(treeS) ); - -} - -template -void -TestDense::testDense2Sparse2() -{ - // The following tests copying a dense grid into a VDB tree with - // existing values outside the bbox of the dense grid. - - using namespace openvdb; - - //std::cerr << "\nTesting testDense2Sparse2 with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef tools::Dense DenseT; - - // Test Domain Resolution - const int sizeX = 8, sizeY = 8, sizeZ = 9; - const Coord magicVoxel(sizeX, sizeY, sizeZ); - - // Define a dense grid - DenseT dense(Coord(sizeX, sizeY, sizeZ)); - const CoordBBox bboxD = dense.bbox(); - //std::cerr << "\nDense bbox" << bboxD << std::endl; - - // Verify that the CoordBBox is truely used as [inclusive, inclusive] - CPPUNIT_ASSERT_EQUAL(sizeX * sizeY * sizeZ, static_cast(dense.valueCount())); - - // Fill the dense grid with constant value 1. - dense.fill(1.0f); - - // Create two empty float grids - FloatGrid::Ptr gridS = FloatGrid::create(0.0f /*background*/); - FloatGrid::Ptr gridP = FloatGrid::create(0.0f /*background*/); - gridS->tree().setValue(magicVoxel, 5.0f); - gridP->tree().setValue(magicVoxel, 5.0f); - - // Convert in serial and parallel modes - tools::copyFromDense(dense, *gridS, /*tolerance*/0.0f, /*serial = */ true); - tools::copyFromDense(dense, *gridP, /*tolerance*/0.0f, /*serial = */ false); - - float minS, maxS; - float minP, maxP; - - gridS->evalMinMax(minS, maxS); - gridP->evalMinMax(minP, maxP); - - const float tolerance = 0.0001f; - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0f, minP, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0f, minS, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0f, maxP, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0f, maxS, tolerance); - CPPUNIT_ASSERT_EQUAL(gridP->activeVoxelCount(), Index64(1 + sizeX * sizeY * sizeZ)); - - const FloatTree& treeS = gridS->tree(); - const FloatTree& treeP = gridP->tree(); - - // Values in Test Domain are correct - for (Coord ijk(bboxD.min()); ijk[0] <= bboxD.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxD.min()[1]; ijk[1] <= bboxD.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxD.min()[2]; ijk[2] <= bboxD.max()[2]; ++ijk[2]) { - - const float expected = bboxD.isInside(ijk) ? 1.0f : 0.0f; - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, 1.0f, tolerance); - - const float& vS = treeS.getValue(ijk); - const float& vP = treeP.getValue(ijk); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vS, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vP, tolerance); - } - } - } - - CoordBBox bboxP = gridP->evalActiveVoxelBoundingBox(); - const Index64 voxelCountP = gridP->activeVoxelCount(); - //std::cerr << "\nParallel: bbox=" << bboxP << " voxels=" << voxelCountP << std::endl; - CPPUNIT_ASSERT( bboxP != bboxD ); - CPPUNIT_ASSERT( bboxP == CoordBBox(Coord(0,0,0), magicVoxel) ); - CPPUNIT_ASSERT_EQUAL( dense.valueCount()+1, voxelCountP); - - CoordBBox bboxS = gridS->evalActiveVoxelBoundingBox(); - const Index64 voxelCountS = gridS->activeVoxelCount(); - //std::cerr << "\nSerial: bbox=" << bboxS << " voxels=" << voxelCountS << std::endl; - CPPUNIT_ASSERT( bboxS != bboxD ); - CPPUNIT_ASSERT( bboxS == CoordBBox(Coord(0,0,0), magicVoxel) ); - CPPUNIT_ASSERT_EQUAL( dense.valueCount()+1, voxelCountS); - - // Topology - CPPUNIT_ASSERT( bboxS.isInside(bboxS) ); - CPPUNIT_ASSERT( bboxP.isInside(bboxP) ); - CPPUNIT_ASSERT( bboxS.isInside(bboxP) ); - CPPUNIT_ASSERT( bboxP.isInside(bboxS) ); - - /// Check that the two grids agree - for (Coord ijk(bboxS.min()); ijk[0] <= bboxS.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxS.min()[1]; ijk[1] <= bboxS.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxS.min()[2]; ijk[2] <= bboxS.max()[2]; ++ijk[2]) { - - const float& vS = treeS.getValue(ijk); - const float& vP = treeP.getValue(ijk); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(vS, vP, tolerance); - - // the value we should get based on the original domain - const float expected = bboxD.isInside(ijk) ? 1.0f - : ijk == magicVoxel ? 5.0f : 0.0f; - - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vP, tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, vS, tolerance); - } - } - } - - // Verify the tree topology matches. - - CPPUNIT_ASSERT_EQUAL(gridP->activeVoxelCount(), gridS->activeVoxelCount()); - CPPUNIT_ASSERT(gridP->evalActiveVoxelBoundingBox() == gridS->evalActiveVoxelBoundingBox()); - CPPUNIT_ASSERT(treeP.hasSameTopology(treeS) ); - -} - -template -void -TestDense::testInvalidBBox() -{ - using namespace openvdb; - - //std::cerr << "\nTesting testInvalidBBox with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef tools::Dense DenseT; - const CoordBBox badBBox(Coord(1, 1, 1), Coord(-1, 2, 2)); - - CPPUNIT_ASSERT(badBBox.empty()); - CPPUNIT_ASSERT_THROW(DenseT dense(badBBox), ValueError); -} - -template -void -TestDense::testDense2Sparse2Dense() -{ - using namespace openvdb; - - //std::cerr << "\nTesting testDense2Sparse2Dense with " - // << (Layout == tools::LayoutXYZ ? "XYZ" : "ZYX") << " memory layout" - // << std::endl; - - typedef tools::Dense DenseT; - - const CoordBBox bboxBig(Coord(-12, 7, -32), Coord(12, 14, -15)); - const CoordBBox bboxSmall(Coord(-10, 8, -31), Coord(10, 12, -20)); - - - // A larger bbox - CoordBBox bboxBigger = bboxBig; - bboxBigger.expand(Coord(10)); - - - // Small is in big - CPPUNIT_ASSERT(bboxBig.isInside(bboxSmall)); - - // Big is in Bigger - CPPUNIT_ASSERT(bboxBigger.isInside(bboxBig)); - - // Construct a small dense grid - DenseT denseSmall(bboxSmall, 0.f); - { - // insert non-const values - const int n = static_cast(denseSmall.valueCount()); - float* d = denseSmall.data(); - for (int i = 0; i < n; ++i) { d[i] = static_cast(i); } - } - // Construct large dense grid - DenseT denseBig(bboxBig, 0.f); - { - // insert non-const values - const int n = static_cast(denseBig.valueCount()); - float* d = denseBig.data(); - for (int i = 0; i < n; ++i) { d[i] = static_cast(i); } - } - - // Make a sparse grid to copy this data into - FloatGrid::Ptr grid = FloatGrid::create(3.3f /*background*/); - tools::copyFromDense(denseBig, *grid, /*tolerance*/0.0f, /*serial = */ true); - tools::copyFromDense(denseSmall, *grid, /*tolerance*/0.0f, /*serial = */ false); - - const FloatTree& tree = grid->tree(); - // - CPPUNIT_ASSERT_EQUAL(bboxBig.volume(), grid->activeVoxelCount()); - - // iterate over the Bigger - for (Coord ijk(bboxBigger.min()); ijk[0] <= bboxBigger.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxBigger.min()[1]; ijk[1] <= bboxBigger.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxBigger.min()[2]; ijk[2] <= bboxBigger.max()[2]; ++ijk[2]) { - - float expected = 3.3f; - if (bboxSmall.isInside(ijk)) { - expected = denseSmall.getValue(ijk); - } else if (bboxBig.isInside(ijk)) { - expected = denseBig.getValue(ijk); - } - - const float& value = tree.getValue(ijk); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, value, 0.0001); - - } - } - } - - // Convert to Dense in small bbox - { - DenseT denseSmall2(bboxSmall); - tools::copyToDense(*grid, denseSmall2, true /* serial */); - - // iterate over the Bigger - for (Coord ijk(bboxSmall.min()); ijk[0] <= bboxSmall.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxSmall.min()[1]; ijk[1] <= bboxSmall.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxSmall.min()[2]; ijk[2] <= bboxSmall.max()[2]; ++ijk[2]) { - - const float& expected = denseSmall.getValue(ijk); - const float& value = denseSmall2.getValue(ijk); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, value, 0.0001); - } - } - } - } - // Convert to Dense in large bbox - { - DenseT denseBig2(bboxBig); - - tools::copyToDense(*grid, denseBig2, false /* serial */); - // iterate over the Bigger - for (Coord ijk(bboxBig.min()); ijk[0] <= bboxBig.max()[0]; ++ijk[0]) { - for (ijk[1] = bboxBig.min()[1]; ijk[1] <= bboxBig.max()[1]; ++ijk[1]) { - for (ijk[2] = bboxBig.min()[2]; ijk[2] <= bboxBig.max()[2]; ++ijk[2]) { - - float expected = -1.f; // should never be this - if (bboxSmall.isInside(ijk)) { - expected = denseSmall.getValue(ijk); - } else if (bboxBig.isInside(ijk)) { - expected = denseBig.getValue(ijk); - } - const float& value = denseBig2.getValue(ijk); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, value, 0.0001); - } - } - } - } -} -#undef BENCHMARK_TEST - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestDenseSparseTools.cc b/openvdb_3_0_0_library/unittest/TestDenseSparseTools.cc deleted file mode 100755 index 999038b..0000000 --- a/openvdb_3_0_0_library/unittest/TestDenseSparseTools.cc +++ /dev/null @@ -1,411 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include "util.h" - -class TestDenseSparseTools: public CppUnit::TestCase -{ -public: - virtual void setUp(); - virtual void tearDown() { if (mDense) delete mDense;} - - CPPUNIT_TEST_SUITE(TestDenseSparseTools); - CPPUNIT_TEST(testExtractSparseFloatTree); - CPPUNIT_TEST(testExtractSparseBoolTree); - CPPUNIT_TEST(testExtractSparseAltDenseLayout); - CPPUNIT_TEST(testExtractSparseMaskedTree); - CPPUNIT_TEST(testDenseTransform); - CPPUNIT_TEST(testOver); - CPPUNIT_TEST_SUITE_END(); - - void testExtractSparseFloatTree(); - void testExtractSparseBoolTree(); - void testExtractSparseAltDenseLayout(); - void testExtractSparseMaskedTree(); - void testDenseTransform(); - void testOver(); - -private: - openvdb::tools::Dense* mDense; - openvdb::math::Coord mijk; -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestDenseSparseTools); - - -void -TestDenseSparseTools::setUp() -{ - namespace vdbmath = openvdb::math; - - // Domain for the dense grid - - vdbmath::CoordBBox domain(vdbmath::Coord(-100, -16, 12), - vdbmath::Coord( 90, 103, 100)); - - // Create dense grid, filled with 0.f - - mDense = new openvdb::tools::Dense(domain, 0.f); - - // Insert non-zero values - - mijk[0] = 1; mijk[1] = -2; mijk[2] = 14; -} - - -namespace { - - // Simple Rule for extracting data greater than a determined mMaskValue - // and producing a tree that holds type ValueType - namespace vdbmath = openvdb::math; - - class FloatRule - { - public: - // Standard tree type (e.g. BoolTree or FloatTree in openvdb.h) - typedef openvdb::FloatTree ResultTreeType; - typedef ResultTreeType::LeafNodeType ResultLeafNodeType; - - typedef float ResultValueType; - typedef float DenseValueType; - - FloatRule(const DenseValueType& value): mMaskValue(value){} - - template - void operator()(const DenseValueType& a, const IndexOrCoord& offset, - ResultLeafNodeType* leaf) const - { - if (a > mMaskValue) { - leaf->setValueOn(offset, a); - } - } - - private: - const DenseValueType mMaskValue; - }; - - class BoolRule - { - public: - // Standard tree type (e.g. BoolTree or FloatTree in openvdb.h) - typedef openvdb::BoolTree ResultTreeType; - typedef ResultTreeType::LeafNodeType ResultLeafNodeType; - - typedef bool ResultValueType; - typedef float DenseValueType; - - BoolRule(const DenseValueType& value): mMaskValue(value){} - - template - void operator()(const DenseValueType& a, const IndexOrCoord& offset, - ResultLeafNodeType* leaf) const - { - if (a > mMaskValue) { - leaf->setValueOn(offset, true); - } - } - - private: - const DenseValueType mMaskValue; - }; - - - // Square each value - struct SqrOp - { - float operator()(const float& in) const - { return in * in; } - }; -} - - -void -TestDenseSparseTools::testExtractSparseFloatTree() -{ - namespace vdbmath = openvdb::math; - - - FloatRule rule(0.5f); - - const float testvalue = 1.f; - mDense->setValue(mijk, testvalue); - const float background(0.f); - openvdb::FloatTree::Ptr result - = openvdb::tools::extractSparseTree(*mDense, rule, background); - - // The result should have only one active value. - - CPPUNIT_ASSERT(result->activeVoxelCount() == 1); - - // The result should have only one leaf - - CPPUNIT_ASSERT(result->leafCount() == 1); - - // The background - - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, result->background(), 1.e-6); - - // The stored value - - CPPUNIT_ASSERT_DOUBLES_EQUAL(testvalue, result->getValue(mijk), 1.e-6); -} - - -void -TestDenseSparseTools::testExtractSparseBoolTree() -{ - - const float testvalue = 1.f; - mDense->setValue(mijk, testvalue); - - const float cutoff(0.5); - - openvdb::BoolTree::Ptr result - = openvdb::tools::extractSparseTree(*mDense, BoolRule(cutoff), false); - - // The result should have only one active value. - - CPPUNIT_ASSERT(result->activeVoxelCount() == 1); - - // The result should have only one leaf - - CPPUNIT_ASSERT(result->leafCount() == 1); - - // The background - - CPPUNIT_ASSERT(result->background() == false); - - // The stored value - - CPPUNIT_ASSERT(result->getValue(mijk) == true); -} - - -void -TestDenseSparseTools::testExtractSparseAltDenseLayout() -{ - namespace vdbmath = openvdb::math; - - FloatRule rule(0.5f); - // Create a dense grid with the alternate data layout - // but the same domain as mDense - openvdb::tools::Dense dense(mDense->bbox(), 0.f); - - const float testvalue = 1.f; - dense.setValue(mijk, testvalue); - - const float background(0.f); - openvdb::FloatTree::Ptr result = openvdb::tools::extractSparseTree(dense, rule, background); - - // The result should have only one active value. - - CPPUNIT_ASSERT(result->activeVoxelCount() == 1); - - // The result should have only one leaf - - CPPUNIT_ASSERT(result->leafCount() == 1); - - // The background - - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, result->background(), 1.e-6); - - // The stored value - - CPPUNIT_ASSERT_DOUBLES_EQUAL(testvalue, result->getValue(mijk), 1.e-6); -} - - -void -TestDenseSparseTools::testExtractSparseMaskedTree() -{ - namespace vdbmath = openvdb::math; - - const float testvalue = 1.f; - mDense->setValue(mijk, testvalue); - - // Create a mask with two values. One in the domain of - // interest and one outside. The intersection of the active - // state topology of the mask and the domain of interest will define - // the topology of the extracted result. - - openvdb::FloatTree mask(0.f); - - // turn on a point inside the bouding domain of the dense grid - mask.setValue(mijk, 5.f); - - // turn on a point outside the bounding domain of the dense grid - vdbmath::Coord outsidePoint = mDense->bbox().min() - vdbmath::Coord(3, 3, 3); - mask.setValue(outsidePoint, 1.f); - - float background = 10.f; - - openvdb::FloatTree::Ptr result - = openvdb::tools::extractSparseTreeWithMask(*mDense, mask, background); - - // The result should have only one active value. - - CPPUNIT_ASSERT(result->activeVoxelCount() == 1); - - // The result should have only one leaf - - CPPUNIT_ASSERT(result->leafCount() == 1); - - // The background - - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, result->background(), 1.e-6); - - // The stored value - - CPPUNIT_ASSERT_DOUBLES_EQUAL(testvalue, result->getValue(mijk), 1.e-6); -} - - -void -TestDenseSparseTools::testDenseTransform() -{ - - namespace vdbmath = openvdb::math; - - vdbmath::CoordBBox domain(vdbmath::Coord(-4, -6, 10), - vdbmath::Coord( 1, 2, 15)); - - // Create dense grid, filled with value - const float value(2.f); const float valueSqr(value*value); - - openvdb::tools::Dense dense(domain, 0.f); - dense.fill(value); - - SqrOp op; - - vdbmath::CoordBBox smallBBox(vdbmath::Coord(-5, -5, 11), - vdbmath::Coord( 0, 1, 13) ); - - // Apply the transformation - openvdb::tools::transformDense(dense, smallBBox, op, true); - - vdbmath::Coord ijk; - // Test results. - for (ijk[0] = domain.min().x(); ijk[0] < domain.max().x() + 1; ++ijk[0]) { - for (ijk[1] = domain.min().y(); ijk[1] < domain.max().y() + 1; ++ijk[1]) { - for (ijk[2] = domain.min().z(); ijk[2] < domain.max().z() + 1; ++ijk[2]) { - - if (smallBBox.isInside(ijk)) { - // the functor was applied here - // the value should be base * base - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(ijk), valueSqr, 1.e-6); - } else { - // the original value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(ijk), value, 1.e-6); - } - } - } - } -} - - -void -TestDenseSparseTools::testOver() -{ - namespace vdbmath = openvdb::math; - - const vdbmath::CoordBBox domain(vdbmath::Coord(-10, 0, 5), vdbmath::Coord( 10, 5, 10)); - const openvdb::Coord ijk = domain.min() + openvdb::Coord(1, 1, 1); - // Create dense grid, filled with value - const float value(2.f); - const float strength(1.f); - const float beta(1.f); - - openvdb::FloatTree src(0.f); - src.setValue(ijk, 1.f); - openvdb::FloatTree alpha(0.f); - alpha.setValue(ijk, 1.f); - - - const float expected = openvdb::tools::ds::OpOver::apply( - value, alpha.getValue(ijk), src.getValue(ijk), strength, beta, 1.f); - - { // testing composite function - openvdb::tools::Dense dense(domain, 0.f); - dense.fill(value); - - openvdb::tools::compositeToDense( - dense, src, alpha, beta, strength, true /*threaded*/); - - // Check for over value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(ijk), expected, 1.e-6); - // Check for original value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(openvdb::Coord(1,1,1) + ijk), value, 1.e-6); - } - - { // testing sparse explict sparse composite - openvdb::tools::Dense dense(domain, 0.f); - dense.fill(value); - - typedef openvdb::tools::ds::CompositeFunctorTranslator - CompositeTool; - typedef CompositeTool::OpT Method; - openvdb::tools::SparseToDenseCompositor - sparseToDense(dense, src, alpha, beta, strength); - - sparseToDense.sparseComposite(true); - // Check for over value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(ijk), expected, 1.e-6); - // Check for original value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(openvdb::Coord(1,1,1) + ijk), value, 1.e-6); - } - - { // testing sparse explict dense composite - openvdb::tools::Dense dense(domain, 0.f); - dense.fill(value); - - typedef openvdb::tools::ds::CompositeFunctorTranslator - CompositeTool; - typedef CompositeTool::OpT Method; - openvdb::tools::SparseToDenseCompositor - sparseToDense(dense, src, alpha, beta, strength); - - sparseToDense.denseComposite(true); - // Check for over value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(ijk), expected, 1.e-6); - // Check for original value - CPPUNIT_ASSERT_DOUBLES_EQUAL(dense.getValue(openvdb::Coord(1,1,1) + ijk), value, 1.e-6); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestDiagnostics.cc b/openvdb_3_0_0_library/unittest/TestDiagnostics.cc deleted file mode 100755 index 85b10a5..0000000 --- a/openvdb_3_0_0_library/unittest/TestDiagnostics.cc +++ /dev/null @@ -1,340 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class TestDiagnostics: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestDiagnostics); - CPPUNIT_TEST(testCheck); - CPPUNIT_TEST(testDiagnose); - CPPUNIT_TEST(testUniqueInactiveValues); - CPPUNIT_TEST_SUITE_END(); - - void testCheck(); - void testDiagnose(); - void testUniqueInactiveValues(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestDiagnostics); - - -//////////////////////////////////////// - -void -TestDiagnostics::testCheck() -{ - const float val = 1.0f; - const float nan = std::numeric_limits::quiet_NaN(); - const float inf1= std::numeric_limits::infinity(); - const openvdb::math::Vec3 inf2(val, inf1, val); - - {//test CheckNan - openvdb::tools::CheckNan c; - CPPUNIT_ASSERT(!c(val)); - CPPUNIT_ASSERT( c(nan)); - CPPUNIT_ASSERT( c(nan)); - CPPUNIT_ASSERT(!c(inf1)); - CPPUNIT_ASSERT(!c(inf2)); - } - {//test CheckInf - openvdb::tools::CheckInf c; - CPPUNIT_ASSERT(!c(val)); - CPPUNIT_ASSERT(!c(nan)); - CPPUNIT_ASSERT(!c(nan)); - CPPUNIT_ASSERT( c(inf1)); - CPPUNIT_ASSERT( c(inf2)); - } - {//test CheckFinite - openvdb::tools::CheckFinite c; - CPPUNIT_ASSERT(!c(val)); - CPPUNIT_ASSERT( c(nan)); - CPPUNIT_ASSERT( c(nan)); - CPPUNIT_ASSERT( c(inf1)); - CPPUNIT_ASSERT( c(inf2)); - } - {//test CheckMin - openvdb::tools::CheckMin c(0.0f); - CPPUNIT_ASSERT(!c( 0.5f)); - CPPUNIT_ASSERT(!c( 0.0f)); - CPPUNIT_ASSERT(!c( 1.0f)); - CPPUNIT_ASSERT(!c( 1.1f)); - CPPUNIT_ASSERT( c(-0.1f)); - } - {//test CheckMax - openvdb::tools::CheckMax c(0.0f); - CPPUNIT_ASSERT( c( 0.5f)); - CPPUNIT_ASSERT(!c( 0.0f)); - CPPUNIT_ASSERT( c( 1.0f)); - CPPUNIT_ASSERT( c( 1.1f)); - CPPUNIT_ASSERT(!c(-0.1f)); - } - {//test CheckRange - openvdb::tools::CheckRange c(0.0f, 1.0f); - CPPUNIT_ASSERT(!c(0.5f)); - CPPUNIT_ASSERT(!c(0.0f)); - CPPUNIT_ASSERT(!c(1.0f)); - CPPUNIT_ASSERT( c(1.1f)); - CPPUNIT_ASSERT(c(-0.1f)); - } -}//testCheck - -void -TestDiagnostics::testDiagnose() -{ - using namespace openvdb; - const float val = 1.0f; - const float nan = std::numeric_limits::quiet_NaN(); - const float inf = std::numeric_limits::infinity(); - - {//empty grid - FloatGrid grid; - tools::Diagnose d(grid); - tools::CheckNan c; - std::string str = d.check(c); - //std::cerr << "Empty grid:\n" << str; - CPPUNIT_ASSERT_EQUAL(std::string(), str); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {//non-empty grid - FloatGrid grid; - grid.tree().setValue(Coord(-1,3,6), val); - tools::Diagnose d(grid); - tools::CheckNan c; - std::string str = d.check(c); - //std::cerr << "Non-Empty grid:\n" << str; - CPPUNIT_ASSERT_EQUAL(std::string(), str); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {//nan grid - FloatGrid grid; - grid.tree().setValue(Coord(-1,3,6), nan); - tools::Diagnose d(grid); - tools::CheckNan c; - std::string str = d.check(c); - //std::cerr << "NaN grid:\n" << str; - CPPUNIT_ASSERT(!str.empty()); - CPPUNIT_ASSERT_EQUAL(1, int(d.failureCount())); - } - - {//nan and infinite grid - FloatGrid grid; - grid.tree().setValue(Coord(-1,3,6), nan); - grid.tree().setValue(Coord(10,30,60), inf); - tools::Diagnose d(grid); - tools::CheckFinite c; - std::string str = d.check(c); - //std::cerr << "Not Finite grid:\n" << str; - CPPUNIT_ASSERT(!str.empty()); - CPPUNIT_ASSERT_EQUAL(2, int(d.failureCount())); - } - {//out-of-range grid - FloatGrid grid(10.0f); - grid.tree().setValue(Coord(-1,3,6), 1.0f); - grid.tree().setValue(Coord(10,30,60), 1.5); - grid.tree().fill(math::CoordBBox::createCube(math::Coord(0),8), 20.0f, true); - tools::Diagnose d(grid); - tools::CheckRange c(0.0f, 1.0f); - std::string str = d.check(c); - //std::cerr << "out-of-range grid:\n" << str; - CPPUNIT_ASSERT(!str.empty()); - CPPUNIT_ASSERT_EQUAL(3, int(d.failureCount())); - } - - const float radius = 4.3f; - const openvdb::Vec3f center(15.8f, 13.2f, 16.7f); - const float voxelSize = 0.1f, width = 2.0f, gamma=voxelSize*width; - - FloatGrid::Ptr gridSphere = - tools::createLevelSetSphere(radius, center, voxelSize, width); - - //gridSphere->print(std::cerr, 2); - - {// Check min/max of active values - math::Extrema ex = tools::extrema(gridSphere->cbeginValueOn()); - //std::cerr << "Min = " << ex.min() << " max = " << ex.max() << std::endl; - CPPUNIT_ASSERT(ex.min() > -voxelSize*width); - CPPUNIT_ASSERT(ex.max() < voxelSize*width); - - } - {// Check min/max of all values - math::Extrema ex = tools::extrema(gridSphere->cbeginValueAll()); - //std::cerr << "Min = " << ex.min() << " max = " << ex.max() << std::endl; - CPPUNIT_ASSERT(ex.min() >= -voxelSize*width); - CPPUNIT_ASSERT(ex.max() <= voxelSize*width); - - } - {// check range of all values in a sphere w/o mask - tools::CheckRange c(-gamma, gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "Values out of range:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check range of on values in a sphere w/o mask - tools::CheckRange c(-gamma, gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "Values out of range:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check range of off tiles in a sphere w/o mask - tools::CheckRange c(-gamma, gamma); - tools::Diagnose d(*gridSphere); - {// check off tile iterator - FloatGrid::ValueOffCIter i(gridSphere->tree()); - i.setMaxDepth(FloatGrid::ValueOffCIter::LEAF_DEPTH - 1); - for (; i; ++i) CPPUNIT_ASSERT( math::Abs(*i) <= gamma); - } - std::string str = d.check(c); - //std::cerr << "Values out of range:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check range of sphere w/o mask - tools::CheckRange c(0.0f, gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "Values out of range:\n" << str; - CPPUNIT_ASSERT(!str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT(d.failureCount() < gridSphere->activeVoxelCount()); - } - {// check range of sphere w mask - tools::CheckRange c(0.0f, gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c, true); - //std::cerr << "Values out of range:\n" << str; - CPPUNIT_ASSERT(!str.empty()); - CPPUNIT_ASSERT_EQUAL(d.valueCount(), d.valueCount()); - CPPUNIT_ASSERT(d.failureCount() < gridSphere->activeVoxelCount()); - } - {// check min of sphere w/o mask - tools::CheckMin c(-gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "Min values:\n" << str; - CPPUNIT_ASSERT_EQUAL(std::string(), str); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check max of sphere w/o mask - tools::CheckMax c(gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "MAX values:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check norm of gradient of sphere w/o mask - tools::CheckNormGrad c(*gridSphere, 0.75f, 1.25f); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c, false, true, false, false); - //std::cerr << "NormGrad:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } - {// check inactive values - tools::CheckMagnitude c(gamma); - tools::Diagnose d(*gridSphere); - std::string str = d.check(c); - //std::cerr << "Magnitude:\n" << str; - CPPUNIT_ASSERT(str.empty()); - CPPUNIT_ASSERT_EQUAL(0, int(d.valueCount())); - CPPUNIT_ASSERT_EQUAL(0, int(d.failureCount())); - } -} - -void -TestDiagnostics::testUniqueInactiveValues() -{ - openvdb::FloatGrid grid; - - grid.tree().setValueOff(openvdb::Coord(0,0,0), -1); - grid.tree().setValueOff(openvdb::Coord(0,0,1), -2); - grid.tree().setValueOff(openvdb::Coord(0,1,0), -3); - grid.tree().setValue(openvdb::Coord(1,0,0), 1); - - std::vector values; - - CPPUNIT_ASSERT(openvdb::tools::uniqueInactiveValues(grid, values, 4)); - - CPPUNIT_ASSERT_EQUAL(4, int(values.size())); - - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[0], -3.0f)); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[1], -2.0f)); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[2], -1.0f)); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[3], 0.0f)); - - - // test with level set sphere - const float radius = 4.3f; - const openvdb::Vec3f center(15.8f, 13.2f, 16.7f); - const float voxelSize = 0.5f, width = 2.0f; - - openvdb::FloatGrid::Ptr gridSphere = - openvdb::tools::createLevelSetSphere(radius, center, voxelSize, width); - - CPPUNIT_ASSERT(openvdb::tools::uniqueInactiveValues(*gridSphere.get(), values, 2)); - - CPPUNIT_ASSERT_EQUAL(2, int(values.size())); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[0], -voxelSize * width)); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[1], voxelSize * width)); - - // test with fog volume - openvdb::tools::sdfToFogVolume(*gridSphere); - - CPPUNIT_ASSERT(openvdb::tools::uniqueInactiveValues(*gridSphere.get(), values, 1)); - - CPPUNIT_ASSERT_EQUAL(1, int(values.size())); - CPPUNIT_ASSERT(openvdb::math::isApproxEqual(values[0], 0.0f)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestDivergence.cc b/openvdb_3_0_0_library/unittest/TestDivergence.cc deleted file mode 100755 index e5d60c2..0000000 --- a/openvdb_3_0_0_library/unittest/TestDivergence.cc +++ /dev/null @@ -1,710 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -namespace { -const int GRID_DIM = 10; -} - - -class TestDivergence: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestDivergence); - CPPUNIT_TEST(testISDivergence); // Divergence in Index Space - CPPUNIT_TEST(testISDivergenceStencil); - CPPUNIT_TEST(testWSDivergence); // Divergence in World Space - CPPUNIT_TEST(testWSDivergenceStencil); - CPPUNIT_TEST(testDivergenceTool); // Divergence tool - CPPUNIT_TEST(testDivergenceMaskedTool); // Divergence tool - CPPUNIT_TEST(testStaggeredDivergence); - CPPUNIT_TEST_SUITE_END(); - - void testISDivergence(); - void testISDivergenceStencil(); - void testWSDivergence(); - void testWSDivergenceStencil(); - void testDivergenceTool(); - void testDivergenceMaskedTool(); - void testStaggeredDivergence(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestDivergence); - - -void -TestDivergence::testDivergenceTool() -{ - using namespace openvdb; - - VectorGrid::Ptr inGrid = VectorGrid::create(); - VectorTree& inTree = inGrid->tree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; xactiveVoxelCount())); - - FloatGrid::ConstAccessor accessor = divGrid->getConstAccessor(); - --dim;//ignore boundary divergence - for (int x = -dim; xtree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; xfill(maskBBox, true /*value*/, true /*activate*/); - - FloatGrid::Ptr divGrid = tools::divergence(*inGrid, *maskGrid); - CPPUNIT_ASSERT_EQUAL(math::Pow3(dim), int(divGrid->activeVoxelCount())); - - FloatGrid::ConstAccessor accessor = divGrid->getConstAccessor(); - --dim;//ignore boundary divergence - for (int x = -dim; xsetGridClass( GRID_STAGGERED ); - VectorTree& inTree = inGrid->tree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; xactiveVoxelCount())); - - FloatGrid::ConstAccessor accessor = divGrid->getConstAccessor(); - --dim;//ignore boundary divergence - for (int x = -dim; xtree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; xgetConstAccessor(); - CPPUNIT_ASSERT(!inTree.empty()); - CPPUNIT_ASSERT_EQUAL(math::Pow3(2*dim), int(inTree.activeVoxelCount())); - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - } - } - } - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(inAccessor, xyz); - - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - d = math::ISDivergence::result(inAccessor, xyz); - - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - d = math::ISDivergence::result(inAccessor, xyz); - - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - } - } - } - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(inAccessor, xyz); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2, d, /*tolerance=*/0.00001); - - d = math::ISDivergence::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2, d, /*tolerance=*/0.00001); - } - } - } -} - - -void -TestDivergence::testISDivergenceStencil() -{ - using namespace openvdb; - - VectorGrid::Ptr inGrid = VectorGrid::create(); - VectorTree& inTree = inGrid->tree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; x sevenpt(*inGrid); - math::ThirteenPointStencil thirteenpt(*inGrid); - math::NineteenPointStencil nineteenpt(*inGrid); - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(sevenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - } - } - } - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(thirteenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(thirteenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(thirteenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - } - } - } - - --dim;//ignore boundary divergence - // test index space divergence - for (int x = -dim; x::result(nineteenpt); - ASSERT_DOUBLES_EXACTLY_EQUAL(2, d); - - d = math::ISDivergence::result(nineteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2, d, /*tolerance=*/0.00001); - - d = math::ISDivergence::result(nineteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2, d, /*tolerance=*/0.00001); - } - } - } -} - - -void -TestDivergence::testWSDivergence() -{ - using namespace openvdb; - - typedef VectorGrid::ConstAccessor Accessor; - - { // non-unit voxel size - double voxel_size = 0.5; - VectorGrid::Ptr inGrid = VectorGrid::create(); - inGrid->setTransform(math::Transform::createLinearTransform(voxel_size)); - - VectorTree& inTree = inGrid->tree(); - CPPUNIT_ASSERT(inTree.empty()); - - int dim = GRID_DIM; - for (int x = -dim; xindexToWorld(Vec3d(x,y,z)); - inTree.setValue(Coord(x,y,z), - VectorTree::ValueType(float(location.x()), float(location.y()), 0.f)); - } - } - } - - Accessor inAccessor = inGrid->getConstAccessor(); - CPPUNIT_ASSERT(!inTree.empty()); - CPPUNIT_ASSERT_EQUAL(math::Pow3(2*dim), int(inTree.activeVoxelCount())); - - --dim;//ignore boundary divergence - - // test with a map - // test with a map - math::AffineMap map(voxel_size*math::Mat3d::identity()); - math::UniformScaleMap uniform_map(voxel_size); - math::UniformScaleTranslateMap uniform_translate_map(voxel_size, Vec3d(0,0,0)); - - for (int x = -dim; x -#include -#include - -class TestDoubleMetadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestDoubleMetadata); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestDoubleMetadata); - -void -TestDoubleMetadata::test() -{ - using namespace openvdb; - - Metadata::Ptr m(new DoubleMetadata(1.23)); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("double") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("double") == 0); - - DoubleMetadata *s = dynamic_cast(m.get()); - //CPPUNIT_ASSERT(s->value() == 1.23); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.23,s->value(),0); - s->value() = 4.56; - //CPPUNIT_ASSERT(s->value() == 4.56); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.56,s->value(),0); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - //CPPUNIT_ASSERT(s->value() == 4.56); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.56,s->value(),0); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestExceptions.cc b/openvdb_3_0_0_library/unittest/TestExceptions.cc deleted file mode 100755 index 7911200..0000000 --- a/openvdb_3_0_0_library/unittest/TestExceptions.cc +++ /dev/null @@ -1,111 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include - - -class TestExceptions : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestExceptions); - CPPUNIT_TEST(testArithmeticError); - CPPUNIT_TEST(testIndexError); - CPPUNIT_TEST(testIoError); - CPPUNIT_TEST(testKeyError); - CPPUNIT_TEST(testLookupError); - CPPUNIT_TEST(testNotImplementedError); - CPPUNIT_TEST(testReferenceError); - CPPUNIT_TEST(testRuntimeError); - CPPUNIT_TEST(testTypeError); - CPPUNIT_TEST(testValueError); - CPPUNIT_TEST_SUITE_END(); - - void testArithmeticError() { testException(); } - void testIndexError() { testException(); } - void testIoError() { testException(); } - void testKeyError() { testException(); } - void testLookupError() { testException(); } - void testNotImplementedError() { testException(); } - void testReferenceError() { testException(); } - void testRuntimeError() { testException(); } - void testTypeError() { testException(); } - void testValueError() { testException(); } - -private: - template void testException(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestExceptions); - - -template struct ExceptionTraits -{ static std::string name() { return ""; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "ArithmeticError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "IndexError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "IoError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "KeyError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "LookupError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "NotImplementedError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "ReferenceError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "RuntimeError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "TypeError"; } }; -template<> struct ExceptionTraits -{ static std::string name() { return "ValueError"; } }; - - -template -void -TestExceptions::testException() -{ - std::string ErrorMsg("Error message"); - - CPPUNIT_ASSERT_THROW(OPENVDB_THROW(ExceptionT, ErrorMsg), ExceptionT); - - try { - OPENVDB_THROW(ExceptionT, ErrorMsg); - } catch (openvdb::Exception& e) { - const std::string expectedMsg = ExceptionTraits::name() + ": " + ErrorMsg; - CPPUNIT_ASSERT_EQUAL(expectedMsg, std::string(e.what())); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestFile.cc b/openvdb_3_0_0_library/unittest/TestFile.cc deleted file mode 100755 index d234c9f..0000000 --- a/openvdb_3_0_0_library/unittest/TestFile.cc +++ /dev/null @@ -1,2468 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include // for tbb::this_tbb_thread::sleep() -#include -#include -#include -#include -#include -#include -#include // for tools::sdfToFogVolume() -#include -#include -#include "util.h" // for unittest_util::makeSphere() -#include // for remove() and rename() -#include -#include -#include -#include -#include -#include // for stat() -#include -#ifndef _WIN32 -#include -#endif -#ifdef OPENVDB_USE_BLOSC -#include -#include // for memset() -#endif - - -class TestFile: public CppUnit::TestCase -{ -public: - virtual void setUp() {} - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestFile); - CPPUNIT_TEST(testHeader); - CPPUNIT_TEST(testWriteGrid); - CPPUNIT_TEST(testWriteMultipleGrids); - CPPUNIT_TEST(testWriteFloatAsHalf); - CPPUNIT_TEST(testWriteInstancedGrids); - CPPUNIT_TEST(testReadGridDescriptors); - CPPUNIT_TEST(testGridNaming); - CPPUNIT_TEST(testEmptyFile); - CPPUNIT_TEST(testEmptyGridIO); - CPPUNIT_TEST(testOpen); - CPPUNIT_TEST(testNonVdbOpen); - CPPUNIT_TEST(testGetMetadata); - CPPUNIT_TEST(testReadAll); - CPPUNIT_TEST(testWriteOpenFile); - CPPUNIT_TEST(testReadGridMetadata); - CPPUNIT_TEST(testReadGridPartial); - CPPUNIT_TEST(testReadGrid); -#ifndef OPENVDB_2_ABI_COMPATIBLE - CPPUNIT_TEST(testReadClippedGrid); -#endif - CPPUNIT_TEST(testMultipleBufferIO); - CPPUNIT_TEST(testHasGrid); - CPPUNIT_TEST(testNameIterator); - CPPUNIT_TEST(testReadOldFileFormat); - CPPUNIT_TEST(testCompression); - CPPUNIT_TEST(testAsync); -#ifdef OPENVDB_USE_BLOSC - CPPUNIT_TEST(testBlosc); -#endif - CPPUNIT_TEST_SUITE_END(); - - void testHeader(); - void testWriteGrid(); - void testWriteMultipleGrids(); - void testWriteFloatAsHalf(); - void testWriteInstancedGrids(); - void testReadGridDescriptors(); - void testGridNaming(); - void testEmptyFile(); - void testEmptyGridIO(); - void testOpen(); - void testNonVdbOpen(); - void testGetMetadata(); - void testReadAll(); - void testWriteOpenFile(); - void testReadGridMetadata(); - void testReadGridPartial(); - void testReadGrid(); -#ifndef OPENVDB_2_ABI_COMPATIBLE - void testReadClippedGrid(); -#endif - void testMultipleBufferIO(); - void testHasGrid(); - void testNameIterator(); - void testReadOldFileFormat(); - void testCompression(); - void testAsync(); -#ifdef OPENVDB_USE_BLOSC - void testBlosc(); -#endif -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFile); - - -//////////////////////////////////////// - - -void -TestFile::testHeader() -{ - using namespace openvdb::io; - - File file("something.vdb2"); - - std::ostringstream ostr(std::ios_base::binary); - - file.writeHeader(ostr, /*seekable=*/true); - - std::string uuid_str=file.getUniqueTag(); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - bool unique=true; - CPPUNIT_ASSERT_NO_THROW(unique=file.readHeader(istr)); - - CPPUNIT_ASSERT(!unique);//reading same file again - - CPPUNIT_ASSERT_EQUAL(openvdb::OPENVDB_FILE_VERSION, file.fileVersion()); - CPPUNIT_ASSERT_EQUAL(openvdb::OPENVDB_LIBRARY_MAJOR_VERSION, file.libraryVersion().first); - CPPUNIT_ASSERT_EQUAL(openvdb::OPENVDB_LIBRARY_MINOR_VERSION, file.libraryVersion().second); - CPPUNIT_ASSERT_EQUAL(uuid_str, file.getUniqueTag()); - - //std::cerr << "\nuuid=" << uuid_str << std::endl; - - CPPUNIT_ASSERT(file.isIdentical(uuid_str)); - - remove("something.vdb2"); -} - - -void -TestFile::testWriteGrid() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Tree TreeType; - typedef Grid GridType; - - File file("something.vdb2"); - - std::ostringstream ostr(std::ios_base::binary); - - // Create a grid with transform. - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - - GridType::Ptr grid = createGrid(/*bg=*/1); - TreeType& tree = grid->tree(); - grid->setTransform(trans); - tree.setValue(Coord(10, 1, 2), 10); - tree.setValue(Coord(0, 0, 0), 5); - - // Add some metadata. - Metadata::clearRegistry(); - StringMetadata::registerType(); - const std::string meta0Val, meta1Val("Hello, world."); - Metadata::Ptr stringMetadata = Metadata::createMetadata(typeNameAsString()); - CPPUNIT_ASSERT(stringMetadata); - if (stringMetadata) { - grid->insertMeta("meta0", *stringMetadata); - grid->metaValue("meta0") = meta0Val; - grid->insertMeta("meta1", *stringMetadata); - grid->metaValue("meta1") = meta1Val; - } - - // Create the grid descriptor out of this grid. - GridDescriptor gd(Name("temperature"), grid->type()); - - // Write out the grid. - file.writeGrid(gd, grid, ostr, /*seekable=*/true); - - CPPUNIT_ASSERT(gd.getGridPos() != 0); - CPPUNIT_ASSERT(gd.getBlockPos() != 0); - CPPUNIT_ASSERT(gd.getEndPos() != 0); - - // Read in the grid descriptor. - GridDescriptor gd2; - std::istringstream istr(ostr.str(), std::ios_base::binary); - - // Since the input is only a fragment of a VDB file (in particular, - // it doesn't have a header), set the file format version number explicitly. - io::setCurrentVersion(istr); - - GridBase::Ptr gd2_grid; - CPPUNIT_ASSERT_THROW(gd2.read(istr), openvdb::LookupError); - - // Register the grid and the transform and the blocks. - GridBase::clearRegistry(); - GridType::registerGrid(); - - // Register transform maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - istr.seekg(0, std::ios_base::beg); - CPPUNIT_ASSERT_NO_THROW(gd2_grid = gd2.read(istr)); - - CPPUNIT_ASSERT_EQUAL(gd.gridName(), gd2.gridName()); - CPPUNIT_ASSERT_EQUAL(GridType::gridType(), gd2_grid->type()); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), gd2.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), gd2.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), gd2.getEndPos()); - - // Position the stream to beginning of the grid storage and read the grid. - gd2.seekToGrid(istr); - Archive::readGridCompression(istr); - gd2_grid->readMeta(istr); - gd2_grid->readTransform(istr); - gd2_grid->readTopology(istr); - - // Ensure that we have the same metadata. - CPPUNIT_ASSERT_EQUAL(grid->metaCount(), gd2_grid->metaCount()); - CPPUNIT_ASSERT((*gd2_grid)["meta0"]); - CPPUNIT_ASSERT((*gd2_grid)["meta1"]); - CPPUNIT_ASSERT_EQUAL(meta0Val, gd2_grid->metaValue("meta0")); - CPPUNIT_ASSERT_EQUAL(meta1Val, gd2_grid->metaValue("meta1")); - - // Ensure that we have the same topology and transform. - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().leafCount(), gd2_grid->baseTree().leafCount()); - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().nonLeafCount(), gd2_grid->baseTree().nonLeafCount()); - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().treeDepth(), gd2_grid->baseTree().treeDepth()); - - //CPPUNIT_ASSERT_EQUAL(0.1, gd2_grid->getTransform()->getVoxelSizeX()); - //CPPUNIT_ASSERT_EQUAL(0.1, gd2_grid->getTransform()->getVoxelSizeY()); - //CPPUNIT_ASSERT_EQUAL(0.1, gd2_grid->getTransform()->getVoxelSizeZ()); - - // Read in the data blocks. - gd2.seekToBlocks(istr); - gd2_grid->readBuffers(istr); - TreeType::Ptr tree2 = boost::dynamic_pointer_cast(gd2_grid->baseTreePtr()); - CPPUNIT_ASSERT(tree2.get() != NULL); - CPPUNIT_ASSERT_EQUAL(10, tree2->getValue(Coord(10, 1, 2))); - CPPUNIT_ASSERT_EQUAL(5, tree2->getValue(Coord(0, 0, 0))); - - CPPUNIT_ASSERT_EQUAL(1, tree2->getValue(Coord(1000, 1000, 16000))); - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - remove("something.vdb2"); -} - - -void -TestFile::testWriteMultipleGrids() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Tree TreeType; - typedef Grid GridType; - - File file("something.vdb2"); - - std::ostringstream ostr(std::ios_base::binary); - - // Create a grid with transform. - GridType::Ptr grid = createGrid(/*bg=*/1); - TreeType& tree = grid->tree(); - tree.setValue(Coord(10, 1, 2), 10); - tree.setValue(Coord(0, 0, 0), 5); - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - - GridType::Ptr grid2 = createGrid(/*bg=*/2); - TreeType& tree2 = grid2->tree(); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(1000, 1000, 1000), 50); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.2); - grid2->setTransform(trans2); - - // Create the grid descriptor out of this grid. - GridDescriptor gd(Name("temperature"), grid->type()); - GridDescriptor gd2(Name("density"), grid2->type()); - - // Write out the grids. - file.writeGrid(gd, grid, ostr, /*seekable=*/true); - file.writeGrid(gd2, grid2, ostr, /*seekable=*/true); - - CPPUNIT_ASSERT(gd.getGridPos() != 0); - CPPUNIT_ASSERT(gd.getBlockPos() != 0); - CPPUNIT_ASSERT(gd.getEndPos() != 0); - - CPPUNIT_ASSERT(gd2.getGridPos() != 0); - CPPUNIT_ASSERT(gd2.getBlockPos() != 0); - CPPUNIT_ASSERT(gd2.getEndPos() != 0); - - // register the grid - GridBase::clearRegistry(); - GridType::registerGrid(); - - // register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Read in the first grid descriptor. - GridDescriptor gd_in; - std::istringstream istr(ostr.str(), std::ios_base::binary); - io::setCurrentVersion(istr); - - GridBase::Ptr gd_in_grid; - CPPUNIT_ASSERT_NO_THROW(gd_in_grid = gd_in.read(istr)); - - // Ensure read in the right values. - CPPUNIT_ASSERT_EQUAL(gd.gridName(), gd_in.gridName()); - CPPUNIT_ASSERT_EQUAL(GridType::gridType(), gd_in_grid->type()); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), gd_in.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), gd_in.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), gd_in.getEndPos()); - - // Position the stream to beginning of the grid storage and read the grid. - gd_in.seekToGrid(istr); - Archive::readGridCompression(istr); - gd_in_grid->readMeta(istr); - gd_in_grid->readTransform(istr); - gd_in_grid->readTopology(istr); - - // Ensure that we have the same topology and transform. - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().leafCount(), gd_in_grid->baseTree().leafCount()); - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().nonLeafCount(), gd_in_grid->baseTree().nonLeafCount()); - CPPUNIT_ASSERT_EQUAL( - grid->baseTree().treeDepth(), gd_in_grid->baseTree().treeDepth()); - - // CPPUNIT_ASSERT_EQUAL(0.1, gd_in_grid->getTransform()->getVoxelSizeX()); - // CPPUNIT_ASSERT_EQUAL(0.1, gd_in_grid->getTransform()->getVoxelSizeY()); - // CPPUNIT_ASSERT_EQUAL(0.1, gd_in_grid->getTransform()->getVoxelSizeZ()); - - // Read in the data blocks. - gd_in.seekToBlocks(istr); - gd_in_grid->readBuffers(istr); - TreeType::Ptr grid_in = boost::dynamic_pointer_cast(gd_in_grid->baseTreePtr()); - CPPUNIT_ASSERT(grid_in.get() != NULL); - CPPUNIT_ASSERT_EQUAL(10, grid_in->getValue(Coord(10, 1, 2))); - CPPUNIT_ASSERT_EQUAL(5, grid_in->getValue(Coord(0, 0, 0))); - CPPUNIT_ASSERT_EQUAL(1, grid_in->getValue(Coord(1000, 1000, 16000))); - - ///////////////////////////////////////////////////////////////// - // Now read in the second grid descriptor. Make use of hte end offset. - /////////////////////////////////////////////////////////////// - - gd_in.seekToEnd(istr); - - GridDescriptor gd2_in; - GridBase::Ptr gd2_in_grid; - CPPUNIT_ASSERT_NO_THROW(gd2_in_grid = gd2_in.read(istr)); - - // Ensure that we read in the right values. - CPPUNIT_ASSERT_EQUAL(gd2.gridName(), gd2_in.gridName()); - CPPUNIT_ASSERT_EQUAL(TreeType::treeType(), gd2_in_grid->type()); - CPPUNIT_ASSERT_EQUAL(gd2.getGridPos(), gd2_in.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getBlockPos(), gd2_in.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getEndPos(), gd2_in.getEndPos()); - - // Position the stream to beginning of the grid storage and read the grid. - gd2_in.seekToGrid(istr); - Archive::readGridCompression(istr); - gd2_in_grid->readMeta(istr); - gd2_in_grid->readTransform(istr); - gd2_in_grid->readTopology(istr); - - // Ensure that we have the same topology and transform. - CPPUNIT_ASSERT_EQUAL( - grid2->baseTree().leafCount(), gd2_in_grid->baseTree().leafCount()); - CPPUNIT_ASSERT_EQUAL( - grid2->baseTree().nonLeafCount(), gd2_in_grid->baseTree().nonLeafCount()); - CPPUNIT_ASSERT_EQUAL( - grid2->baseTree().treeDepth(), gd2_in_grid->baseTree().treeDepth()); - // CPPUNIT_ASSERT_EQUAL(0.2, gd2_in_grid->getTransform()->getVoxelSizeX()); - // CPPUNIT_ASSERT_EQUAL(0.2, gd2_in_grid->getTransform()->getVoxelSizeY()); - // CPPUNIT_ASSERT_EQUAL(0.2, gd2_in_grid->getTransform()->getVoxelSizeZ()); - - // Read in the data blocks. - gd2_in.seekToBlocks(istr); - gd2_in_grid->readBuffers(istr); - TreeType::Ptr grid2_in = - boost::dynamic_pointer_cast(gd2_in_grid->baseTreePtr()); - CPPUNIT_ASSERT(grid2_in.get() != NULL); - CPPUNIT_ASSERT_EQUAL(50, grid2_in->getValue(Coord(1000, 1000, 1000))); - CPPUNIT_ASSERT_EQUAL(10, grid2_in->getValue(Coord(0, 0, 0))); - CPPUNIT_ASSERT_EQUAL(2, grid2_in->getValue(Coord(100000, 100000, 16000))); - - // Clear registries. - GridBase::clearRegistry(); - - math::MapRegistry::clear(); - remove("something.vdb2"); -} - - -void -TestFile::testWriteFloatAsHalf() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Vec3STree TreeType; - typedef Grid GridType; - - // Register all grid types. - initialize(); - // Ensure that the registry is cleared on exit. - struct Local { static void uninitialize(char*) { openvdb::uninitialize(); } }; - boost::shared_ptr onExit((char*)(0), Local::uninitialize); - - // Create two test grids. - GridType::Ptr grid1 = createGrid(/*bg=*/Vec3s(1, 1, 1)); - TreeType& tree1 = grid1->tree(); - CPPUNIT_ASSERT(grid1.get() != NULL); - grid1->setTransform(math::Transform::createLinearTransform(0.1)); - grid1->setName("grid1"); - - GridType::Ptr grid2 = createGrid(/*bg=*/Vec3s(2, 2, 2)); - CPPUNIT_ASSERT(grid2.get() != NULL); - TreeType& tree2 = grid2->tree(); - grid2->setTransform(math::Transform::createLinearTransform(0.2)); - // Flag this grid for 16-bit float output. - grid2->setSaveFloatAsHalf(true); - grid2->setName("grid2"); - - for (int x = 0; x < 40; ++x) { - for (int y = 0; y < 40; ++y) { - for (int z = 0; z < 40; ++z) { - tree1.setValue(Coord(x, y, z), Vec3s(float(x), float(y), float(z))); - tree2.setValue(Coord(x, y, z), Vec3s(float(x), float(y), float(z))); - } - } - } - - GridPtrVec grids; - grids.push_back(grid1); - grids.push_back(grid2); - - const char* filename = "something.vdb2"; - { - // Write both grids to a file. - File vdbFile(filename); - vdbFile.write(grids); - } - { - // Verify that both grids can be read back successfully from the file. - File vdbFile(filename); - vdbFile.open(); - GridBase::Ptr - bgrid1 = vdbFile.readGrid("grid1"), - bgrid2 = vdbFile.readGrid("grid2"); - vdbFile.close(); - - CPPUNIT_ASSERT(bgrid1.get() != NULL); - CPPUNIT_ASSERT(bgrid1->isType()); - CPPUNIT_ASSERT(bgrid2.get() != NULL); - CPPUNIT_ASSERT(bgrid2->isType()); - - const TreeType& btree1 = boost::static_pointer_cast(bgrid1)->tree(); - CPPUNIT_ASSERT_EQUAL(Vec3s(10, 10, 10), btree1.getValue(Coord(10, 10, 10))); - const TreeType& btree2 = boost::static_pointer_cast(bgrid2)->tree(); - CPPUNIT_ASSERT_EQUAL(Vec3s(10, 10, 10), btree2.getValue(Coord(10, 10, 10))); - } -} - - -void -TestFile::testWriteInstancedGrids() -{ - using namespace openvdb; - - // Register data types. - openvdb::initialize(); - - // Remove something.vdb2 when done. We must declare this here before the - // other grid smart_ptr's because we re-use them in the test several times. - // We will not be able to remove something.vdb2 on Windows if the pointers - // are still referencing data opened by the "file" variable. - const char* filename = "something.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - // Create grids. - Int32Tree::Ptr tree1(new Int32Tree(1)); - FloatTree::Ptr tree2(new FloatTree(2.0)); - GridBase::Ptr - grid1 = createGrid(tree1), - grid2 = createGrid(tree1), // instance of grid1 - grid3 = createGrid(tree2), - grid4 = createGrid(tree2); // instance of grid3 - grid1->setName("density"); - grid2->setName("density_copy"); - // Leave grid3 and grid4 unnamed. - - // Create transforms. - math::Transform::Ptr trans1 = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid1->setTransform(trans1); - grid2->setTransform(trans2); - grid3->setTransform(trans2); - grid4->setTransform(trans1); - - // Set some values. - tree1->setValue(Coord(0, 0, 0), 5); - tree1->setValue(Coord(100, 0, 0), 6); - tree2->setValue(Coord(0, 0, 0), 10); - tree2->setValue(Coord(0, 100, 0), 11); - - MetaMap::Ptr meta(new MetaMap); - meta->insertMeta("author", StringMetadata("Einstein")); - meta->insertMeta("year", Int32Metadata(2009)); - - GridPtrVecPtr grids(new GridPtrVec); - grids->push_back(grid1); - grids->push_back(grid2); - grids->push_back(grid3); - grids->push_back(grid4); - - // Write the grids to a file and then close the file. - { - io::File vdbFile(filename); - vdbFile.write(*grids, *meta); - } - meta.reset(); - - // Read the grids back in. - io::File file(filename); - file.open(); - grids = file.getGrids(); - meta = file.getMetadata(); - - // Verify the metadata. - CPPUNIT_ASSERT(meta.get() != NULL); - CPPUNIT_ASSERT_EQUAL(2, int(meta->metaCount())); - CPPUNIT_ASSERT_EQUAL(std::string("Einstein"), meta->metaValue("author")); - CPPUNIT_ASSERT_EQUAL(2009, meta->metaValue("year")); - - // Verify the grids. - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT_EQUAL(4, int(grids->size())); - - GridBase::Ptr grid = findGridByName(*grids, "density"); - CPPUNIT_ASSERT(grid.get() != NULL); - Int32Tree::Ptr density = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - - grid.reset(); - grid = findGridByName(*grids, "density_copy"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - // Verify that "density_copy" is an instance of (i.e., shares a tree with) "density". - CPPUNIT_ASSERT_EQUAL(density, gridPtrCast(grid)->treePtr()); - - grid.reset(); - grid = findGridByName(*grids, ""); - CPPUNIT_ASSERT(grid.get() != NULL); - FloatTree::Ptr temperature = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - - grid.reset(); - for (GridPtrVec::reverse_iterator it = grids->rbegin(); !grid && it != grids->rend(); ++it) { - // Search for the second unnamed grid starting from the end of the list. - if ((*it)->getName() == "") grid = *it; - } - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - // Verify that the second unnamed grid is an instance of the first. - CPPUNIT_ASSERT_EQUAL(temperature, gridPtrCast(grid)->treePtr()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(5, density->getValue(Coord(0, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(6, density->getValue(Coord(100, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(10, temperature->getValue(Coord(0, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(11, temperature->getValue(Coord(0, 100, 0)), /*tolerance=*/0); - - // Reread with instancing disabled. - file.close(); - file.setInstancingEnabled(false); - file.open(); - grids = file.getGrids(); - CPPUNIT_ASSERT_EQUAL(4, int(grids->size())); - - grid = findGridByName(*grids, "density"); - CPPUNIT_ASSERT(grid.get() != NULL); - density = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - grid = findGridByName(*grids, "density_copy"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - // Verify that "density_copy" is *not* an instance of "density". - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr() != density); - - // Verify that the two unnamed grids are not instances of each other. - grid = findGridByName(*grids, ""); - CPPUNIT_ASSERT(grid.get() != NULL); - temperature = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - grid.reset(); - for (GridPtrVec::reverse_iterator it = grids->rbegin(); !grid && it != grids->rend(); ++it) { - // Search for the second unnamed grid starting from the end of the list. - if ((*it)->getName() == "") grid = *it; - } - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr() != temperature); - - // Rewrite with instancing disabled, then reread with instancing enabled. - file.close(); - { - /// @todo (FX-7063) For now, write to a new file, then, when there's - /// no longer a need for delayed load from the old file, replace it - /// with the new file. - const char* tempFilename = "somethingelse.vdb"; - boost::shared_ptr scopedTempFile(tempFilename, ::remove); - io::File vdbFile(tempFilename); - vdbFile.setInstancingEnabled(false); - vdbFile.write(*grids, *meta); - grids.reset(); - // Note: Windows requires that the destination not exist, before we can rename to it. - std::remove(filename); - std::rename(tempFilename, filename); - } - file.setInstancingEnabled(true); - file.open(); - grids = file.getGrids(); - CPPUNIT_ASSERT_EQUAL(4, int(grids->size())); - - // Verify that "density_copy" is not an instance of "density". - grid = findGridByName(*grids, "density"); - CPPUNIT_ASSERT(grid.get() != NULL); - density = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - grid = findGridByName(*grids, "density_copy"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr() != density); - - // Verify that the two unnamed grids are not instances of each other. - grid = findGridByName(*grids, ""); - CPPUNIT_ASSERT(grid.get() != NULL); - temperature = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - grid.reset(); - for (GridPtrVec::reverse_iterator it = grids->rbegin(); !grid && it != grids->rend(); ++it) { - // Search for the second unnamed grid starting from the end of the list. - if ((*it)->getName() == "") grid = *it; - } - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr() != temperature); -} - - -void -TestFile::testReadGridDescriptors() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Grid GridType; - typedef GridType::TreeType TreeType; - - File file("something.vdb2"); - - std::ostringstream ostr(std::ios_base::binary); - - // Create a grid with transform. - GridType::Ptr grid = createGrid(1); - TreeType& tree = grid->tree(); - tree.setValue(Coord(10, 1, 2), 10); - tree.setValue(Coord(0, 0, 0), 5); - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - - // Create another grid with transform. - GridType::Ptr grid2 = createGrid(2); - TreeType& tree2 = grid2->tree(); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(1000, 1000, 1000), 50); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.2); - grid2->setTransform(trans2); - - // Create the grid descriptor out of this grid. - GridDescriptor gd(Name("temperature"), grid->type()); - GridDescriptor gd2(Name("density"), grid2->type()); - - // Write out the number of grids. - int32_t gridCount = 2; - ostr.write((char*)&gridCount, sizeof(int32_t)); - // Write out the grids. - file.writeGrid(gd, grid, ostr, /*seekable=*/true); - file.writeGrid(gd2, grid2, ostr, /*seekable=*/true); - - // Register the grid and the transform and the blocks. - GridBase::clearRegistry(); - GridType::registerGrid(); - // register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Read in the grid descriptors. - File file2("something.vdb2"); - std::istringstream istr(ostr.str(), std::ios_base::binary); - io::setCurrentVersion(istr); - file2.readGridDescriptors(istr); - - // Compare with the initial grid descriptors. - File::NameMapCIter it = file2.findDescriptor("temperature"); - CPPUNIT_ASSERT(it != file2.gridDescriptors().end()); - GridDescriptor file2gd = it->second; - CPPUNIT_ASSERT_EQUAL(gd.gridName(), file2gd.gridName()); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), file2gd.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), file2gd.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), file2gd.getEndPos()); - - it = file2.findDescriptor("density"); - CPPUNIT_ASSERT(it != file2.gridDescriptors().end()); - file2gd = it->second; - CPPUNIT_ASSERT_EQUAL(gd2.gridName(), file2gd.gridName()); - CPPUNIT_ASSERT_EQUAL(gd2.getGridPos(), file2gd.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getBlockPos(), file2gd.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getEndPos(), file2gd.getEndPos()); - - // Clear registries. - GridBase::clearRegistry(); - math::MapRegistry::clear(); - - remove("something.vdb2"); -} - - -void -TestFile::testGridNaming() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Tree TreeType; - - // Register data types. - openvdb::initialize(); - - // Create several grids that share a single tree. - TreeType::Ptr tree(new TreeType(1)); - tree->setValue(Coord(10, 1, 2), 10); - tree->setValue(Coord(0, 0, 0), 5); - GridBase::Ptr - grid1 = openvdb::createGrid(tree), - grid2 = openvdb::createGrid(tree), - grid3 = openvdb::createGrid(tree); - - std::vector gridVec; - gridVec.push_back(grid1); - gridVec.push_back(grid2); - gridVec.push_back(grid3); - - // Give all grids the same name, but also some metadata to distinguish them. - for (int n = 0; n <= 2; ++n) { - gridVec[n]->setName("grid"); - gridVec[n]->insertMeta("index", Int32Metadata(n)); - } - - const char* filename = "/tmp/testGridNaming.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - // Test first with grid instancing disabled, then with instancing enabled. - for (int instancing = 0; instancing <= 1; ++instancing) { - { - // Write the grids out to a file. - File file(filename); - file.setInstancingEnabled(instancing); - file.write(gridVec); - } - - // Open the file for reading. - File file(filename); - file.setInstancingEnabled(instancing); - file.open(); - - int n = 0; - for (File::NameIterator i = file.beginName(), e = file.endName(); i != e; ++i, ++n) { - CPPUNIT_ASSERT(file.hasGrid(i.gridName())); - } - // Verify that the file contains three grids. - CPPUNIT_ASSERT_EQUAL(3, n); - - // Read each grid. - for (n = -1; n <= 2; ++n) { - openvdb::Name name("grid"); - - // On the first iteration, read the grid named "grid", then read "grid[0]" - // (which is synonymous with "grid"), then "grid[1]", then "grid[2]". - if (n >= 0) { - name = GridDescriptor::nameAsString(GridDescriptor::addSuffix(name, n)); - } - - CPPUNIT_ASSERT(file.hasGrid(name)); - - // Partially read the current grid. - GridBase::ConstPtr grid = file.readGridPartial(name); - CPPUNIT_ASSERT(grid.get() != NULL); - - // Verify that the grid is named "grid". - CPPUNIT_ASSERT_EQUAL(openvdb::Name("grid"), grid->getName()); - - CPPUNIT_ASSERT_EQUAL((n < 0 ? 0 : n), grid->metaValue("index")); - - // Fully read the current grid. - grid = file.readGrid(name); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(openvdb::Name("grid"), grid->getName()); - CPPUNIT_ASSERT_EQUAL((n < 0 ? 0 : n), grid->metaValue("index")); - } - - // Read all three grids at once. - GridPtrVecPtr allGrids = file.getGrids(); - CPPUNIT_ASSERT(allGrids.get() != NULL); - CPPUNIT_ASSERT_EQUAL(3, int(allGrids->size())); - - GridBase::ConstPtr firstGrid; - std::vector indices; - for (GridPtrVecCIter i = allGrids->begin(), e = allGrids->end(); i != e; ++i) { - GridBase::ConstPtr grid = *i; - CPPUNIT_ASSERT(grid.get() != NULL); - - indices.push_back(grid->metaValue("index")); - - // If instancing is enabled, verify that all grids share the same tree. - if (instancing) { - if (!firstGrid) firstGrid = grid; - CPPUNIT_ASSERT_EQUAL(firstGrid->baseTreePtr(), grid->baseTreePtr()); - } - } - // Verify that three distinct grids were read, - // by examining their "index" metadata. - CPPUNIT_ASSERT_EQUAL(3, int(indices.size())); - std::sort(indices.begin(), indices.end()); - CPPUNIT_ASSERT_EQUAL(0, indices[0]); - CPPUNIT_ASSERT_EQUAL(1, indices[1]); - CPPUNIT_ASSERT_EQUAL(2, indices[2]); - } - - { - // Try writing and then reading a grid with a weird name - // that might conflict with the grid name indexing scheme. - const openvdb::Name weirdName("grid[4]"); - gridVec[0]->setName(weirdName); - { - File file(filename); - file.write(gridVec); - } - File file(filename); - file.open(); - - // Verify that the grid can be read and that its index is 0. - GridBase::ConstPtr grid = file.readGrid(weirdName); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(weirdName, grid->getName()); - CPPUNIT_ASSERT_EQUAL(0, grid->metaValue("index")); - - // Verify that the other grids can still be read successfully. - grid = file.readGrid("grid[0]"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(openvdb::Name("grid"), grid->getName()); - // Because there are now only two grids named "grid", the one with - // index 1 is now "grid[0]". - CPPUNIT_ASSERT_EQUAL(1, grid->metaValue("index")); - - grid = file.readGrid("grid[1]"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(openvdb::Name("grid"), grid->getName()); - // Because there are now only two grids named "grid", the one with - // index 2 is now "grid[1]". - CPPUNIT_ASSERT_EQUAL(2, grid->metaValue("index")); - - // Verify that there is no longer a third grid named "grid". - CPPUNIT_ASSERT_THROW(file.readGrid("grid[2]"), openvdb::KeyError); - } -} - - -void -TestFile::testEmptyFile() -{ - using namespace openvdb; - using namespace openvdb::io; - - const char* filename = "/tmp/testEmptyFile.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - { - File file(filename); - file.write(GridPtrVec(), MetaMap()); - } - File file(filename); - file.open(); - - GridPtrVecPtr grids = file.getGrids(); - MetaMap::Ptr meta = file.getMetadata(); - - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT(grids->empty()); - - CPPUNIT_ASSERT(meta.get() != NULL); - CPPUNIT_ASSERT_EQUAL(0, int(meta->metaCount())); -} - - -void -TestFile::testEmptyGridIO() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Grid GridType; - - const char* filename = "/tmp/something.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - File file(filename); - - std::ostringstream ostr(std::ios_base::binary); - - // Create a grid with transform. - GridType::Ptr grid = createGrid(/*bg=*/1); - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - - // Create another grid with transform. - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.2); - GridType::Ptr grid2 = createGrid(/*bg=*/2); - grid2->setTransform(trans2); - - // Create the grid descriptor out of this grid. - GridDescriptor gd(Name("temperature"), grid->type()); - GridDescriptor gd2(Name("density"), grid2->type()); - - // Write out the number of grids. - int32_t gridCount = 2; - ostr.write((char*)&gridCount, sizeof(int32_t)); - // Write out the grids. - file.writeGrid(gd, grid, ostr, /*seekable=*/true); - file.writeGrid(gd2, grid2, ostr, /*seekable=*/true); - - // Ensure that the block offset and the end offsets are equivalent. - CPPUNIT_ASSERT_EQUAL(0, int(grid->baseTree().leafCount())); - CPPUNIT_ASSERT_EQUAL(0, int(grid2->baseTree().leafCount())); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), gd.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getEndPos(), gd2.getBlockPos()); - - // Register the grid and the transform and the blocks. - GridBase::clearRegistry(); - GridType::registerGrid(); - // register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Read in the grid descriptors. - File file2(filename); - std::istringstream istr(ostr.str(), std::ios_base::binary); - io::setCurrentVersion(istr); - file2.readGridDescriptors(istr); - - // Compare with the initial grid descriptors. - File::NameMapCIter it = file2.findDescriptor("temperature"); - CPPUNIT_ASSERT(it != file2.gridDescriptors().end()); - GridDescriptor file2gd = it->second; - file2gd.seekToGrid(istr); - GridBase::Ptr gd_grid = GridBase::createGrid(file2gd.gridType()); - Archive::readGridCompression(istr); - gd_grid->readMeta(istr); - gd_grid->readTransform(istr); - gd_grid->readTopology(istr); - CPPUNIT_ASSERT_EQUAL(gd.gridName(), file2gd.gridName()); - CPPUNIT_ASSERT(gd_grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(0, int(gd_grid->baseTree().leafCount())); - //CPPUNIT_ASSERT_EQUAL(8, int(gd_grid->baseTree().nonLeafCount())); - CPPUNIT_ASSERT_EQUAL(4, int(gd_grid->baseTree().treeDepth())); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), file2gd.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), file2gd.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), file2gd.getEndPos()); - - it = file2.findDescriptor("density"); - CPPUNIT_ASSERT(it != file2.gridDescriptors().end()); - file2gd = it->second; - file2gd.seekToGrid(istr); - gd_grid = GridBase::createGrid(file2gd.gridType()); - Archive::readGridCompression(istr); - gd_grid->readMeta(istr); - gd_grid->readTransform(istr); - gd_grid->readTopology(istr); - CPPUNIT_ASSERT_EQUAL(gd2.gridName(), file2gd.gridName()); - CPPUNIT_ASSERT(gd_grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(0, int(gd_grid->baseTree().leafCount())); - //CPPUNIT_ASSERT_EQUAL(8, int(gd_grid->nonLeafCount())); - CPPUNIT_ASSERT_EQUAL(4, int(gd_grid->baseTree().treeDepth())); - CPPUNIT_ASSERT_EQUAL(gd2.getGridPos(), file2gd.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getBlockPos(), file2gd.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd2.getEndPos(), file2gd.getEndPos()); - - // Clear registries. - GridBase::clearRegistry(); - math::MapRegistry::clear(); -} - - -void -TestFile::testOpen() -{ - using namespace openvdb; - - typedef openvdb::FloatGrid FloatGrid; - typedef openvdb::Int32Grid IntGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create a VDB to write. - - // Create grids - IntGrid::Ptr grid = createGrid(/*bg=*/1); - IntTree& tree = grid->tree(); - grid->setName("density"); - - FloatGrid::Ptr grid2 = createGrid(/*bg=*/2.0); - FloatTree& tree2 = grid2->tree(); - grid2->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - grid2->setTransform(trans2); - - // Set some values - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(0, 100, 0), 11); - - MetaMap meta; - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - GridPtrVec grids; - grids.push_back(grid); - grids.push_back(grid2); - - CPPUNIT_ASSERT(findGridByName(grids, "density") == grid); - CPPUNIT_ASSERT(findGridByName(grids, "temperature") == grid2); - CPPUNIT_ASSERT(meta.metaValue("author") == "Einstein"); - CPPUNIT_ASSERT_EQUAL(2009, meta.metaValue("year")); - - // Register grid and transform. - GridBase::clearRegistry(); - IntGrid::registerGrid(); - FloatGrid::registerGrid(); - Metadata::clearRegistry(); - StringMetadata::registerType(); - Int32Metadata::registerType(); - // register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - // Now we can read in the file. - CPPUNIT_ASSERT(!vdbfile.open());//opening the same file - // Can't open same file multiple times without closing. - CPPUNIT_ASSERT_THROW(vdbfile.open(), openvdb::IoError); - vdbfile.close(); - CPPUNIT_ASSERT(!vdbfile.open());//opening the same file - - CPPUNIT_ASSERT(vdbfile.isOpen()); - CPPUNIT_ASSERT_EQUAL(OPENVDB_FILE_VERSION, vdbfile.fileVersion()); - CPPUNIT_ASSERT_EQUAL(OPENVDB_FILE_VERSION, io::getFormatVersion(vdbfile.inputStream())); - CPPUNIT_ASSERT_EQUAL(OPENVDB_LIBRARY_MAJOR_VERSION, vdbfile.libraryVersion().first); - CPPUNIT_ASSERT_EQUAL(OPENVDB_LIBRARY_MINOR_VERSION, vdbfile.libraryVersion().second); - CPPUNIT_ASSERT_EQUAL(OPENVDB_LIBRARY_MAJOR_VERSION, - io::getLibraryVersion(vdbfile.inputStream()).first); - CPPUNIT_ASSERT_EQUAL(OPENVDB_LIBRARY_MINOR_VERSION, - io::getLibraryVersion(vdbfile.inputStream()).second); - - // Ensure that we read in the vdb metadata. - CPPUNIT_ASSERT(vdbfile.getMetadata()); - CPPUNIT_ASSERT(vdbfile.getMetadata()->metaValue("author") == "Einstein"); - CPPUNIT_ASSERT_EQUAL(2009, vdbfile.getMetadata()->metaValue("year")); - - // Ensure we got the grid descriptors. - CPPUNIT_ASSERT_EQUAL(1, int(vdbfile.gridDescriptors().count("density"))); - CPPUNIT_ASSERT_EQUAL(1, int(vdbfile.gridDescriptors().count("temperature"))); - - io::File::NameMapCIter it = vdbfile.findDescriptor("density"); - CPPUNIT_ASSERT(it != vdbfile.gridDescriptors().end()); - io::GridDescriptor gd = it->second; - CPPUNIT_ASSERT_EQUAL(IntTree::treeType(), gd.gridType()); - - it = vdbfile.findDescriptor("temperature"); - CPPUNIT_ASSERT(it != vdbfile.gridDescriptors().end()); - gd = it->second; - CPPUNIT_ASSERT_EQUAL(FloatTree::treeType(), gd.gridType()); - - // Ensure we throw an error if there is no file. - io::File vdbfile2("somethingelses.vdb2"); - CPPUNIT_ASSERT_THROW(vdbfile2.open(), openvdb::IoError); - CPPUNIT_ASSERT_THROW(vdbfile2.inputStream(), openvdb::IoError); - - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - // Test closing the file. - vdbfile.close(); - CPPUNIT_ASSERT(vdbfile.isOpen() == false); - CPPUNIT_ASSERT(vdbfile.fileMetadata().get() == NULL); - CPPUNIT_ASSERT_EQUAL(0, int(vdbfile.gridDescriptors().size())); - CPPUNIT_ASSERT_THROW(vdbfile.inputStream(), openvdb::IoError); - - remove("something.vdb2"); -} - - -void -TestFile::testNonVdbOpen() -{ - std::ofstream file("dummy.vdb2", std::ios_base::binary); - - int64_t something = 1; - file.write((char*)&something, sizeof(int64_t)); - - file.close(); - - openvdb::io::File vdbfile("dummy.vdb2"); - CPPUNIT_ASSERT_THROW(vdbfile.open(), openvdb::IoError); - CPPUNIT_ASSERT_THROW(vdbfile.inputStream(), openvdb::IoError); - - remove("dummy.vdb2"); -} - - -void -TestFile::testGetMetadata() -{ - using namespace openvdb; - - GridPtrVec grids; - MetaMap meta; - - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - // Adjust registry before writing. - Metadata::clearRegistry(); - StringMetadata::registerType(); - Int32Metadata::registerType(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - // Check if reading without opening the file - CPPUNIT_ASSERT_THROW(vdbfile.getMetadata(), openvdb::IoError); - - vdbfile.open(); - - MetaMap::Ptr meta2 = vdbfile.getMetadata(); - - CPPUNIT_ASSERT_EQUAL(2, int(meta2->metaCount())); - - CPPUNIT_ASSERT(meta2->metaValue("author") == "Einstein"); - CPPUNIT_ASSERT_EQUAL(2009, meta2->metaValue("year")); - - // Clear registry. - Metadata::clearRegistry(); - - remove("something.vdb2"); -} - - -void -TestFile::testReadAll() -{ - using namespace openvdb; - - typedef openvdb::FloatGrid FloatGrid; - typedef openvdb::Int32Grid IntGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create a vdb to write. - - // Create grids - IntGrid::Ptr grid1 = createGrid(/*bg=*/1); - IntTree& tree = grid1->tree(); - grid1->setName("density"); - - FloatGrid::Ptr grid2 = createGrid(/*bg=*/2.0); - FloatTree& tree2 = grid2->tree(); - grid2->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid1->setTransform(trans); - grid2->setTransform(trans2); - - // Set some values - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(0, 100, 0), 11); - - MetaMap meta; - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - GridPtrVec grids; - grids.push_back(grid1); - grids.push_back(grid2); - - // Register grid and transform. - openvdb::initialize(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - io::File vdbfile2("something.vdb2"); - CPPUNIT_ASSERT_THROW(vdbfile2.getGrids(), openvdb::IoError); - - vdbfile2.open(); - CPPUNIT_ASSERT(vdbfile2.isOpen()); - - GridPtrVecPtr grids2 = vdbfile2.getGrids(); - MetaMap::Ptr meta2 = vdbfile2.getMetadata(); - - // Ensure we have the metadata. - CPPUNIT_ASSERT_EQUAL(2, int(meta2->metaCount())); - CPPUNIT_ASSERT(meta2->metaValue("author") == "Einstein"); - CPPUNIT_ASSERT_EQUAL(2009, meta2->metaValue("year")); - - // Ensure we got the grids. - CPPUNIT_ASSERT_EQUAL(2, int(grids2->size())); - - GridBase::Ptr grid; - grid.reset(); - grid = findGridByName(*grids2, "density"); - CPPUNIT_ASSERT(grid.get() != NULL); - IntTree::Ptr density = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - - grid.reset(); - grid = findGridByName(*grids2, "temperature"); - CPPUNIT_ASSERT(grid.get() != NULL); - FloatTree::Ptr temperature = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(5, density->getValue(Coord(0, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(6, density->getValue(Coord(100, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(10, temperature->getValue(Coord(0, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(11, temperature->getValue(Coord(0, 100, 0)), /*tolerance=*/0); - - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - vdbfile2.close(); - - remove("something.vdb2"); -} - - -void -TestFile::testWriteOpenFile() -{ - using namespace openvdb; - - MetaMap::Ptr meta(new MetaMap); - meta->insertMeta("author", StringMetadata("Einstein")); - meta->insertMeta("year", Int32Metadata(2009)); - - // Register metadata - Metadata::clearRegistry(); - StringMetadata::registerType(); - Int32Metadata::registerType(); - - // Write the metadata out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(GridPtrVec(), *meta); - - io::File vdbfile2("something.vdb2"); - CPPUNIT_ASSERT_THROW(vdbfile2.getGrids(), openvdb::IoError); - - vdbfile2.open(); - CPPUNIT_ASSERT(vdbfile2.isOpen()); - - GridPtrVecPtr grids = vdbfile2.getGrids(); - meta = vdbfile2.getMetadata(); - - // Ensure we have the metadata. - CPPUNIT_ASSERT(meta.get() != NULL); - CPPUNIT_ASSERT_EQUAL(2, int(meta->metaCount())); - CPPUNIT_ASSERT(meta->metaValue("author") == "Einstein"); - CPPUNIT_ASSERT_EQUAL(2009, meta->metaValue("year")); - - // Ensure we got the grids. - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT_EQUAL(0, int(grids->size())); - - // Cannot write an open file. - CPPUNIT_ASSERT_THROW(vdbfile2.write(*grids), openvdb::IoError); - - vdbfile2.close(); - - CPPUNIT_ASSERT_NO_THROW(vdbfile2.write(*grids)); - - // Clear registries. - Metadata::clearRegistry(); - - remove("something.vdb2"); -} - - -void -TestFile::testReadGridMetadata() -{ - using namespace openvdb; - - openvdb::initialize(); - - const char* filename = "/tmp/testReadGridMetadata.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - // Create grids - Int32Grid::Ptr igrid = createGrid(/*bg=*/1); - FloatGrid::Ptr fgrid = createGrid(/*bg=*/2.0); - - // Add metadata. - igrid->setName("igrid"); - igrid->insertMeta("author", StringMetadata("Einstein")); - igrid->insertMeta("year", Int32Metadata(2012)); - - fgrid->setName("fgrid"); - fgrid->insertMeta("author", StringMetadata("Einstein")); - fgrid->insertMeta("year", Int32Metadata(2012)); - - // Add transforms. - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - igrid->setTransform(trans); - fgrid->setTransform(trans); - - // Set some values. - igrid->tree().setValue(Coord(0, 0, 0), 5); - igrid->tree().setValue(Coord(100, 0, 0), 6); - fgrid->tree().setValue(Coord(0, 0, 0), 10); - fgrid->tree().setValue(Coord(0, 100, 0), 11); - - GridPtrVec srcGrids; - srcGrids.push_back(igrid); - srcGrids.push_back(fgrid); - std::map srcGridMap; - srcGridMap[igrid->getName()] = igrid; - srcGridMap[fgrid->getName()] = fgrid; - - enum { OUTPUT_TO_FILE = 0, OUTPUT_TO_STREAM = 1 }; - for (int outputMethod = OUTPUT_TO_FILE; outputMethod <= OUTPUT_TO_STREAM; ++outputMethod) - { - if (outputMethod == OUTPUT_TO_FILE) { - // Write the grids to a file. - io::File vdbfile(filename); - vdbfile.write(srcGrids); - } else { - // Stream the grids to a file (i.e., without file offsets). - std::ofstream ostrm(filename, std::ios_base::binary); - io::Stream(ostrm).write(srcGrids); - } - - // Read just the grid-level metadata from the file. - io::File vdbfile(filename); - - // Verify that reading from an unopened file generates an exception. - CPPUNIT_ASSERT_THROW(vdbfile.readGridMetadata("igrid"), openvdb::IoError); - CPPUNIT_ASSERT_THROW(vdbfile.readGridMetadata("noname"), openvdb::IoError); - CPPUNIT_ASSERT_THROW(vdbfile.readAllGridMetadata(), openvdb::IoError); - - vdbfile.open(); - - CPPUNIT_ASSERT(vdbfile.isOpen()); - - // Verify that reading a nonexistent grid generates an exception. - CPPUNIT_ASSERT_THROW(vdbfile.readGridMetadata("noname"), openvdb::KeyError); - - // Read all grids and store them in a list. - GridPtrVecPtr gridMetadata = vdbfile.readAllGridMetadata(); - CPPUNIT_ASSERT(gridMetadata.get() != NULL); - CPPUNIT_ASSERT_EQUAL(2, int(gridMetadata->size())); - - // Read individual grids and append them to the list. - GridBase::Ptr grid = vdbfile.readGridMetadata("igrid"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(std::string("igrid"), grid->getName()); - gridMetadata->push_back(grid); - - grid = vdbfile.readGridMetadata("fgrid"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(std::string("fgrid"), grid->getName()); - gridMetadata->push_back(grid); - - // Verify that the grids' metadata and transforms match the original grids'. - for (size_t i = 0, N = gridMetadata->size(); i < N; ++i) { - grid = (*gridMetadata)[i]; - - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(grid->getName() == "igrid" || grid->getName() == "fgrid"); - CPPUNIT_ASSERT(grid->baseTreePtr().get() != NULL); - - // Since we didn't read the grid's topology, the tree should be empty. - CPPUNIT_ASSERT_EQUAL(0, int(grid->constBaseTreePtr()->leafCount())); - CPPUNIT_ASSERT_EQUAL(0, int(grid->constBaseTreePtr()->activeVoxelCount())); - - // Retrieve the source grid of the same name. - GridBase::ConstPtr srcGrid = srcGridMap[grid->getName()]; - - // Compare grid types and transforms. - CPPUNIT_ASSERT_EQUAL(srcGrid->type(), grid->type()); - CPPUNIT_ASSERT_EQUAL(srcGrid->transform(), grid->transform()); - - // Compare metadata, ignoring fields that were added when the file was written. - MetaMap::Ptr - statsMetadata = grid->getStatsMetadata(), - otherMetadata = grid->copyMeta(); // shallow copy - CPPUNIT_ASSERT(statsMetadata->metaCount() != 0); - statsMetadata->insertMeta(GridBase::META_FILE_COMPRESSION, StringMetadata("")); - for (MetaMap::ConstMetaIterator it = grid->beginMeta(), end = grid->endMeta(); - it != end; ++it) - { - // Keep all fields that exist in the source grid. - if ((*srcGrid)[it->first]) continue; - // Remove any remaining grid statistics fields. - if ((*statsMetadata)[it->first]) { - otherMetadata->removeMeta(it->first); - } - } - CPPUNIT_ASSERT_EQUAL(srcGrid->str(), otherMetadata->str()); - - const CoordBBox srcBBox = srcGrid->evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT_EQUAL(srcBBox.min().asVec3i(), grid->metaValue("file_bbox_min")); - CPPUNIT_ASSERT_EQUAL(srcBBox.max().asVec3i(), grid->metaValue("file_bbox_max")); - CPPUNIT_ASSERT_EQUAL(srcGrid->activeVoxelCount(), - Index64(grid->metaValue("file_voxel_count"))); - CPPUNIT_ASSERT_EQUAL(srcGrid->memUsage(), - Index64(grid->metaValue("file_mem_bytes"))); - } - } -} - - -void -TestFile::testReadGridPartial() -{ - using namespace openvdb; - - typedef openvdb::FloatGrid FloatGrid; - typedef openvdb::Int32Grid IntGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create grids - IntGrid::Ptr grid = createGrid(/*bg=*/1); - IntTree& tree = grid->tree(); - grid->setName("density"); - - FloatGrid::Ptr grid2 = createGrid(/*bg=*/2.0); - FloatTree& tree2 = grid2->tree(); - grid2->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - grid2->setTransform(trans2); - - // Set some values - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(0, 100, 0), 11); - - MetaMap meta; - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - GridPtrVec grids; - grids.push_back(grid); - grids.push_back(grid2); - - // Register grid and transform. - openvdb::initialize(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - io::File vdbfile2("something.vdb2"); - - CPPUNIT_ASSERT_THROW(vdbfile2.readGridPartial("density"), openvdb::IoError); - - vdbfile2.open(); - - CPPUNIT_ASSERT(vdbfile2.isOpen()); - - CPPUNIT_ASSERT_THROW(vdbfile2.readGridPartial("noname"), openvdb::KeyError); - - GridBase::ConstPtr density = vdbfile2.readGridPartial("density"); - - CPPUNIT_ASSERT(density.get() != NULL); - - IntTree::ConstPtr typedDensity = gridConstPtrCast(density)->treePtr(); - - CPPUNIT_ASSERT(typedDensity.get() != NULL); - - // the following should cause a compiler error. - // typedDensity->setValue(0, 0, 0, 0); - - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - vdbfile2.close(); - - remove("something.vdb2"); -} - - -void -TestFile::testReadGrid() -{ - using namespace openvdb; - - typedef openvdb::FloatGrid FloatGrid; - typedef openvdb::Int32Grid IntGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create a vdb to write. - - // Create grids - IntGrid::Ptr grid = createGrid(/*bg=*/1); - IntTree& tree = grid->tree(); - grid->setName("density"); - - FloatGrid::Ptr grid2 = createGrid(/*bg=*/2.0); - FloatTree& tree2 = grid2->tree(); - grid2->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - grid2->setTransform(trans2); - - // Set some values - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(0, 100, 0), 11); - - MetaMap meta; - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - GridPtrVec grids; - grids.push_back(grid); - grids.push_back(grid2); - - // Register grid and transform. - openvdb::initialize(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - io::File vdbfile2("something.vdb2"); - - CPPUNIT_ASSERT_THROW(vdbfile2.readGridPartial("density"), openvdb::IoError); - - vdbfile2.open(); - - CPPUNIT_ASSERT(vdbfile2.isOpen()); - - CPPUNIT_ASSERT_THROW(vdbfile2.readGridPartial("noname"), openvdb::KeyError); - - // Get Temperature - GridBase::Ptr temperature = vdbfile2.readGrid("temperature"); - - CPPUNIT_ASSERT(temperature.get() != NULL); - - FloatTree::Ptr typedTemperature = gridPtrCast(temperature)->treePtr(); - - CPPUNIT_ASSERT(typedTemperature.get() != NULL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(10, typedTemperature->getValue(Coord(0, 0, 0)), 0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(11, typedTemperature->getValue(Coord(0, 100, 0)), 0); - - // Get Density - GridBase::Ptr density = vdbfile2.readGrid("density"); - - CPPUNIT_ASSERT(density.get() != NULL); - - IntTree::Ptr typedDensity = gridPtrCast(density)->treePtr(); - - CPPUNIT_ASSERT(typedDensity.get() != NULL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(5,typedDensity->getValue(Coord(0, 0, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(6,typedDensity->getValue(Coord(100, 0, 0)), /*tolerance=*/0); - - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - vdbfile2.close(); - - remove("something.vdb2"); -} - - -//////////////////////////////////////// - - -#ifndef OPENVDB_2_ABI_COMPATIBLE - -template -void -validateClippedGrid(const GridT& clipped, const typename GridT::ValueType& fg) -{ - using namespace openvdb; - - typedef typename GridT::ValueType ValueT; - - const CoordBBox bbox = clipped.evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().y()); - CPPUNIT_ASSERT_EQUAL(-6, bbox.min().z()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().y()); - CPPUNIT_ASSERT_EQUAL(6, bbox.max().z()); - CPPUNIT_ASSERT_EQUAL(6 + 6 + 1, int(clipped.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(2, int(clipped.constTree().leafCount())); - - typename GridT::ConstAccessor acc = clipped.getConstAccessor(); - const ValueT bg = clipped.background(); - Coord xyz; - int &x = xyz[0], &y = xyz[1], &z = xyz[2]; - for (x = -10; x <= 10; ++x) { - for (y = -10; y <= 10; ++y) { - for (z = -10; z <= 10; ++z) { - if (x == 4 && y == 4 && z >= -6 && z <= 6) { - CPPUNIT_ASSERT_EQUAL(fg, acc.getValue(Coord(4, 4, z))); - } else { - CPPUNIT_ASSERT_EQUAL(bg, acc.getValue(Coord(x, y, z))); - } - } - } - } -} - - -// See also TestGrid::testClipping() -void -TestFile::testReadClippedGrid() -{ - using namespace openvdb; - - // Register types. - openvdb::initialize(); - - // World-space clipping region - const BBoxd clipBox(Vec3d(4.0, 4.0, -6.0), Vec3d(4.9, 4.9, 6.0)); - - // Create grids of several types and fill a cubic region of each with a foreground value. - - const bool bfg = true; - BoolGrid::Ptr bgrid = BoolGrid::create(/*bg=*/zeroVal()); - bgrid->setName("bgrid"); - bgrid->fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/bfg, /*active=*/true); - - const float ffg = 5.f; - FloatGrid::Ptr fgrid = FloatGrid::create(/*bg=*/zeroVal()); - fgrid->setName("fgrid"); - fgrid->fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/ffg, /*active=*/true); - - const Vec3s vfg(1.f, -2.f, 3.f); - Vec3SGrid::Ptr vgrid = Vec3SGrid::create(/*bg=*/zeroVal()); - vgrid->setName("vgrid"); - vgrid->fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/vfg, /*active=*/true); - - GridPtrVec srcGrids; - srcGrids.push_back(bgrid); - srcGrids.push_back(fgrid); - srcGrids.push_back(vgrid); - - const char* filename = "/tmp/testReadClippedGrid.vdb"; - boost::shared_ptr scopedFile(filename, ::remove); - - enum { OUTPUT_TO_FILE = 0, OUTPUT_TO_STREAM = 1 }; - for (int outputMethod = OUTPUT_TO_FILE; outputMethod <= OUTPUT_TO_STREAM; ++outputMethod) - { - if (outputMethod == OUTPUT_TO_FILE) { - // Write the grids to a file. - io::File vdbfile(filename); - vdbfile.write(srcGrids); - } else { - // Stream the grids to a file (i.e., without file offsets). - std::ofstream ostrm(filename, std::ios_base::binary); - io::Stream(ostrm).write(srcGrids); - } - - // Open the file for reading. - io::File vdbfile(filename); - vdbfile.open(); - - GridBase::Ptr grid; - - // Read and clip each grid. - - CPPUNIT_ASSERT_NO_THROW(grid = vdbfile.readGrid("bgrid", clipBox)); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_NO_THROW(bgrid = gridPtrCast(grid)); - validateClippedGrid(*bgrid, bfg); - - CPPUNIT_ASSERT_NO_THROW(grid = vdbfile.readGrid("fgrid", clipBox)); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_NO_THROW(fgrid = gridPtrCast(grid)); - validateClippedGrid(*fgrid, ffg); - - CPPUNIT_ASSERT_NO_THROW(grid = vdbfile.readGrid("vgrid", clipBox)); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_NO_THROW(vgrid = gridPtrCast(grid)); - validateClippedGrid(*vgrid, vfg); - } -} - -#endif // !defined(OPENVDB_2_ABI_COMPATIBLE) - - -//////////////////////////////////////// - - -void -TestFile::testMultipleBufferIO() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef Int32Grid GridType; - typedef GridType::TreeType TreeType; - - File file("something.vdb2"); - - std::ostringstream ostr(std::ios_base::binary); - - // Create a grid with transform. - GridType::Ptr grid = createGrid(/*bg=*/1); - TreeType& tree = grid->tree(); - grid->setName("temperature"); - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - tree.setValue(Coord(10, 1, 2), 10); - tree.setValue(Coord(0, 0, 0), 5); - - GridPtrVec grids; - grids.push_back(grid); - - // Register grid and transform. - openvdb::initialize(); - - // write the vdb to the file. - file.write(grids); - - // read into a different grid. - File file2("something.vdb2"); - file2.open(); - - GridBase::Ptr temperature = file2.readGrid("temperature"); - - CPPUNIT_ASSERT(temperature.get() != NULL); - - // Clear registries. - GridBase::clearRegistry(); - math::MapRegistry::clear(); - - remove("something.vdb2"); -} - - -void -TestFile::testHasGrid() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef openvdb::FloatGrid FloatGrid; - typedef openvdb::Int32Grid IntGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create a vdb to write. - - // Create grids - IntGrid::Ptr grid = createGrid(/*bg=*/1); - IntTree& tree = grid->tree(); - grid->setName("density"); - - FloatGrid::Ptr grid2 = createGrid(/*bg=*/2.0); - FloatTree& tree2 = grid2->tree(); - grid2->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid->setTransform(trans); - grid2->setTransform(trans2); - - // Set some values - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - tree2.setValue(Coord(0, 0, 0), 10); - tree2.setValue(Coord(0, 100, 0), 11); - - MetaMap meta; - meta.insertMeta("author", StringMetadata("Einstein")); - meta.insertMeta("year", Int32Metadata(2009)); - - GridPtrVec grids; - grids.push_back(grid); - grids.push_back(grid2); - - // Register grid and transform. - GridBase::clearRegistry(); - IntGrid::registerGrid(); - FloatGrid::registerGrid(); - Metadata::clearRegistry(); - StringMetadata::registerType(); - Int32Metadata::registerType(); - // register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::UniformScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - math::UniformScaleTranslateMap::registerMap(); - math::NonlinearFrustumMap::registerMap(); - - // Write the vdb out to a file. - io::File vdbfile("something.vdb2"); - vdbfile.write(grids, meta); - - io::File vdbfile2("something.vdb2"); - - CPPUNIT_ASSERT_THROW(vdbfile2.hasGrid("density"), openvdb::IoError); - - vdbfile2.open(); - - CPPUNIT_ASSERT(vdbfile2.hasGrid("density")); - CPPUNIT_ASSERT(vdbfile2.hasGrid("temperature")); - CPPUNIT_ASSERT(!vdbfile2.hasGrid("Temperature")); - CPPUNIT_ASSERT(!vdbfile2.hasGrid("densitY")); - - // Clear registries. - GridBase::clearRegistry(); - Metadata::clearRegistry(); - math::MapRegistry::clear(); - - vdbfile2.close(); - - remove("something.vdb2"); -} - - -void -TestFile::testNameIterator() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef openvdb::FloatGrid FloatGrid; - typedef FloatGrid::TreeType FloatTree; - typedef Int32Grid::TreeType IntTree; - - // Create trees. - IntTree::Ptr itree(new IntTree(1)); - itree->setValue(Coord(0, 0, 0), 5); - itree->setValue(Coord(100, 0, 0), 6); - FloatTree::Ptr ftree(new FloatTree(2.0)); - ftree->setValue(Coord(0, 0, 0), 10.0); - ftree->setValue(Coord(0, 100, 0), 11.0); - - // Create grids. - GridPtrVec grids; - GridBase::Ptr grid = createGrid(itree); - grid->setName("density"); - grids.push_back(grid); - - grid = createGrid(ftree); - grid->setName("temperature"); - grids.push_back(grid); - - // Create two unnamed grids. - grids.push_back(createGrid(ftree)); - grids.push_back(createGrid(ftree)); - - // Create two grids with the same name. - grid = createGrid(ftree); - grid->setName("level_set"); - grids.push_back(grid); - grid = createGrid(ftree); - grid->setName("level_set"); - grids.push_back(grid); - - // Register types. - openvdb::initialize(); - - const char* filename = "/tmp/testNameIterator.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - // Write the grids out to a file. - { - io::File vdbfile(filename); - vdbfile.write(grids); - } - - io::File vdbfile(filename); - - // Verify that name iteration fails if the file is not open. - CPPUNIT_ASSERT_THROW(vdbfile.beginName(), openvdb::IoError); - - vdbfile.open(); - - // Names should appear in lexicographic order. - Name names[6] = { "[0]", "[1]", "density", "level_set[0]", "level_set[1]", "temperature" }; - int count = 0; - for (io::File::NameIterator iter = vdbfile.beginName(); iter != vdbfile.endName(); ++iter) { - CPPUNIT_ASSERT_EQUAL(names[count], *iter); - CPPUNIT_ASSERT_EQUAL(names[count], iter.gridName()); - ++count; - grid = vdbfile.readGrid(*iter); - CPPUNIT_ASSERT(grid); - } - CPPUNIT_ASSERT_EQUAL(6, count); - - vdbfile.close(); -} - - -void -TestFile::testReadOldFileFormat() -{ - /// @todo Save some old-format (prior to OPENVDB_FILE_VERSION) .vdb2 files - /// to /work/rd/fx_tools/vdb_unittest/TestFile::testReadOldFileFormat/ - /// Verify that the files can still be read correctly. -} - - -void -TestFile::testCompression() -{ - using namespace openvdb; - using namespace openvdb::io; - - typedef openvdb::Int32Grid IntGrid; - - // Register types. - openvdb::initialize(); - - // Create reference grids. - IntGrid::Ptr intGrid = IntGrid::create(/*background=*/0); - intGrid->fill(CoordBBox(Coord(0), Coord(49)), /*value=*/999, /*active=*/true); - intGrid->fill(CoordBBox(Coord(6), Coord(43)), /*value=*/0, /*active=*/false); - intGrid->fill(CoordBBox(Coord(21), Coord(22)), /*value=*/1, /*active=*/false); - intGrid->fill(CoordBBox(Coord(23), Coord(24)), /*value=*/2, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(8, int(IntGrid::TreeType::LeafNodeType::DIM)); - - FloatGrid::Ptr lsGrid = createLevelSet(); - unittest_util::makeSphere(/*dim=*/Coord(100), /*ctr=*/Vec3f(50, 50, 50), /*r=*/20.0, - *lsGrid, unittest_util::SPHERE_SPARSE_NARROW_BAND); - CPPUNIT_ASSERT_EQUAL(int(GRID_LEVEL_SET), int(lsGrid->getGridClass())); - - FloatGrid::Ptr fogGrid = lsGrid->deepCopy(); - tools::sdfToFogVolume(*fogGrid); - CPPUNIT_ASSERT_EQUAL(int(GRID_FOG_VOLUME), int(fogGrid->getGridClass())); - - - GridPtrVec grids; - grids.push_back(intGrid); - grids.push_back(lsGrid); - grids.push_back(fogGrid); - - const char* filename = "/tmp/testCompression.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - - size_t uncompressedSize = 0; - { - // Write the grids out to a file with compression disabled. - io::File vdbfile(filename); - vdbfile.setCompression(io::COMPRESS_NONE); - vdbfile.write(grids); - vdbfile.close(); - - // Get the size of the file in bytes. - struct stat buf; - buf.st_size = 0; - CPPUNIT_ASSERT_EQUAL(0, ::stat(filename, &buf)); - uncompressedSize = buf.st_size; - } - - // Write the grids out with various combinations of compression options - // and verify that they can be read back successfully. - // Currently, only bits 0 and 1 have meaning as compression flags - // (see io/Compression.h), so the valid combinations range from 0x0 to 0x3. - for (uint32_t flags = 0x0; flags <= 0x3; ++flags) { - - if (flags != io::COMPRESS_NONE) { - io::File vdbfile(filename); - vdbfile.setCompression(flags); - vdbfile.write(grids); - vdbfile.close(); - } - if (flags != io::COMPRESS_NONE) { - // Verify that the compressed file is significantly smaller than - // the uncompressed file. - size_t compressedSize = 0; - struct stat buf; - buf.st_size = 0; - CPPUNIT_ASSERT_EQUAL(0, ::stat(filename, &buf)); - compressedSize = buf.st_size; - CPPUNIT_ASSERT(compressedSize < size_t(0.75 * double(uncompressedSize))); - } - { - // Verify that the grids can be read back successfully. - - io::File vdbfile(filename); - vdbfile.open(); - - GridPtrVecPtr inGrids = vdbfile.getGrids(); - CPPUNIT_ASSERT_EQUAL(3, int(inGrids->size())); - - // Verify that the original and input grids are equal. - { - const IntGrid::Ptr grid = gridPtrCast((*inGrids)[0]); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(int(intGrid->getGridClass()), int(grid->getGridClass())); - - CPPUNIT_ASSERT(grid->tree().hasSameTopology(intGrid->tree())); - - CPPUNIT_ASSERT_EQUAL( - intGrid->tree().getValue(Coord(0)), - grid->tree().getValue(Coord(0))); - // Verify that leaf nodes with more than two distinct inactive values - // are handled correctly (FX-7085). - CPPUNIT_ASSERT_EQUAL( - intGrid->tree().getValue(Coord(6)), - grid->tree().getValue(Coord(6))); - CPPUNIT_ASSERT_EQUAL( - intGrid->tree().getValue(Coord(21)), - grid->tree().getValue(Coord(21))); - CPPUNIT_ASSERT_EQUAL( - intGrid->tree().getValue(Coord(23)), - grid->tree().getValue(Coord(23))); - - // Verify that the only active value in this grid is 999. - Int32 minVal = -1, maxVal = -1; - grid->evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(999, minVal); - CPPUNIT_ASSERT_EQUAL(999, maxVal); - } - for (int idx = 1; idx <= 2; ++idx) { - const FloatGrid::Ptr - grid = gridPtrCast((*inGrids)[idx]), - refGrid = gridPtrCast(grids[idx]); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(int(refGrid->getGridClass()), int(grid->getGridClass())); - - CPPUNIT_ASSERT(grid->tree().hasSameTopology(refGrid->tree())); - - FloatGrid::ConstAccessor refAcc = refGrid->getConstAccessor(); - for (FloatGrid::ValueAllCIter it = grid->cbeginValueAll(); it; ++it) { - CPPUNIT_ASSERT_EQUAL(refAcc.getValue(it.getCoord()), *it); - } - } - } - } -} - - -//////////////////////////////////////// - - -namespace { - -using namespace openvdb; - -struct TestAsyncHelper -{ - std::set ids; - std::map filenames; - size_t refFileSize; - bool verbose; - - TestAsyncHelper(size_t _refFileSize): refFileSize(_refFileSize), verbose(false) {} - - ~TestAsyncHelper() - { - // Remove output files. - for (std::map::iterator it = filenames.begin(); - it != filenames.end(); ++it) - { - ::remove(it->second.c_str()); - } - filenames.clear(); - ids.clear(); - } - - io::Queue::Notifier notifier() - { - return boost::bind(&TestAsyncHelper::validate, this, _1, _2); - } - - void insert(io::Queue::Id id, const std::string& filename) - { - ids.insert(id); - filenames[id] = filename; - if (verbose) std::cerr << "queued " << filename << " as task " << id << "\n"; - } - - void validate(io::Queue::Id id, io::Queue::Status status) - { - if (verbose) { - std::ostringstream ostr; - ostr << "task " << id; - switch (status) { - case io::Queue::UNKNOWN: ostr << " is unknown"; break; - case io::Queue::PENDING: ostr << " is pending"; break; - case io::Queue::SUCCEEDED: ostr << " succeeded"; break; - case io::Queue::FAILED: ostr << " failed"; break; - } - std::cerr << ostr.str() << "\n"; - } - - if (status == io::Queue::SUCCEEDED) { - // If the task completed successfully, verify that the output file's - // size matches the reference file's size. - struct stat buf; - buf.st_size = 0; - CPPUNIT_ASSERT_EQUAL(0, ::stat(filenames[id].c_str(), &buf)); - CPPUNIT_ASSERT_EQUAL(Index64(refFileSize), Index64(buf.st_size)); - } - - if (status == io::Queue::SUCCEEDED || status == io::Queue::FAILED) { - ids.erase(id); - } - } -}; // struct TestAsyncHelper - -} // unnamed namespace - - -void -TestFile::testAsync() -{ - using namespace openvdb; - - // Register types. - openvdb::initialize(); - - // Create a grid. - FloatGrid::Ptr lsGrid = createLevelSet(); - unittest_util::makeSphere(/*dim=*/Coord(100), /*ctr=*/Vec3f(50, 50, 50), /*r=*/20.0, - *lsGrid, unittest_util::SPHERE_SPARSE_NARROW_BAND); - - MetaMap fileMetadata; - fileMetadata.insertMeta("author", StringMetadata("Einstein")); - fileMetadata.insertMeta("year", Int32Metadata(2013)); - - GridPtrVec grids; - grids.push_back(lsGrid); - grids.push_back(lsGrid->deepCopy()); - grids.push_back(lsGrid->deepCopy()); - - size_t refFileSize = 0; - { - // Write a reference file without using asynchronous I/O. - const char* filename = "/tmp/testAsyncref.vdb"; - boost::shared_ptr scopedFile(filename, ::remove); - io::File f(filename); - f.write(grids, fileMetadata); - - // Record the size of the reference file. - struct stat buf; - buf.st_size = 0; - CPPUNIT_ASSERT_EQUAL(0, ::stat(filename, &buf)); - refFileSize = buf.st_size; - } - - { - // Output multiple files using asynchronous I/O. - // Use polling to get the status of the I/O tasks. - - TestAsyncHelper helper(refFileSize); - - io::Queue queue; - for (int i = 1; i < 10; ++i) { - std::ostringstream ostr; - ostr << "/tmp/testAsync." << i << ".vdb"; - const std::string filename = ostr.str(); - io::Queue::Id id = queue.write(grids, io::File(filename), fileMetadata); - helper.insert(id, filename); - } - - tbb::tick_count start = tbb::tick_count::now(); - while (!helper.ids.empty()) { - if ((tbb::tick_count::now() - start).seconds() > 60) break; // time out after 1 minute - - // Wait one second for tasks to complete. - tbb::this_tbb_thread::sleep(tbb::tick_count::interval_t(1.0/*sec*/)); - - // Poll each task in the pending map. - std::set ids = helper.ids; // iterate over a copy - for (std::set::iterator it = ids.begin(); it != ids.end(); ++it) { - const io::Queue::Id id = *it; - const io::Queue::Status status = queue.status(id); - helper.validate(id, status); - } - } - CPPUNIT_ASSERT(helper.ids.empty()); - CPPUNIT_ASSERT(queue.empty()); - } - { - // Output multiple files using asynchronous I/O. - // Use notifications to get the status of the I/O tasks. - - TestAsyncHelper helper(refFileSize); - - io::Queue queue(/*capacity=*/2); - queue.addNotifier(helper.notifier()); - - for (int i = 1; i < 10; ++i) { - std::ostringstream ostr; - ostr << "/tmp/testAsync" << i << ".vdb"; - const std::string filename = ostr.str(); - io::Queue::Id id = queue.write(grids, io::File(filename), fileMetadata); - helper.insert(id, filename); - } - while (!queue.empty()) { - tbb::this_tbb_thread::sleep(tbb::tick_count::interval_t(1.0/*sec*/)); - } - } - { - // Test queue timeout. - - io::Queue queue(/*capacity=*/1); - queue.setTimeout(0/*sec*/); - - boost::shared_ptr - scopedFile1("/tmp/testAsyncIOa.vdb", ::remove), - scopedFile2("/tmp/testAsyncIOb.vdb", ::remove); - std::ofstream - file1(scopedFile1.get()), - file2(scopedFile2.get()); - - queue.write(grids, io::Stream(file1)); - - // With the queue length restricted to 1 and the timeout to 0 seconds, - // the next write() call should time out immediately with an exception. - // (It is possible, though highly unlikely, for the previous task to complete - // in time for this write() to actually succeed.) - CPPUNIT_ASSERT_THROW(queue.write(grids, io::Stream(file2)), openvdb::RuntimeError); - } -} - - -#ifdef OPENVDB_USE_BLOSC -// This tests for a data corruption bug that existed in versions of Blosc prior to 1.5.0 -// (see https://github.com/Blosc/c-blosc/pull/63). -void -TestFile::testBlosc() -{ - openvdb::initialize(); - - const unsigned char rawdata[] = { - 0x93, 0xb0, 0x49, 0xaf, 0x62, 0xad, 0xe3, 0xaa, 0xe4, 0xa5, 0x43, 0x20, 0x24, - 0x29, 0xc9, 0xaf, 0xee, 0xad, 0x0b, 0xac, 0x3d, 0xa8, 0x1f, 0x99, 0x53, 0x27, - 0xb6, 0x2b, 0x16, 0xb0, 0x5f, 0xae, 0x89, 0xac, 0x51, 0xa9, 0xfc, 0xa1, 0xc9, - 0x24, 0x59, 0x2a, 0x2f, 0x2d, 0xb4, 0xae, 0xeb, 0xac, 0x2f, 0xaa, 0xec, 0xa4, - 0x53, 0x21, 0x31, 0x29, 0x8f, 0x2c, 0x8e, 0x2e, 0x31, 0xad, 0xd6, 0xaa, 0x6d, - 0xa6, 0xad, 0x1b, 0x3e, 0x28, 0x0a, 0x2c, 0xfd, 0x2d, 0xf8, 0x2f, 0x45, 0xab, - 0x81, 0xa7, 0x1f, 0x95, 0x02, 0x27, 0x3d, 0x2b, 0x85, 0x2d, 0x75, 0x2f, 0xb6, - 0x30, 0x13, 0xa8, 0xb2, 0x9c, 0xf3, 0x25, 0x9c, 0x2a, 0x28, 0x2d, 0x0b, 0x2f, - 0x7b, 0x30, 0x68, 0x9e, 0x51, 0x25, 0x31, 0x2a, 0xe6, 0x2c, 0xbc, 0x2e, 0x4e, - 0x30, 0x5a, 0xb0, 0xe6, 0xae, 0x0e, 0xad, 0x59, 0xaa, 0x08, 0xa5, 0x89, 0x21, - 0x59, 0x29, 0xb0, 0x2c, 0x57, 0xaf, 0x8c, 0xad, 0x6f, 0xab, 0x65, 0xa7, 0xd3, - 0x12, 0xf5, 0x27, 0xeb, 0x2b, 0xf6, 0x2d, 0xee, 0xad, 0x27, 0xac, 0xab, 0xa8, - 0xb1, 0x9f, 0xa2, 0x25, 0xaa, 0x2a, 0x4a, 0x2d, 0x47, 0x2f, 0x7b, 0xac, 0x6d, - 0xa9, 0x45, 0xa3, 0x73, 0x23, 0x9d, 0x29, 0xb7, 0x2c, 0xa8, 0x2e, 0x51, 0x30, - 0xf7, 0xa9, 0xec, 0xa4, 0x79, 0x20, 0xc5, 0x28, 0x3f, 0x2c, 0x24, 0x2e, 0x09, - 0x30, 0xc8, 0xa5, 0xb1, 0x1c, 0x23, 0x28, 0xc3, 0x2b, 0xba, 0x2d, 0x9c, 0x2f, - 0xc3, 0x30, 0x44, 0x18, 0x6e, 0x27, 0x3d, 0x2b, 0x6b, 0x2d, 0x40, 0x2f, 0x8f, - 0x30, 0x02, 0x27, 0xed, 0x2a, 0x36, 0x2d, 0xfe, 0x2e, 0x68, 0x30, 0x66, 0xae, - 0x9e, 0xac, 0x96, 0xa9, 0x7c, 0xa3, 0xa9, 0x23, 0xc5, 0x29, 0xd8, 0x2c, 0xd7, - 0x2e, 0x0e, 0xad, 0x90, 0xaa, 0xe4, 0xa5, 0xf8, 0x1d, 0x82, 0x28, 0x2b, 0x2c, - 0x1e, 0x2e, 0x0c, 0x30, 0x53, 0xab, 0x9c, 0xa7, 0xd4, 0x96, 0xe7, 0x26, 0x30, - 0x2b, 0x7f, 0x2d, 0x6e, 0x2f, 0xb3, 0x30, 0x74, 0xa8, 0xb1, 0x9f, 0x36, 0x25, - 0x3e, 0x2a, 0xfa, 0x2c, 0xdd, 0x2e, 0x65, 0x30, 0xfc, 0xa1, 0xe0, 0x23, 0x82, - 0x29, 0x8f, 0x2c, 0x66, 0x2e, 0x23, 0x30, 0x2d, 0x22, 0xfb, 0x28, 0x3f, 0x2c, - 0x0a, 0x2e, 0xde, 0x2f, 0xaa, 0x28, 0x0a, 0x2c, 0xc8, 0x2d, 0x8f, 0x2f, 0xb0, - 0x30, 0xde, 0x2b, 0xa0, 0x2d, 0x5a, 0x2f, 0x8f, 0x30, 0x12, 0xac, 0x9d, 0xa8, - 0x0f, 0xa0, 0x51, 0x25, 0x66, 0x2a, 0x1b, 0x2d, 0x0b, 0x2f, 0x82, 0x30, 0x7b, - 0xa9, 0xea, 0xa3, 0x63, 0x22, 0x3f, 0x29, 0x7b, 0x2c, 0x60, 0x2e, 0x26, 0x30, - 0x76, 0xa5, 0xf8, 0x1d, 0x4c, 0x28, 0xeb, 0x2b, 0xce, 0x2d, 0xb0, 0x2f, 0xd3, - 0x12, 0x1d, 0x27, 0x15, 0x2b, 0x57, 0x2d, 0x2c, 0x2f, 0x85, 0x30, 0x0e, 0x26, - 0x74, 0x2a, 0xfa, 0x2c, 0xc3, 0x2e, 0x4a, 0x30, 0x08, 0x2a, 0xb7, 0x2c, 0x74, - 0x2e, 0x1d, 0x30, 0x8f, 0x2c, 0x3f, 0x2e, 0xf8, 0x2f, 0x24, 0x2e, 0xd0, 0x2f, - 0xc3, 0x30, 0xdb, 0xa6, 0xd3, 0x0e, 0x38, 0x27, 0x3d, 0x2b, 0x78, 0x2d, 0x5a, - 0x2f, 0xa3, 0x30, 0x68, 0x9e, 0x51, 0x25, 0x31, 0x2a, 0xe6, 0x2c, 0xbc, 0x2e, - 0x4e, 0x30, 0xa9, 0x23, 0x59, 0x29, 0x6e, 0x2c, 0x38, 0x2e, 0x06, 0x30, 0xb8, - 0x28, 0x10, 0x2c, 0xce, 0x2d, 0x95, 0x2f, 0xb3, 0x30, 0x9b, 0x2b, 0x7f, 0x2d, - 0x39, 0x2f, 0x7f, 0x30, 0x4a, 0x2d, 0xf8, 0x2e, 0x58, 0x30, 0xd0, 0x2e, 0x3d, - 0x30, 0x30, 0x30, 0x53, 0x21, 0xc5, 0x28, 0x24, 0x2c, 0xef, 0x2d, 0xc3, 0x2f, - 0xda, 0x27, 0x58, 0x2b, 0x6b, 0x2d, 0x33, 0x2f, 0x82, 0x30, 0x9c, 0x2a, 0x00, - 0x2d, 0xbc, 0x2e, 0x41, 0x30, 0xb0, 0x2c, 0x60, 0x2e, 0x0c, 0x30, 0x1e, 0x2e, - 0xca, 0x2f, 0xc0, 0x30, 0x95, 0x2f, 0x9f, 0x30, 0x8c, 0x30, 0x23, 0x2a, 0xc4, - 0x2c, 0x81, 0x2e, 0x23, 0x30, 0x5a, 0x2c, 0x0a, 0x2e, 0xc3, 0x2f, 0xc3, 0x30, - 0xad, 0x2d, 0x5a, 0x2f, 0x88, 0x30, 0x0b, 0x2f, 0x5b, 0x30, 0x3a, 0x30, 0x7f, - 0x2d, 0x2c, 0x2f, 0x72, 0x30, 0xc3, 0x2e, 0x37, 0x30, 0x09, 0x30, 0xb6, 0x30 - }; - - const char* indata = reinterpret_cast(rawdata); - size_t inbytes = sizeof(rawdata); - - const int - compbufbytes = int(inbytes + BLOSC_MAX_OVERHEAD), - decompbufbytes = int(inbytes + BLOSC_MAX_OVERHEAD); - - boost::scoped_array - compresseddata(new char[compbufbytes]), - outdata(new char[decompbufbytes]); - - for (int compcode = 0; compcode <= BLOSC_ZLIB; ++compcode) { - char* compname = NULL; - if (0 > blosc_compcode_to_compname(compcode, &compname)) continue; - /// @todo This changes the compressor setting globally. - if (blosc_set_compressor(compname) < 0) continue; - - for (int typesize = 1; typesize <= 4; ++typesize) { - - // Compress the data. - ::memset(compresseddata.get(), 0, compbufbytes); - int compressedbytes = blosc_compress( - /*clevel=*/9, - /*doshuffle=*/true, - typesize, - /*srcsize=*/inbytes, - /*src=*/indata, - /*dest=*/compresseddata.get(), - /*destsize=*/compbufbytes); - - CPPUNIT_ASSERT(compressedbytes > 0); - - // Decompress the data. - ::memset(outdata.get(), 0, decompbufbytes); - int outbytes = blosc_decompress( - compresseddata.get(), outdata.get(), decompbufbytes); - - CPPUNIT_ASSERT(outbytes > 0); - CPPUNIT_ASSERT_EQUAL(int(inbytes), outbytes); - - // Compare original and decompressed data. - int diff = 0; - for (size_t i = 0; i < inbytes; ++i) { - if (outdata[i] != indata[i]) ++diff; - } - if (diff > 0) { - const char* mesg = "Your version of the Blosc library is most likely" - " out of date; please install the latest version. " - "(Earlier versions have a bug that can cause data corruption.)"; - CPPUNIT_ASSERT_MESSAGE(mesg, diff == 0); - return; - } - } - } -} -#endif - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestFloatMetadata.cc b/openvdb_3_0_0_library/unittest/TestFloatMetadata.cc deleted file mode 100755 index 262bb7e..0000000 --- a/openvdb_3_0_0_library/unittest/TestFloatMetadata.cc +++ /dev/null @@ -1,77 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - - -class TestFloatMetadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestFloatMetadata); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFloatMetadata); - -void -TestFloatMetadata::test() -{ - using namespace openvdb; - - Metadata::Ptr m(new FloatMetadata(1.0)); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("float") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("float") == 0); - - FloatMetadata *s = dynamic_cast(m.get()); - //CPPUNIT_ASSERT(s->value() == 1.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0f,s->value(),0); - s->value() = 2.0; - //CPPUNIT_ASSERT(s->value() == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0f,s->value(),0); - m2->copy(*s); - - s = dynamic_cast(m2.get()); - //CPPUNIT_ASSERT(s->value() == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0f,s->value(),0); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGradient.cc b/openvdb_3_0_0_library/unittest/TestGradient.cc deleted file mode 100755 index 3b6643c..0000000 --- a/openvdb_3_0_0_library/unittest/TestGradient.cc +++ /dev/null @@ -1,820 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestGradient: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestGradient); - CPPUNIT_TEST(testISGradient); // Gradient in Index Space - CPPUNIT_TEST(testISGradientStencil); - CPPUNIT_TEST(testWSGradient); // Gradient in World Space - CPPUNIT_TEST(testWSGradientStencil); - CPPUNIT_TEST(testWSGradientStencilFrustum); - CPPUNIT_TEST(testWSGradientNormSqr); // Gradient Norm Sqr (world space only) - CPPUNIT_TEST(testWSGradientNormSqrStencil); // Gradient Norm Sqr (world space only) - CPPUNIT_TEST(testGradientTool); // Gradient tool - CPPUNIT_TEST(testGradientMaskedTool); // Gradient tool - CPPUNIT_TEST(testIntersectsIsoValue); // zero-crossing - CPPUNIT_TEST(testOldStyleStencils); // old stencil impl - deprecate - - CPPUNIT_TEST_SUITE_END(); - - void testISGradient(); - void testISGradientStencil(); - void testWSGradient(); - void testWSGradientStencilFrustum(); - void testWSGradientStencil(); - void testWSGradientNormSqr(); - void testWSGradientNormSqrStencil(); - void testGradientTool(); - void testGradientMaskedTool(); - void testIntersectsIsoValue(); - void testOldStyleStencils(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGradient); - - -void -TestGradient::testISGradient() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius=10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - const Coord xyz(10, 20, 30); - - - // Index Space Gradients: random access and stencil version - AccessorType inAccessor = grid->getConstAccessor(); - Vec3f result; - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.02); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.02); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); -} - - -void -TestGradient::testISGradientStencil() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - const Coord xyz(10, 20, 30); - - - // Index Space Gradients: stencil version - Vec3f result; - // this stencil is large enough for all thie different schemes used - // in this test - math::NineteenPointStencil stencil(*grid); - stencil.moveTo(xyz); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.02); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.02); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::ISGradient::result(stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); -} - - -void -TestGradient::testWSGradient() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - const Coord xyz(11, 17, 26); - - AccessorType inAccessor = grid->getConstAccessor(); - // try with a map - - // Index Space Gradients: stencil version - Vec3f result; - math::MapBase::Ptr rotated_map; - { - math::UniformScaleMap map(voxel_size); - result = math::Gradient::result( - map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - rotated_map = map.preRotate(1.5, math::X_AXIS); - // verify the new map is an affine map - CPPUNIT_ASSERT(rotated_map->type() == math::AffineMap::mapType()); - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - // the gradient should have the same length even after rotation - result = math::Gradient::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - result = math::Gradient::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - math::UniformScaleTranslateMap map(voxel_size, Vec3d(0,0,0)); - result = math::Gradient::result( - map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - math::ScaleTranslateMap map(Vec3d(voxel_size, voxel_size, voxel_size), Vec3d(0,0,0)); - result = math::Gradient::result( - map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - - { - // this map has no scale, expect result/voxel_spaceing = 1 - math::TranslationMap map; - result = math::Gradient::result(map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(voxel_size, result.length(), /*tolerance=*/0.01); - } - - { - // test the GenericMap Grid interface - math::GenericMap generic_map(*grid); - result = math::Gradient::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test the GenericMap Transform interface - math::GenericMap generic_map(grid->transform()); - result = math::Gradient::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test the GenericMap Map interface - math::GenericMap generic_map(rotated_map); - result = math::Gradient::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test a map with non-uniform SCALING AND ROTATION - Vec3d voxel_sizes(0.25, 0.45, 0.75); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - // apply rotation - rotated_map = base_map->preRotate(1.5, math::X_AXIS); - grid->setTransform(math::Transform::Ptr(new math::Transform(rotated_map))); - // remake the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - - // math::ScaleMap map(voxel_sizes); - result = math::Gradient::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test a map with non-uniform SCALING - Vec3d voxel_sizes(0.25, 0.45, 0.75); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - grid->setTransform(math::Transform::Ptr(new math::Transform(base_map))); - // remake the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - math::ScaleMap::Ptr scale_map = - boost::static_pointer_cast(base_map); - - // math::ScaleMap map(voxel_sizes); - result = math::Gradient::result(*scale_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } -} - -void -TestGradient::testWSGradientStencilFrustum() -{ - using namespace openvdb; - - // Construct a frustum that matches the one in TestMaps::testFrustum() - - openvdb::BBoxd bbox(Vec3d(0), Vec3d(100)); - math::NonlinearFrustumMap frustum(bbox, 1./6., 5); - /// frustum will have depth, far plane - near plane = 5 - /// the frustum has width 1 in the front and 6 in the back - - Vec3d trans(2,2,2); - math::NonlinearFrustumMap::Ptr map = - boost::static_pointer_cast( - frustum.preScale(Vec3d(10,10,10))->postTranslate(trans)); - - - // Create a grid with this frustum - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/0.f); - math::Transform::Ptr transform = math::Transform::Ptr( new math::Transform(map)); - grid->setTransform(transform); - - FloatGrid::Accessor acc = grid->getAccessor(); - // Totally fill the interior of the frustum with word space distances - // from its center. - - - math::Vec3d isCenter(.5 * 101, .5 * 101, .5 * 101); - math::Vec3d wsCenter = map->applyMap(isCenter); - - math::Coord ijk; - - // convert to IntType - Vec3i min(bbox.min()); - Vec3i max = Vec3i(bbox.max()) + Vec3i(1, 1, 1); - - for (ijk[0] = min.x(); ijk[0] < max.x(); ++ijk[0]) { - for (ijk[1] = min.y(); ijk[1] < max.y(); ++ijk[1]) { - for (ijk[2] = min.z(); ijk[2] < max.z(); ++ijk[2]) { - const math::Vec3d wsLocation = transform->indexToWorld(ijk); - const float dis = float((wsLocation - wsCenter).length()); - - acc.setValue(ijk, dis); - } - } - } - - - { - // test at location 10, 10, 10 in index space - math::Coord xyz(10, 10, 10); - - math::Vec3s result = - math::Gradient::result(*map, acc, xyz); - - // The Gradient should be unit lenght for this case - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - math::Vec3d wsVec = transform->indexToWorld(xyz); - math::Vec3d direction = (wsVec - wsCenter); - direction.normalize(); - - // test the actual direction of the gradient - CPPUNIT_ASSERT(direction.eq(result, 0.01 /*tolerance*/)); - } - - { - // test at location 30, 30, 60 in index space - math::Coord xyz(30, 30, 60); - - math::Vec3s result = - math::Gradient::result(*map, acc, xyz); - - // The Gradient should be unit lenght for this case - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - math::Vec3d wsVec = transform->indexToWorld(xyz); - math::Vec3d direction = (wsVec - wsCenter); - direction.normalize(); - - // test the actual direction of the gradient - CPPUNIT_ASSERT(direction.eq(result, 0.01 /*tolerance*/)); - } -} - - - -void -TestGradient::testWSGradientStencil() -{ - using namespace openvdb; - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f ,10.0f);//i.e. (12,16,20) in index space - const float radius = 10; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - const Coord xyz(11, 17, 26); - - // try with a map - math::SevenPointStencil stencil(*grid); - stencil.moveTo(xyz); - - math::SecondOrderDenseStencil dense_2ndOrder(*grid); - dense_2ndOrder.moveTo(xyz); - - math::FourthOrderDenseStencil dense_4thOrder(*grid); - dense_4thOrder.moveTo(xyz); - - Vec3f result; - math::MapBase::Ptr rotated_map; - { - math::UniformScaleMap map(voxel_size); - result = math::Gradient::result( - map, stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - rotated_map = map.preRotate(1.5, math::X_AXIS); - // verify the new map is an affine map - CPPUNIT_ASSERT(rotated_map->type() == math::AffineMap::mapType()); - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - // the gradient should have the same length even after rotation - - result = math::Gradient::result( - *affine_map, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - - result = math::Gradient::result( - *affine_map, dense_4thOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - math::UniformScaleTranslateMap map(voxel_size, Vec3d(0,0,0)); - - result = math::Gradient::result(map, stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - math::ScaleTranslateMap map(Vec3d(voxel_size, voxel_size, voxel_size), Vec3d(0,0,0)); - result = math::Gradient::result(map, stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - math::TranslationMap map; - result = math::Gradient::result(map, stencil); - // value = 1 because the translation map assumes uniform spacing - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, result.length(), /*tolerance=*/0.01); - } - { - // test the GenericMap Grid interface - math::GenericMap generic_map(*grid); - result = math::Gradient::result( - generic_map, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test the GenericMap Transform interface - math::GenericMap generic_map(grid->transform()); - result = math::Gradient::result( - generic_map, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test the GenericMap Map interface - math::GenericMap generic_map(rotated_map); - result = math::Gradient::result( - generic_map, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test a map with non-uniform SCALING AND ROTATION - Vec3d voxel_sizes(0.25, 0.45, 0.75); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - // apply rotation - rotated_map = base_map->preRotate(1.5, math::X_AXIS); - grid->setTransform(math::Transform::Ptr(new math::Transform(rotated_map))); - // remake the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - - stencil.moveTo(xyz); - result = math::Gradient::result(*affine_map, stencil); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } - { - // test a map with NON-UNIFORM SCALING - Vec3d voxel_sizes(0.5, 1.0, 0.75); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - grid->setTransform(math::Transform::Ptr(new math::Transform(base_map))); - // remake the sphere - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - math::ScaleMap map(voxel_sizes); - dense_2ndOrder.moveTo(xyz); - - result = math::Gradient::result(map, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, result.length(), /*tolerance=*/0.01); - } -} - - -void -TestGradient::testWSGradientNormSqr() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f,8.0f,10.0f);//i.e. (12,16,20) in index space - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - const Coord xyz(11, 17, 26); - - AccessorType inAccessor = grid->getConstAccessor(); - - // test gradient in index and world space using the 7-pt stencil - math::UniformScaleMap uniform_scale(voxel_size); - FloatTree::ValueType normsqrd; - normsqrd = math::GradientNormSqrd::result( - uniform_scale, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.07); - - // test world space using the 13pt stencil - normsqrd = math::GradientNormSqrd::result( - uniform_scale, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.05); - - math::AffineMap affine(voxel_size*math::Mat3d::identity()); - normsqrd = math::GradientNormSqrd::result( - affine, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.07); - - normsqrd = math::GradientNormSqrd::result( - uniform_scale, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.05); -} - - -void -TestGradient::testWSGradientNormSqrStencil() -{ - using namespace openvdb; - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - const Coord xyz(11, 17, 26); - - math::SevenPointStencil sevenpt(*grid); - sevenpt.moveTo(xyz); - - math::ThirteenPointStencil thirteenpt(*grid); - thirteenpt.moveTo(xyz); - - math::SecondOrderDenseStencil dense_2ndOrder(*grid); - dense_2ndOrder.moveTo(xyz); - - math::NineteenPointStencil nineteenpt(*grid); - nineteenpt.moveTo(xyz); - - // test gradient in index and world space using the 7-pt stencil - math::UniformScaleMap uniform_scale(voxel_size); - FloatTree::ValueType normsqrd; - normsqrd = math::GradientNormSqrd::result( - uniform_scale, sevenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.07); - - - // test gradient in index and world space using the 13pt stencil - normsqrd = math::GradientNormSqrd::result( - uniform_scale, thirteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.05); - - math::AffineMap affine(voxel_size*math::Mat3d::identity()); - normsqrd = math::GradientNormSqrd::result( - affine, dense_2ndOrder); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.07); - - normsqrd = math::GradientNormSqrd::result( - uniform_scale, nineteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, normsqrd, /*tolerance=*/0.05); -} - - -void -TestGradient::testGradientTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64, 64, 64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - const Coord xyz(10, 20, 30); - - Vec3SGrid::Ptr grad = tools::gradient(*grid); - CPPUNIT_ASSERT_EQUAL(int(tree.activeVoxelCount()), int(grad->activeVoxelCount())); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, grad->getConstAccessor().getValue(xyz).length(), - /*tolerance=*/0.01); -} - - -void -TestGradient::testGradientMaskedTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64, 64, 64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius = 10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - BoolGrid::Ptr maskGrid = BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - Vec3SGrid::Ptr grad = tools::gradient(*grid, *maskGrid); - {// outside the masked region - const Coord xyz(10, 20, 30); - CPPUNIT_ASSERT(!maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, grad->getConstAccessor().getValue(xyz).length(), - /*tolerance=*/0.01); - } - {// inside the masked region - const Coord xyz(38, 35, 33); - CPPUNIT_ASSERT(maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, grad->getConstAccessor().getValue(xyz).length(), - /*tolerance=*/0.01); - } -} - - -void -TestGradient::testIntersectsIsoValue() -{ - using namespace openvdb; - - {// test zero crossing in -x - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(-1,0,0), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT( stencil.intersects( )); - CPPUNIT_ASSERT( stencil.intersects( 0.0f)); - CPPUNIT_ASSERT( stencil.intersects( 2.0f)); - CPPUNIT_ASSERT(!stencil.intersects( 5.5f)); - CPPUNIT_ASSERT(!stencil.intersects(-2.5f)); - } - {// test zero crossing in +x - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(1,0,0), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } - {// test zero crossing in -y - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(0,-1,0), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } - {// test zero crossing in y - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(0,1,0), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } - {// test zero crossing in -z - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(0,0,-1), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } - {// test zero crossing in z - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(0,0,1), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } - {// test zero crossing in -x & z - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(-1,0,1), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(!stencil.intersects()); - } - {// test zero multiple crossings - FloatGrid grid(/*backgroundValue=*/5.0); - FloatTree& tree = grid.tree(); - Coord xyz(2,-5,60); - tree.setValue(xyz, 1.3f); - tree.setValue(xyz.offsetBy(-1, 0, 1), -1.0f); - tree.setValue(xyz.offsetBy( 0, 0, 1), -2.0f); - tree.setValue(xyz.offsetBy( 0, 1, 0), -3.0f); - tree.setValue(xyz.offsetBy( 0, 0,-1), -2.0f); - math::SevenPointStencil stencil(grid); - stencil.moveTo(xyz); - CPPUNIT_ASSERT(stencil.intersects()); - } -} - - -void -TestGradient::testOldStyleStencils() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(/*voxel size=*/0.5)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f,8.0f,10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - const Coord xyz(11, 17, 26); - - math::GradStencil gs(*grid); - gs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, gs.gradient().length(), /*tolerance=*/0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, gs.normSqGrad(), /*tolerance=*/0.10); - - math::WenoStencil ws(*grid); - ws.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, ws.gradient().length(), /*tolerance=*/0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, ws.normSqGrad(), /*tolerance=*/0.01); - - math::CurvatureStencil cs(*grid); - cs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, cs.gradient().length(), /*tolerance=*/0.01); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGrid.cc b/openvdb_3_0_0_library/unittest/TestGrid.cc deleted file mode 100755 index 9aa50e0..0000000 --- a/openvdb_3_0_0_library/unittest/TestGrid.cc +++ /dev/null @@ -1,433 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestGrid: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestGrid); - CPPUNIT_TEST(testGridRegistry); - CPPUNIT_TEST(testConstPtr); - CPPUNIT_TEST(testGetGrid); - CPPUNIT_TEST(testIsType); - CPPUNIT_TEST(testTransform); - CPPUNIT_TEST(testCopyGrid); - CPPUNIT_TEST(testValueConversion); - CPPUNIT_TEST(testClipping); - CPPUNIT_TEST_SUITE_END(); - - void testGridRegistry(); - void testConstPtr(); - void testGetGrid(); - void testIsType(); - void testTransform(); - void testCopyGrid(); - void testValueConversion(); - void testClipping(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGrid); - - -//////////////////////////////////////// - - -class ProxyTree: public openvdb::TreeBase -{ -public: - typedef int ValueType; - typedef void ValueAllCIter; - typedef void ValueAllIter; - typedef void ValueOffCIter; - typedef void ValueOffIter; - typedef void ValueOnCIter; - typedef void ValueOnIter; - typedef openvdb::TreeBase::Ptr TreeBasePtr; - typedef boost::shared_ptr Ptr; - typedef boost::shared_ptr ConstPtr; - - static const openvdb::Index DEPTH; - static const ValueType backg; - - ProxyTree() {} - ProxyTree(const ValueType&) {} - virtual ~ProxyTree() {} - - static const openvdb::Name& treeType() { static const openvdb::Name s("proxy"); return s; } - virtual const openvdb::Name& type() const { return treeType(); } - virtual openvdb::Name valueType() const { return "proxy"; } - const ValueType& background() const { return backg; } - - virtual TreeBasePtr copy() const { return TreeBasePtr(new ProxyTree(*this)); } - - virtual void readTopology(std::istream& is, bool = false) { is.seekg(0, std::ios::beg); } - virtual void writeTopology(std::ostream& os, bool = false) const { os.seekp(0); } - -#ifndef OPENVDB_2_ABI_COMPATIBLE - virtual void readBuffers(std::istream& is, - const openvdb::CoordBBox&, bool /*saveFloatAsHalf*/=false) { is.seekg(0); } - virtual void readNonresidentBuffers() const {} -#endif - virtual void readBuffers(std::istream& is, bool /*saveFloatAsHalf*/=false) { is.seekg(0); } - virtual void writeBuffers(std::ostream& os, bool /*saveFloatAsHalf*/=false) const - { os.seekp(0, std::ios::beg); } - - bool empty() const { return true; } - void clear() {} - void prune(const ValueType& = 0) {} - void clip(const openvdb::CoordBBox&) {} -#ifndef OPENVDB_2_ABI_COMPATIBLE - virtual void clipUnallocatedNodes() {} -#endif - - virtual void getIndexRange(openvdb::CoordBBox&) const {} - virtual bool evalLeafBoundingBox(openvdb::CoordBBox& bbox) const - { bbox.min() = bbox.max() = openvdb::Coord(0, 0, 0); return false; } - virtual bool evalActiveVoxelBoundingBox(openvdb::CoordBBox& bbox) const - { bbox.min() = bbox.max() = openvdb::Coord(0, 0, 0); return false; } - virtual bool evalActiveVoxelDim(openvdb::Coord& dim) const - { dim = openvdb::Coord(0, 0, 0); return false; } - virtual bool evalLeafDim(openvdb::Coord& dim) const - { dim = openvdb::Coord(0, 0, 0); return false; } - - virtual openvdb::Index treeDepth() const { return 0; } - virtual openvdb::Index leafCount() const { return 0; } - virtual openvdb::Index nonLeafCount() const { return 0; } - virtual openvdb::Index64 activeVoxelCount() const { return 0UL; } - virtual openvdb::Index64 inactiveVoxelCount() const { return 0UL; } - virtual openvdb::Index64 activeLeafVoxelCount() const { return 0UL; } - virtual openvdb::Index64 inactiveLeafVoxelCount() const { return 0UL; } -#ifndef OPENVDB_2_ABI_COMPATIBLE - virtual openvdb::Index64 activeTileCount() const { return 0UL; } -#endif -}; - -const openvdb::Index ProxyTree::DEPTH = 0; -const ProxyTree::ValueType ProxyTree::backg = 0; - -typedef openvdb::Grid ProxyGrid; - - -//////////////////////////////////////// - -void -TestGrid::testGridRegistry() -{ - using namespace openvdb::tree; - - typedef Tree, 2> > > TreeType; - typedef openvdb::Grid GridType; - - openvdb::GridBase::clearRegistry(); - - CPPUNIT_ASSERT(!GridType::isRegistered()); - GridType::registerGrid(); - CPPUNIT_ASSERT(GridType::isRegistered()); - CPPUNIT_ASSERT_THROW(GridType::registerGrid(), openvdb::KeyError); - GridType::unregisterGrid(); - CPPUNIT_ASSERT(!GridType::isRegistered()); - CPPUNIT_ASSERT_NO_THROW(GridType::unregisterGrid()); - CPPUNIT_ASSERT(!GridType::isRegistered()); - CPPUNIT_ASSERT_NO_THROW(GridType::registerGrid()); - CPPUNIT_ASSERT(GridType::isRegistered()); - - openvdb::GridBase::clearRegistry(); -} - - -void -TestGrid::testConstPtr() -{ - using namespace openvdb; - - GridBase::ConstPtr constgrid = ProxyGrid::create(); - - CPPUNIT_ASSERT_EQUAL(Name("proxy"), constgrid->type()); -} - - -void -TestGrid::testGetGrid() -{ - using namespace openvdb; - - GridBase::Ptr grid = FloatGrid::create(/*bg=*/0.0); - GridBase::ConstPtr constGrid = grid; - - CPPUNIT_ASSERT(grid->baseTreePtr()); - - CPPUNIT_ASSERT(!gridPtrCast(grid)); - CPPUNIT_ASSERT(!gridPtrCast(grid)); - - CPPUNIT_ASSERT(gridConstPtrCast(constGrid)); - CPPUNIT_ASSERT(!gridConstPtrCast(constGrid)); -} - - -void -TestGrid::testIsType() -{ - using namespace openvdb; - - GridBase::Ptr grid = FloatGrid::create(); - CPPUNIT_ASSERT(grid->isType()); - CPPUNIT_ASSERT(!grid->isType()); -} - - -void -TestGrid::testTransform() -{ - ProxyGrid grid; - - // Verify that the grid has a valid default transform. - CPPUNIT_ASSERT(grid.transformPtr()); - - // Verify that a null transform pointer is not allowed. - CPPUNIT_ASSERT_THROW(grid.setTransform(openvdb::math::Transform::Ptr()), - openvdb::ValueError); - - grid.setTransform(openvdb::math::Transform::createLinearTransform()); - - CPPUNIT_ASSERT(grid.transformPtr()); - - // Verify that calling Transform-related Grid methods (Grid::voxelSize(), etc.) - // is the same as calling those methods on the Transform. - - CPPUNIT_ASSERT(grid.transform().voxelSize().eq(grid.voxelSize())); - CPPUNIT_ASSERT(grid.transform().voxelSize(openvdb::Vec3d(0.1, 0.2, 0.3)).eq( - grid.voxelSize(openvdb::Vec3d(0.1, 0.2, 0.3)))); - - CPPUNIT_ASSERT(grid.transform().indexToWorld(openvdb::Vec3d(0.1, 0.2, 0.3)).eq( - grid.indexToWorld(openvdb::Vec3d(0.1, 0.2, 0.3)))); - CPPUNIT_ASSERT(grid.transform().indexToWorld(openvdb::Coord(1, 2, 3)).eq( - grid.indexToWorld(openvdb::Coord(1, 2, 3)))); - CPPUNIT_ASSERT(grid.transform().worldToIndex(openvdb::Vec3d(0.1, 0.2, 0.3)).eq( - grid.worldToIndex(openvdb::Vec3d(0.1, 0.2, 0.3)))); -} - - -void -TestGrid::testCopyGrid() -{ - using namespace openvdb; - - // set up a grid - const float fillValue1=5.0f; - FloatGrid::Ptr grid1 = createGrid(/*bg=*/fillValue1); - FloatTree& tree1 = grid1->tree(); - tree1.setValue(Coord(-10,40,845), 3.456f); - tree1.setValue(Coord(1,-50,-8), 1.0f); - - // create a new grid, copying the first grid - GridBase::Ptr grid2 = grid1->deepCopy(); - - // cast down to the concrete type to query values - FloatTree& tree2 = gridPtrCast(grid2)->tree(); - - // compare topology - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - // trees should be equal - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue1, tree2.getValue(Coord(1,2,3))); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.456f, tree2.getValue(Coord(-10,40,845))); - ASSERT_DOUBLES_EXACTLY_EQUAL(1.0f, tree2.getValue(Coord(1,-50,-8))); - - // change 1 value in tree2 - Coord changeCoord(1, -500, -8); - tree2.setValue(changeCoord, 1.0f); - - // topology should no longer match - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - // query changed value and make sure it's different between trees - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue1, tree1.getValue(changeCoord)); - ASSERT_DOUBLES_EXACTLY_EQUAL(1.0f, tree2.getValue(changeCoord)); -} - - -void -TestGrid::testValueConversion() -{ - using namespace openvdb; - - const Coord c0(-10, 40, 845), c1(1, -50, -8), c2(1, 2, 3); - const float fval0 = 3.25f, fval1 = 1.0f, fbkgd = 5.0f; - - // Create a FloatGrid. - FloatGrid fgrid(fbkgd); - FloatTree& ftree = fgrid.tree(); - ftree.setValue(c0, fval0); - ftree.setValue(c1, fval1); - - // Copy the FloatGrid to a DoubleGrid. - DoubleGrid dgrid(fgrid); - DoubleTree& dtree = dgrid.tree(); - // Compare topology. - CPPUNIT_ASSERT(dtree.hasSameTopology(ftree)); - CPPUNIT_ASSERT(ftree.hasSameTopology(dtree)); - // Compare values. - ASSERT_DOUBLES_EXACTLY_EQUAL(double(fbkgd), dtree.getValue(c2)); - ASSERT_DOUBLES_EXACTLY_EQUAL(double(fval0), dtree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(double(fval1), dtree.getValue(c1)); - - // Copy the FloatGrid to a BoolGrid. - BoolGrid bgrid(fgrid); - BoolTree& btree = bgrid.tree(); - // Compare topology. - CPPUNIT_ASSERT(btree.hasSameTopology(ftree)); - CPPUNIT_ASSERT(ftree.hasSameTopology(btree)); - // Compare values. - CPPUNIT_ASSERT_EQUAL(bool(fbkgd), btree.getValue(c2)); - CPPUNIT_ASSERT_EQUAL(bool(fval0), btree.getValue(c0)); - CPPUNIT_ASSERT_EQUAL(bool(fval1), btree.getValue(c1)); - - // Copy the FloatGrid to a Vec3SGrid. - Vec3SGrid vgrid(fgrid); - Vec3STree& vtree = vgrid.tree(); - // Compare topology. - CPPUNIT_ASSERT(vtree.hasSameTopology(ftree)); - CPPUNIT_ASSERT(ftree.hasSameTopology(vtree)); - // Compare values. - CPPUNIT_ASSERT_EQUAL(Vec3s(fbkgd), vtree.getValue(c2)); - CPPUNIT_ASSERT_EQUAL(Vec3s(fval0), vtree.getValue(c0)); - CPPUNIT_ASSERT_EQUAL(Vec3s(fval1), vtree.getValue(c1)); - - // Verify that a Vec3SGrid can't be copied to an Int32Grid - // (because an Int32 can't be constructed from a Vec3S). - CPPUNIT_ASSERT_THROW(Int32Grid igrid2(vgrid), openvdb::TypeError); - - // Verify that a grid can't be converted to another type with a different - // tree configuration. - typedef tree::Tree3::Type DTree23; - typedef Grid DGrid23; - CPPUNIT_ASSERT_THROW(DGrid23 d23grid(fgrid), openvdb::TypeError); -} - - -//////////////////////////////////////// - - -template -void -validateClippedGrid(const GridT& clipped, const typename GridT::ValueType& fg) -{ - using namespace openvdb; - - typedef typename GridT::ValueType ValueT; - - const CoordBBox bbox = clipped.evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().y()); - CPPUNIT_ASSERT_EQUAL(-6, bbox.min().z()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().y()); - CPPUNIT_ASSERT_EQUAL(6, bbox.max().z()); - CPPUNIT_ASSERT_EQUAL(6 + 6 + 1, int(clipped.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(2, int(clipped.constTree().leafCount())); - - typename GridT::ConstAccessor acc = clipped.getConstAccessor(); - const ValueT bg = clipped.background(); - Coord xyz; - int &x = xyz[0], &y = xyz[1], &z = xyz[2]; - for (x = -10; x <= 10; ++x) { - for (y = -10; y <= 10; ++y) { - for (z = -10; z <= 10; ++z) { - if (x == 4 && y == 4 && z >= -6 && z <= 6) { - CPPUNIT_ASSERT_EQUAL(fg, acc.getValue(Coord(4, 4, z))); - } else { - CPPUNIT_ASSERT_EQUAL(bg, acc.getValue(Coord(x, y, z))); - } - } - } - } -} - - -// See also TestTools::testClipping() -void -TestGrid::testClipping() -{ - using namespace openvdb; - - const BBoxd clipBox(Vec3d(4.0, 4.0, -6.0), Vec3d(4.9, 4.9, 6.0)); - - { - const float fg = 5.f; - FloatGrid cube(0.f); - cube.fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/fg, /*active=*/true); -#ifdef OPENVDB_2_ABI_COMPATIBLE - cube.tree().clip(cube.constTransform().worldToIndexNodeCentered(clipBox)); -#else - cube.clipGrid(clipBox); -#endif - validateClippedGrid(cube, fg); - } - { - const bool fg = true; - BoolGrid cube(false); - cube.fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/fg, /*active=*/true); -#ifdef OPENVDB_2_ABI_COMPATIBLE - cube.tree().clip(cube.constTransform().worldToIndexNodeCentered(clipBox)); -#else - cube.clipGrid(clipBox); -#endif - validateClippedGrid(cube, fg); - } - { - const Vec3s fg(1.f, -2.f, 3.f); - Vec3SGrid cube(Vec3s(0.f)); - cube.fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/fg, /*active=*/true); -#ifdef OPENVDB_2_ABI_COMPATIBLE - cube.tree().clip(cube.constTransform().worldToIndexNodeCentered(clipBox)); -#else - cube.clipGrid(clipBox); -#endif - validateClippedGrid(cube, fg); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGridBbox.cc b/openvdb_3_0_0_library/unittest/TestGridBbox.cc deleted file mode 100755 index 5d76aec..0000000 --- a/openvdb_3_0_0_library/unittest/TestGridBbox.cc +++ /dev/null @@ -1,114 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include - -#include -#include -#include -#include -#include - - -class TestGridBbox: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestGridBbox); - CPPUNIT_TEST(testLeafBbox); - CPPUNIT_TEST(testGridBbox); - CPPUNIT_TEST_SUITE_END(); - - void testLeafBbox(); - void testGridBbox(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGridBbox); - - -//////////////////////////////////////// - - -void -TestGridBbox::testLeafBbox() -{ - openvdb::FloatTree tree(/*fillValue=*/256.0f); - - openvdb::CoordBBox bbox; - CPPUNIT_ASSERT(!tree.evalLeafBoundingBox(bbox)); - - // Add values to buffer zero. - tree.setValue(openvdb::Coord( 0, 9, 9), 2.0); - tree.setValue(openvdb::Coord(100, 35, 800), 2.5); - - // Coordinates in CoordBBox are inclusive! - CPPUNIT_ASSERT(tree.evalLeafBoundingBox(bbox)); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 8, 8), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(104-1, 40-1, 808-1), bbox.max()); - - // Test negative coordinates. - tree.setValue(openvdb::Coord(-100, -35, -800), 2.5); - - CPPUNIT_ASSERT(tree.evalLeafBoundingBox(bbox)); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-104, -40, -800), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(104-1, 40-1, 808-1), bbox.max()); -} - - -void -TestGridBbox::testGridBbox() -{ - openvdb::FloatTree tree(/*fillValue=*/256.0f); - - openvdb::CoordBBox bbox; - CPPUNIT_ASSERT(!tree.evalActiveVoxelBoundingBox(bbox)); - - // Add values to buffer zero. - tree.setValue(openvdb::Coord( 1, 0, 0), 1.5); - tree.setValue(openvdb::Coord( 0, 12, 8), 2.0); - tree.setValue(openvdb::Coord( 1, 35, 800), 2.5); - tree.setValue(openvdb::Coord(100, 0, 16), 3.0); - tree.setValue(openvdb::Coord( 1, 0, 16), 3.5); - - // Coordinates in CoordBBox are inclusive! - CPPUNIT_ASSERT(tree.evalActiveVoxelBoundingBox(bbox)); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord( 0, 0, 0), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(100, 35, 800), bbox.max()); - - // Test negative coordinates. - tree.setValue(openvdb::Coord(-100, -35, -800), 2.5); - - CPPUNIT_ASSERT(tree.evalActiveVoxelBoundingBox(bbox)); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-100, -35, -800), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(100, 35, 800), bbox.max()); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGridDescriptor.cc b/openvdb_3_0_0_library/unittest/TestGridDescriptor.cc deleted file mode 100755 index 56b94a2..0000000 --- a/openvdb_3_0_0_library/unittest/TestGridDescriptor.cc +++ /dev/null @@ -1,190 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - - -class TestGridDescriptor: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestGridDescriptor); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testCopy); - CPPUNIT_TEST(testName); - CPPUNIT_TEST_SUITE_END(); - - void testIO(); - void testCopy(); - void testName(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGridDescriptor); - - -void -TestGridDescriptor::testIO() -{ - using namespace openvdb::io; - using namespace openvdb; - - typedef FloatGrid GridType; - - GridDescriptor gd(GridDescriptor::addSuffix("temperature", 2), GridType::gridType()); - gd.setInstanceParentName("temperature_32bit"); - - gd.setGridPos(123); - gd.setBlockPos(234); - gd.setEndPos(567); - - // write out the gd. - std::ostringstream ostr(std::ios_base::binary); - - gd.writeHeader(ostr); - gd.writeStreamPos(ostr); - - // Read in the gd. - std::istringstream istr(ostr.str(), std::ios_base::binary); - - // Since the input is only a fragment of a VDB file (in particular, - // it doesn't have a header), set the file format version number explicitly. - io::setCurrentVersion(istr); - - GridDescriptor gd2; - - CPPUNIT_ASSERT_THROW(gd2.read(istr), openvdb::LookupError); - - // Register the grid. - GridBase::clearRegistry(); - GridType::registerGrid(); - - // seek back and read again. - istr.seekg(0, std::ios_base::beg); - GridBase::Ptr grid; - CPPUNIT_ASSERT_NO_THROW(grid = gd2.read(istr)); - - CPPUNIT_ASSERT_EQUAL(gd.gridName(), gd2.gridName()); - CPPUNIT_ASSERT_EQUAL(gd.uniqueName(), gd2.uniqueName()); - CPPUNIT_ASSERT_EQUAL(gd.gridType(), gd2.gridType()); - CPPUNIT_ASSERT_EQUAL(gd.instanceParentName(), gd2.instanceParentName()); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(GridType::gridType(), grid->type()); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), gd2.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), gd2.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), gd2.getEndPos()); - - // Clear the registry when we are done. - GridBase::clearRegistry(); -} - - -void -TestGridDescriptor::testCopy() -{ - using namespace openvdb::io; - using namespace openvdb; - - typedef FloatGrid GridType; - - GridDescriptor gd("temperature", GridType::gridType()); - gd.setInstanceParentName("temperature_32bit"); - - gd.setGridPos(123); - gd.setBlockPos(234); - gd.setEndPos(567); - - GridDescriptor gd2; - - // do the copy - gd2 = gd; - - CPPUNIT_ASSERT_EQUAL(gd.gridName(), gd2.gridName()); - CPPUNIT_ASSERT_EQUAL(gd.uniqueName(), gd2.uniqueName()); - CPPUNIT_ASSERT_EQUAL(gd.gridType(), gd2.gridType()); - CPPUNIT_ASSERT_EQUAL(gd.instanceParentName(), gd2.instanceParentName()); - CPPUNIT_ASSERT_EQUAL(gd.getGridPos(), gd2.getGridPos()); - CPPUNIT_ASSERT_EQUAL(gd.getBlockPos(), gd2.getBlockPos()); - CPPUNIT_ASSERT_EQUAL(gd.getEndPos(), gd2.getEndPos()); -} - - -void -TestGridDescriptor::testName() -{ - using openvdb::Name; - using openvdb::io::GridDescriptor; - - const std::string typ = openvdb::FloatGrid::gridType(); - - Name name("test"); - GridDescriptor gd(name, typ); - - // Verify that the grid name and the unique name are equivalent - // when the unique name has no suffix. - CPPUNIT_ASSERT_EQUAL(name, gd.gridName()); - CPPUNIT_ASSERT_EQUAL(name, gd.uniqueName()); - CPPUNIT_ASSERT_EQUAL(name, GridDescriptor::nameAsString(name)); - CPPUNIT_ASSERT_EQUAL(name, GridDescriptor::stripSuffix(name)); - - // Add a suffix. - name = GridDescriptor::addSuffix("test", 2); - gd = GridDescriptor(name, typ); - - // Verify that the grid name and the unique name differ - // when the unique name has a suffix. - CPPUNIT_ASSERT_EQUAL(name, gd.uniqueName()); - CPPUNIT_ASSERT(gd.gridName() != gd.uniqueName()); - CPPUNIT_ASSERT_EQUAL(GridDescriptor::stripSuffix(name), gd.gridName()); - CPPUNIT_ASSERT_EQUAL(Name("test[2]"), GridDescriptor::nameAsString(name)); - - // As above, but with a longer suffix - name = GridDescriptor::addSuffix("test", 13); - gd = GridDescriptor(name, typ); - - CPPUNIT_ASSERT_EQUAL(name, gd.uniqueName()); - CPPUNIT_ASSERT(gd.gridName() != gd.uniqueName()); - CPPUNIT_ASSERT_EQUAL(GridDescriptor::stripSuffix(name), gd.gridName()); - CPPUNIT_ASSERT_EQUAL(Name("test[13]"), GridDescriptor::nameAsString(name)); - - // Multiple suffixes aren't supported, but verify that - // they behave reasonably, at least. - name = GridDescriptor::addSuffix(name, 4); - gd = GridDescriptor(name, typ); - - CPPUNIT_ASSERT_EQUAL(name, gd.uniqueName()); - CPPUNIT_ASSERT(gd.gridName() != gd.uniqueName()); - CPPUNIT_ASSERT_EQUAL(GridDescriptor::stripSuffix(name), gd.gridName()); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGridIO.cc b/openvdb_3_0_0_library/unittest/TestGridIO.cc deleted file mode 100755 index 218a001..0000000 --- a/openvdb_3_0_0_library/unittest/TestGridIO.cc +++ /dev/null @@ -1,236 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include // for remove() - - -class TestGridIO: public CppUnit::TestCase -{ -public: - typedef openvdb::tree::Tree< - openvdb::tree::RootNode< - openvdb::tree::InternalNode< - openvdb::tree::InternalNode< - openvdb::tree::InternalNode< - openvdb::tree::LeafNode, 3>, 4>, 5> > > - Float5432Tree; - typedef openvdb::Grid Float5432Grid; - - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestGridIO); - CPPUNIT_TEST(testReadAllBool); - CPPUNIT_TEST(testReadAllFloat); - CPPUNIT_TEST(testReadAllVec3S); - CPPUNIT_TEST(testReadAllFloat5432); - CPPUNIT_TEST(testReadAllHermite); - CPPUNIT_TEST_SUITE_END(); - - void testReadAllBool() { readAllTest(); } - void testReadAllFloat() { readAllTest(); } - void testReadAllVec3S() { readAllTest(); } - void testReadAllFloat5432() { Float5432Grid::registerGrid(); readAllTest(); } - void testReadAllHermite() { readAllTest(); } -private: - template void readAllTest(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGridIO); - - -//////////////////////////////////////// - - -template -void -TestGridIO::readAllTest() -{ - using namespace openvdb; - - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::Ptr TreePtr; - typedef typename TreeType::ValueType ValueT; - typedef typename TreeType::NodeCIter NodeCIter; - const ValueT zero = zeroVal(); - - // For each level of the tree, compute a bit mask for use in converting - // global coordinates to node origins for nodes at that level. - // That is, node_origin = global_coordinates & mask[node_level]. - std::vector mask; - TreeType::getNodeLog2Dims(mask); - const size_t height = mask.size(); - for (size_t i = 0; i < height; ++i) { - Index dim = 0; - for (size_t j = i; j < height; ++j) dim += mask[j]; - mask[i] = ~((1 << dim) - 1); - } - const Index childDim = 1 + ~(mask[0]); - - // Choose sample coordinate pairs (coord0, coord1) and (coord0, coord2) - // that are guaranteed to lie in different children of the root node - // (because they are separated by more than the child node dimension). - const Coord - coord0(0, 0, 0), - coord1(int(1.1 * childDim), 0, 0), - coord2(0, int(1.1 * childDim), 0); - - // Create trees. - TreePtr - tree1(new TreeType(zero + 1)), - tree2(new TreeType(zero + 2)); - - // Set some values. - tree1->setValue(coord0, zero + 5); - tree1->setValue(coord1, zero + 6); - tree2->setValue(coord0, zero + 10); - tree2->setValue(coord2, zero + 11); - - // Create grids with trees and assign transforms. - math::Transform::Ptr trans1(math::Transform::createLinearTransform(0.1)), - trans2(math::Transform::createLinearTransform(0.1)); - GridBase::Ptr grid1 = createGrid(tree1), grid2 = createGrid(tree2); - grid1->setTransform(trans1); - grid1->setName("density"); - grid2->setTransform(trans2); - grid2->setName("temperature"); - - OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 5), tree1->getValue(coord0)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 6), tree1->getValue(coord1)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 10), tree2->getValue(coord0)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 11), tree2->getValue(coord2)); - OPENVDB_NO_FP_EQUALITY_WARNING_END - - // count[d] is the number of nodes already visited at depth d. - // There should be exactly two nodes at each depth (apart from the root). - std::vector count(height, 0); - - // Verify that tree1 has correct node origins. - for (NodeCIter iter = tree1->cbeginNode(); iter; ++iter) { - const Index depth = iter.getDepth(); - const Coord expected[2] = { - coord0 & mask[depth], // origin of the first node at this depth - coord1 & mask[depth] // origin of the second node at this depth - }; - CPPUNIT_ASSERT_EQUAL(expected[count[depth]], iter.getCoord()); - ++count[depth]; - } - // Verify that tree2 has correct node origins. - count.assign(height, 0); // reset node counts - for (NodeCIter iter = tree2->cbeginNode(); iter; ++iter) { - const Index depth = iter.getDepth(); - const Coord expected[2] = { coord0 & mask[depth], coord2 & mask[depth] }; - CPPUNIT_ASSERT_EQUAL(expected[count[depth]], iter.getCoord()); - ++count[depth]; - } - - MetaMap::Ptr meta(new MetaMap); - meta->insertMeta("author", StringMetadata("Einstein")); - meta->insertMeta("year", Int32Metadata(2009)); - - GridPtrVecPtr grids(new GridPtrVec); - grids->push_back(grid1); - grids->push_back(grid2); - - // Write grids and metadata out to a file. - { - io::File vdbfile("something.vdb2"); - vdbfile.write(*grids, *meta); - } - meta.reset(); - grids.reset(); - - io::File vdbfile("something.vdb2"); - CPPUNIT_ASSERT_THROW(vdbfile.getGrids(), openvdb::IoError); // file has not been opened - - // Read the grids back in. - vdbfile.open(); - CPPUNIT_ASSERT(vdbfile.isOpen()); - - grids = vdbfile.getGrids(); - meta = vdbfile.getMetadata(); - - // Ensure we have the metadata. - CPPUNIT_ASSERT(meta.get() != NULL); - CPPUNIT_ASSERT_EQUAL(2, int(meta->metaCount())); - CPPUNIT_ASSERT_EQUAL(std::string("Einstein"), meta->metaValue("author")); - CPPUNIT_ASSERT_EQUAL(2009, meta->metaValue("year")); - - // Ensure we got both grids. - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT_EQUAL(2, int(grids->size())); - - grid1.reset(); - grid1 = findGridByName(*grids, "density"); - CPPUNIT_ASSERT(grid1.get() != NULL); - TreePtr density = gridPtrCast(grid1)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - - grid2.reset(); - grid2 = findGridByName(*grids, "temperature"); - CPPUNIT_ASSERT(grid2.get() != NULL); - TreePtr temperature = gridPtrCast(grid2)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - - OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 5), density->getValue(coord0)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 6), density->getValue(coord1)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 10), temperature->getValue(coord0)); - CPPUNIT_ASSERT_EQUAL(ValueT(zero + 11), temperature->getValue(coord2)); - OPENVDB_NO_FP_EQUALITY_WARNING_END - - // Check if we got the correct node origins. - count.assign(height, 0); - for (NodeCIter iter = density->cbeginNode(); iter; ++iter) { - const Index depth = iter.getDepth(); - const Coord expected[2] = { coord0 & mask[depth], coord1 & mask[depth] }; - CPPUNIT_ASSERT_EQUAL(expected[count[depth]], iter.getCoord()); - ++count[depth]; - } - count.assign(height, 0); - for (NodeCIter iter = temperature->cbeginNode(); iter; ++iter) { - const Index depth = iter.getDepth(); - const Coord expected[2] = { coord0 & mask[depth], coord2 & mask[depth] }; - CPPUNIT_ASSERT_EQUAL(expected[count[depth]], iter.getCoord()); - ++count[depth]; - } - - vdbfile.close(); - - ::remove("something.vdb2"); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestGridTransformer.cc b/openvdb_3_0_0_library/unittest/TestGridTransformer.cc deleted file mode 100755 index 3805836..0000000 --- a/openvdb_3_0_0_library/unittest/TestGridTransformer.cc +++ /dev/null @@ -1,266 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestGridTransformer: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestGridTransformer); - CPPUNIT_TEST(testTransformBoolPoint); - CPPUNIT_TEST(testTransformFloatPoint); - CPPUNIT_TEST(testTransformFloatBox); - CPPUNIT_TEST(testTransformFloatQuadratic); - CPPUNIT_TEST(testTransformDoubleBox); - CPPUNIT_TEST(testTransformInt32Box); - CPPUNIT_TEST(testTransformInt64Box); - CPPUNIT_TEST(testTransformVec3SPoint); - CPPUNIT_TEST(testTransformVec3DBox); - CPPUNIT_TEST(testResampleToMatch); - CPPUNIT_TEST_SUITE_END(); - - void testTransformBoolPoint() - { transformGrid(); } - void testTransformFloatPoint() - { transformGrid(); } - void testTransformFloatBox() - { transformGrid(); } - void testTransformFloatQuadratic() - { transformGrid(); } - void testTransformDoubleBox() - { transformGrid(); } - void testTransformInt32Box() - { transformGrid(); } - void testTransformInt64Box() - { transformGrid(); } - void testTransformVec3SPoint() - { transformGrid(); } - void testTransformVec3DBox() - { transformGrid(); } - - void testResampleToMatch(); - -private: - template void transformGrid(); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestGridTransformer); - - -//////////////////////////////////////// - - -template -void -TestGridTransformer::transformGrid() -{ - using openvdb::Coord; - using openvdb::CoordBBox; - using openvdb::Vec3R; - - typedef typename GridType::ValueType ValueT; - - const int radius = Sampler::radius(); - const openvdb::Vec3R zeroVec(0, 0, 0), oneVec(1, 1, 1); - const ValueT - zero = openvdb::zeroVal(), - one = zero + 1, - two = one + 1, - background = one; - const bool transformTiles = true; - - // Create a sparse test grid comprising the eight corners of a 20 x 20 x 20 cube. - typename GridType::Ptr inGrid = GridType::create(background); - typename GridType::Accessor inAcc = inGrid->getAccessor(); - inAcc.setValue(Coord( 0, 0, 0), /*value=*/zero); - inAcc.setValue(Coord(20, 0, 0), zero); - inAcc.setValue(Coord( 0, 20, 0), zero); - inAcc.setValue(Coord( 0, 0, 20), zero); - inAcc.setValue(Coord(20, 0, 20), zero); - inAcc.setValue(Coord( 0, 20, 20), zero); - inAcc.setValue(Coord(20, 20, 0), zero); - inAcc.setValue(Coord(20, 20, 20), zero); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(8), inGrid->activeVoxelCount()); - - // For various combinations of scaling, rotation and translation... - for (int i = 0; i < 8; ++i) { - const openvdb::Vec3R - scale = i & 1 ? openvdb::Vec3R(10, 4, 7.5) : oneVec, - rotate = (i & 2 ? openvdb::Vec3R(30, 230, -190) : zeroVec) * (M_PI / 180), - translate = i & 4 ? openvdb::Vec3R(-5, 0, 10) : zeroVec, - pivot = i & 8 ? openvdb::Vec3R(0.5, 4, -3.3) : zeroVec; - openvdb::tools::GridTransformer transformer(pivot, scale, rotate, translate); - transformer.setTransformTiles(transformTiles); - - // Add a tile (either active or inactive) in the interior of the cube. - const bool tileIsActive = (i % 2); - inGrid->fill(CoordBBox(Coord(8), Coord(15)), two, tileIsActive); - if (tileIsActive) { - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(512 + 8), inGrid->activeVoxelCount()); - } else { - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(8), inGrid->activeVoxelCount()); - } - // Verify that a voxel outside the cube has the background value. - CPPUNIT_ASSERT(openvdb::math::isExactlyEqual(inAcc.getValue(Coord(21, 0, 0)), background)); - CPPUNIT_ASSERT_EQUAL(false, inAcc.isValueOn(Coord(21, 0, 0))); - // Verify that a voxel inside the cube has value two. - CPPUNIT_ASSERT(openvdb::math::isExactlyEqual(inAcc.getValue(Coord(12)), two)); - CPPUNIT_ASSERT_EQUAL(tileIsActive, inAcc.isValueOn(Coord(12))); - - // Verify that the bounding box of all active values is 20 x 20 x 20. - CoordBBox activeVoxelBBox = inGrid->evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT(!activeVoxelBBox.empty()); - const Coord imin = activeVoxelBBox.min(), imax = activeVoxelBBox.max(); - CPPUNIT_ASSERT_EQUAL(Coord(0), imin); - CPPUNIT_ASSERT_EQUAL(Coord(20), imax); - - // Transform the corners of the input grid's bounding box - // and compute the enclosing bounding box in the output grid. - const openvdb::Mat4R xform = transformer.getTransform(); - const Vec3R - inRMin(imin.x(), imin.y(), imin.z()), - inRMax(imax.x(), imax.y(), imax.z()); - Vec3R outRMin, outRMax; - outRMin = outRMax = inRMin * xform; - for (int j = 0; j < 8; ++j) { - Vec3R corner( - j & 1 ? inRMax.x() : inRMin.x(), - j & 2 ? inRMax.y() : inRMin.y(), - j & 4 ? inRMax.z() : inRMin.z()); - outRMin = openvdb::math::minComponent(outRMin, corner * xform); - outRMax = openvdb::math::maxComponent(outRMax, corner * xform); - } - - CoordBBox bbox( - Coord(openvdb::tools::local_util::floorVec3(outRMin) - radius), - Coord(openvdb::tools::local_util::ceilVec3(outRMax) + radius)); - - // Transform the test grid. - typename GridType::Ptr outGrid = GridType::create(background); - transformer.transformGrid(*inGrid, *outGrid); - openvdb::tools::prune(outGrid->tree()); - - // Verify that the bounding box of the transformed grid - // matches the transformed bounding box of the original grid. - - activeVoxelBBox = outGrid->evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT(!activeVoxelBBox.empty()); - const openvdb::Vec3i - omin = activeVoxelBBox.min().asVec3i(), - omax = activeVoxelBBox.max().asVec3i(); - const int bboxTolerance = 1; // allow for rounding -#if 0 - if (!omin.eq(bbox.min().asVec3i(), bboxTolerance) || - !omax.eq(bbox.max().asVec3i(), bboxTolerance)) - { - std::cerr << "\nS = " << scale << ", R = " << rotate - << ", T = " << translate << ", P = " << pivot << "\n" - << xform.transpose() << "\n" << "computed bbox = " << bbox - << "\nactual bbox = " << omin << " -> " << omax << "\n"; - } -#endif - CPPUNIT_ASSERT(omin.eq(bbox.min().asVec3i(), bboxTolerance)); - CPPUNIT_ASSERT(omax.eq(bbox.max().asVec3i(), bboxTolerance)); - - // Verify that (a voxel in) the interior of the cube was - // transformed correctly. - const Coord center = Coord::round(Vec3R(12) * xform); - const typename GridType::TreeType& outTree = outGrid->tree(); - CPPUNIT_ASSERT(openvdb::math::isExactlyEqual(transformTiles ? two : background, - outTree.getValue(center))); - if (transformTiles && tileIsActive) CPPUNIT_ASSERT(outTree.isValueOn(center)); - else CPPUNIT_ASSERT(!outTree.isValueOn(center)); - } -} - - -//////////////////////////////////////// - - -void -TestGridTransformer::testResampleToMatch() -{ - using namespace openvdb; - - // Create an input grid with an identity transform. - FloatGrid inGrid; - // Populate it with a 10 x 10 x 10 cube. - inGrid.fill(CoordBBox(Coord(5), Coord(14)), /*value=*/1.0); - CPPUNIT_ASSERT_EQUAL(1000, int(inGrid.activeVoxelCount())); - - {//test identity transform - FloatGrid outGrid; - CPPUNIT_ASSERT(outGrid.transform() == inGrid.transform()); - // Resample the input grid into the output grid using point sampling. - tools::resampleToMatch(inGrid, outGrid); - CPPUNIT_ASSERT_EQUAL(int(inGrid.activeVoxelCount()), int(outGrid.activeVoxelCount())); - for (openvdb::FloatTree::ValueOnCIter iter = inGrid.tree().cbeginValueOn(); iter; ++iter) { - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,outGrid.tree().getValue(iter.getCoord())); - } - // The output grid's transform should not have changed. - CPPUNIT_ASSERT(outGrid.transform() == inGrid.transform()); - } - - {//test nontrivial transform - // Create an output grid with a different transform. - math::Transform::Ptr xform = math::Transform::createLinearTransform(); - xform->preScale(Vec3d(2.0, 2.0, 1.0)); - FloatGrid outGrid; - outGrid.setTransform(xform); - CPPUNIT_ASSERT(outGrid.transform() != inGrid.transform()); - - // Resample the input grid into the output grid using point sampling. - tools::resampleToMatch(inGrid, outGrid); - - // The output grid's transform should not have changed. - CPPUNIT_ASSERT_EQUAL(*xform, outGrid.transform()); - - // The output grid should have half the resolution of the input grid in x and y - // and the same resolution in z. - CPPUNIT_ASSERT_EQUAL(250, int(outGrid.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(Coord(5, 5, 10), outGrid.evalActiveVoxelDim()), - CPPUNIT_ASSERT_EQUAL(CoordBBox(Coord(3, 3, 5), Coord(7, 7, 14)), - outGrid.evalActiveVoxelBoundingBox()); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestHermite.cc b/openvdb_3_0_0_library/unittest/TestHermite.cc deleted file mode 100755 index 2161540..0000000 --- a/openvdb_3_0_0_library/unittest/TestHermite.cc +++ /dev/null @@ -1,359 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -class TestHermite: public CppUnit::TestFixture -{ -public: - - CPPUNIT_TEST_SUITE(TestHermite); - CPPUNIT_TEST(testAccessors); - CPPUNIT_TEST(testComparisons); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST_SUITE_END(); - - void testAccessors(); - void testComparisons(); - void testIO(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestHermite); - - -//////////////////////////////////////// - - -void -TestHermite::testAccessors() -{ - using namespace openvdb; - using namespace openvdb::math; - const double offsetTol = 0.001; - const float normalTol = 0.015f; - - ////////// - - // Check initial values. - - Hermite hermite; - - CPPUNIT_ASSERT(!hermite); - CPPUNIT_ASSERT(!hermite.isInside()); - - CPPUNIT_ASSERT(!hermite.hasOffsetX()); - CPPUNIT_ASSERT(!hermite.hasOffsetY()); - CPPUNIT_ASSERT(!hermite.hasOffsetZ()); - - - ////////// - - // Check set & get - - // x - Vec3s n0(1.0, 0.0, 0.0); - hermite.setX(0.5f, n0); - CPPUNIT_ASSERT(hermite.hasOffsetX()); - CPPUNIT_ASSERT(!hermite.hasOffsetY()); - CPPUNIT_ASSERT(!hermite.hasOffsetZ()); - - float offset = hermite.getOffsetX(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, offset, offsetTol); - - Vec3s n1 = hermite.getNormalX(); - CPPUNIT_ASSERT(n0.eq(n1, normalTol)); - - // y - n0 = Vec3s(0.0, 1.0, 0.0); - hermite.setY(0.3f, n0); - CPPUNIT_ASSERT(hermite.hasOffsetX()); - CPPUNIT_ASSERT(hermite.hasOffsetY()); - CPPUNIT_ASSERT(!hermite.hasOffsetZ()); - - offset = hermite.getOffsetY(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.3, offset, offsetTol); - - n1 = hermite.getNormalY(); - CPPUNIT_ASSERT(n0.eq(n1, normalTol)); - - // z - n0 = Vec3s(0.0, 0.0, 1.0); - hermite.setZ(0.75f, n0); - CPPUNIT_ASSERT(hermite.hasOffsetX()); - CPPUNIT_ASSERT(hermite.hasOffsetY()); - CPPUNIT_ASSERT(hermite.hasOffsetZ()); - - offset = hermite.getOffsetZ(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.75, offset, offsetTol); - - n1 = hermite.getNormalZ(); - CPPUNIT_ASSERT(n0.eq(n1, normalTol)); - - - ////////// - - // Check inside/outside state - - hermite.setIsInside(true); - CPPUNIT_ASSERT(hermite.isInside()); - - hermite.clear(); - - CPPUNIT_ASSERT(!hermite); - CPPUNIT_ASSERT(!hermite.isInside()); - - CPPUNIT_ASSERT(!hermite.hasOffsetX()); - CPPUNIT_ASSERT(!hermite.hasOffsetY()); - CPPUNIT_ASSERT(!hermite.hasOffsetZ()); - - n0 = Vec3s(0.0, 0.0, -1.0); - hermite.setZ(0.15f, n0); - CPPUNIT_ASSERT(!hermite.hasOffsetX()); - CPPUNIT_ASSERT(!hermite.hasOffsetY()); - CPPUNIT_ASSERT(hermite.hasOffsetZ()); - - offset = hermite.getOffsetZ(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.15, offset, offsetTol); - - n1 = hermite.getNormalZ(); - CPPUNIT_ASSERT(n0.eq(n1, normalTol)); - - hermite.setIsInside(true); - CPPUNIT_ASSERT(hermite.isInside()); - - CPPUNIT_ASSERT(hermite); -} - - -//////////////////////////////////////// - - -void -TestHermite::testComparisons() -{ - using namespace openvdb; - using namespace openvdb::math; - const double offsetTol = 0.001; - const float normalTol = 0.015f; - - - ////////// - - - Vec3s offsets(0.50f, 0.82f, 0.14f); - Vec3s nX(1.0, 0.0, 0.0); - Vec3s nY(0.0, 1.0, 0.0); - Vec3s nZ(0.0, 0.0, 1.0); - - Hermite A, B; - - A.setX(offsets[0], nX); - A.setY(offsets[1], nY); - A.setZ(offsets[2], nZ); - A.setIsInside(true); - - B = A; - - CPPUNIT_ASSERT(B); - CPPUNIT_ASSERT(B == A); - CPPUNIT_ASSERT(!(B != A)); - CPPUNIT_ASSERT(B.isInside()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[0], B.getOffsetX(), offsetTol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[1], B.getOffsetY(), offsetTol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[2], B.getOffsetZ(), offsetTol); - - CPPUNIT_ASSERT(B.getNormalX().eq(nX, normalTol)); - CPPUNIT_ASSERT(B.getNormalY().eq(nY, normalTol)); - CPPUNIT_ASSERT(B.getNormalZ().eq(nZ, normalTol)); - - CPPUNIT_ASSERT(!A.isLessX(B)); - CPPUNIT_ASSERT(!A.isLessY(B)); - CPPUNIT_ASSERT(!A.isLessZ(B)); - - CPPUNIT_ASSERT(!A.isGreaterX(B)); - CPPUNIT_ASSERT(!A.isGreaterY(B)); - CPPUNIT_ASSERT(!A.isGreaterZ(B)); - - B = -B; - - CPPUNIT_ASSERT(B); - CPPUNIT_ASSERT(B != A); - CPPUNIT_ASSERT(!B.isInside()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[0], B.getOffsetX(), offsetTol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[1], B.getOffsetY(), offsetTol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(offsets[2], B.getOffsetZ(), offsetTol); - - CPPUNIT_ASSERT(B.getNormalX().eq(-nX, normalTol)); - CPPUNIT_ASSERT(B.getNormalY().eq(-nY, normalTol)); - CPPUNIT_ASSERT(B.getNormalZ().eq(-nZ, normalTol)); - - CPPUNIT_ASSERT(A.isLessX(B)); - CPPUNIT_ASSERT(A.isLessY(B)); - CPPUNIT_ASSERT(A.isLessZ(B)); - - CPPUNIT_ASSERT(!A.isGreaterX(B)); - CPPUNIT_ASSERT(!A.isGreaterY(B)); - CPPUNIT_ASSERT(!A.isGreaterZ(B)); - - - ////////// - - // min / max - - Hermite C = min(A, B); - - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C == A); - CPPUNIT_ASSERT(C != B); - - C = max(A, B); - - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C != A); - CPPUNIT_ASSERT(C == B); - - - A.clear(); - B.clear(); - C.clear(); - - A.setX(offsets[0], nX); - A.setY(offsets[1], nY); - A.setZ(offsets[2], nZ); - A.setIsInside(true); - - B.setX(offsets[2], nX); - B.setY(offsets[0], nY); - B.setZ(offsets[1], nZ); - B.setIsInside(true); - - C = max(A, B); - - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C != A); - CPPUNIT_ASSERT(C != B); - CPPUNIT_ASSERT(C.isGreaterX(A)); - CPPUNIT_ASSERT(C.isGreaterY(A)); - CPPUNIT_ASSERT(C.isGreaterZ(B)); - - C = min(A, B); - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C != A); - CPPUNIT_ASSERT(C != B); - CPPUNIT_ASSERT(C.isLessX(B)); - CPPUNIT_ASSERT(C.isLessY(B)); - CPPUNIT_ASSERT(C.isLessZ(A)); - - - A.clear(); - B.clear(); - C.clear(); - - - A.setY(offsets[1], nY); - A.setZ(offsets[2], nZ); - - B.setX(offsets[2], nX); - B.setY(offsets[0], nY); - - C = min(A, B); - - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C != A); - CPPUNIT_ASSERT(C != B); - - CPPUNIT_ASSERT(!C.hasOffsetX()); - CPPUNIT_ASSERT(C.hasOffsetY()); - CPPUNIT_ASSERT(!C.hasOffsetZ()); - - CPPUNIT_ASSERT(C.isLessY(A)); - - C = max(A, B); - - CPPUNIT_ASSERT(C); - CPPUNIT_ASSERT(C != A); - CPPUNIT_ASSERT(C != B); - - CPPUNIT_ASSERT(C.hasOffsetX()); - CPPUNIT_ASSERT(C.hasOffsetY()); - CPPUNIT_ASSERT(C.hasOffsetZ()); - - CPPUNIT_ASSERT(C.isGreaterX(A)); - CPPUNIT_ASSERT(C.isGreaterY(B)); - CPPUNIT_ASSERT(C.isGreaterZ(B)); -} - - -//////////////////////////////////////// - - -void -TestHermite::testIO() -{ - using namespace openvdb; - using namespace openvdb::math; - - std::stringstream - ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - Hermite A, B; - - A.setX(0.50f, Vec3s(1.0, 0.0, 0.0)); - A.setY(0.82f, Vec3s(0.0, 1.0, 0.0)); - A.setZ(0.14f, Vec3s(0.0, 0.0, 1.0)); - A.setIsInside(true); - - CPPUNIT_ASSERT(A); - CPPUNIT_ASSERT(!B); - - A.write(ss); - - B.read(ss); - - CPPUNIT_ASSERT(A); - CPPUNIT_ASSERT(B); - - CPPUNIT_ASSERT(A == B); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestInit.cc b/openvdb_3_0_0_library/unittest/TestInit.cc deleted file mode 100755 index b95b917..0000000 --- a/openvdb_3_0_0_library/unittest/TestInit.cc +++ /dev/null @@ -1,122 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - - -class TestInit: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestInit); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestInit); - - -void -TestInit::test() -{ - using namespace openvdb; - - initialize(); - - // data types - CPPUNIT_ASSERT(DoubleMetadata::isRegisteredType()); - CPPUNIT_ASSERT(FloatMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Int32Metadata::isRegisteredType()); - CPPUNIT_ASSERT(Int64Metadata::isRegisteredType()); - CPPUNIT_ASSERT(StringMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec2IMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec2SMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec2DMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec3IMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec3SMetadata::isRegisteredType()); - CPPUNIT_ASSERT(Vec3DMetadata::isRegisteredType()); - - // map types - CPPUNIT_ASSERT(math::AffineMap::isRegistered()); - CPPUNIT_ASSERT(math::UnitaryMap::isRegistered()); - CPPUNIT_ASSERT(math::ScaleMap::isRegistered()); - CPPUNIT_ASSERT(math::TranslationMap::isRegistered()); - CPPUNIT_ASSERT(math::ScaleTranslateMap::isRegistered()); - CPPUNIT_ASSERT(math::NonlinearFrustumMap::isRegistered()); - - // grid types - CPPUNIT_ASSERT(BoolGrid::isRegistered()); - CPPUNIT_ASSERT(FloatGrid::isRegistered()); - CPPUNIT_ASSERT(DoubleGrid::isRegistered()); - CPPUNIT_ASSERT(Int32Grid::isRegistered()); - CPPUNIT_ASSERT(Int64Grid::isRegistered()); - CPPUNIT_ASSERT(StringGrid::isRegistered()); - CPPUNIT_ASSERT(Vec3IGrid::isRegistered()); - CPPUNIT_ASSERT(Vec3SGrid::isRegistered()); - CPPUNIT_ASSERT(Vec3DGrid::isRegistered()); - - uninitialize(); - - CPPUNIT_ASSERT(!DoubleMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!FloatMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Int32Metadata::isRegisteredType()); - CPPUNIT_ASSERT(!Int64Metadata::isRegisteredType()); - CPPUNIT_ASSERT(!StringMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec2IMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec2SMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec2DMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec3IMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec3SMetadata::isRegisteredType()); - CPPUNIT_ASSERT(!Vec3DMetadata::isRegisteredType()); - - CPPUNIT_ASSERT(!math::AffineMap::isRegistered()); - CPPUNIT_ASSERT(!math::UnitaryMap::isRegistered()); - CPPUNIT_ASSERT(!math::ScaleMap::isRegistered()); - CPPUNIT_ASSERT(!math::TranslationMap::isRegistered()); - CPPUNIT_ASSERT(!math::ScaleTranslateMap::isRegistered()); - CPPUNIT_ASSERT(!math::NonlinearFrustumMap::isRegistered()); - - CPPUNIT_ASSERT(!BoolGrid::isRegistered()); - CPPUNIT_ASSERT(!FloatGrid::isRegistered()); - CPPUNIT_ASSERT(!DoubleGrid::isRegistered()); - CPPUNIT_ASSERT(!Int32Grid::isRegistered()); - CPPUNIT_ASSERT(!Int64Grid::isRegistered()); - CPPUNIT_ASSERT(!StringGrid::isRegistered()); - CPPUNIT_ASSERT(!Vec3IGrid::isRegistered()); - CPPUNIT_ASSERT(!Vec3SGrid::isRegistered()); - CPPUNIT_ASSERT(!Vec3DGrid::isRegistered()); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestInt32Metadata.cc b/openvdb_3_0_0_library/unittest/TestInt32Metadata.cc deleted file mode 100755 index 1421f52..0000000 --- a/openvdb_3_0_0_library/unittest/TestInt32Metadata.cc +++ /dev/null @@ -1,74 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestInt32Metadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestInt32Metadata); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestInt32Metadata); - -void -TestInt32Metadata::test() -{ - using namespace openvdb; - - Metadata::Ptr m(new Int32Metadata(123)); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("int32") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("int32") == 0); - - Int32Metadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == 123); - s->value() = 456; - CPPUNIT_ASSERT(s->value() == 456); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value() == 456); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestInt64Metadata.cc b/openvdb_3_0_0_library/unittest/TestInt64Metadata.cc deleted file mode 100755 index 002b2e7..0000000 --- a/openvdb_3_0_0_library/unittest/TestInt64Metadata.cc +++ /dev/null @@ -1,74 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestInt64Metadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestInt64Metadata); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestInt64Metadata); - -void -TestInt64Metadata::test() -{ - using namespace openvdb; - - Metadata::Ptr m(new Int64Metadata(123)); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("int64") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("int64") == 0); - - Int64Metadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == 123); - s->value() = 456; - CPPUNIT_ASSERT(s->value() == 456); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value() == 456); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestInternalOrigin.cc b/openvdb_3_0_0_library/unittest/TestInternalOrigin.cc deleted file mode 100755 index b341c9d..0000000 --- a/openvdb_3_0_0_library/unittest/TestInternalOrigin.cc +++ /dev/null @@ -1,106 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -class TestInternalOrigin: public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestInternalOrigin); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestInternalOrigin); - -void -TestInternalOrigin::test() -{ - std::set indices; - indices.insert(openvdb::Coord( 0, 0, 0)); - indices.insert(openvdb::Coord( 1, 0, 0)); - indices.insert(openvdb::Coord( 0,100, 8)); - indices.insert(openvdb::Coord(-9, 0, 8)); - indices.insert(openvdb::Coord(32, 0, 16)); - indices.insert(openvdb::Coord(33, -5, 16)); - indices.insert(openvdb::Coord(42,707,-35)); - indices.insert(openvdb::Coord(43, 17, 64)); - - typedef openvdb::tree::Tree4::Type FloatTree4; - FloatTree4 tree(0.0f); - std::set::iterator iter=indices.begin(); - for (int n = 0; iter != indices.end(); ++n, ++iter) { - tree.setValue(*iter, float(1.0 + float(n) * 0.5f)); - } - - openvdb::Coord C3, G; - typedef FloatTree4::RootNodeType Node0; - typedef Node0::ChildNodeType Node1; - typedef Node1::ChildNodeType Node2; - typedef Node2::LeafNodeType Node3; - for (Node0::ChildOnCIter iter0=tree.root().cbeginChildOn(); iter0; ++iter0) {//internal 1 - openvdb::Coord C0=iter0->origin(); - iter0.getCoord(G); - CPPUNIT_ASSERT_EQUAL(C0,G); - for (Node1::ChildOnCIter iter1=iter0->cbeginChildOn(); iter1; ++iter1) {//internal 2 - openvdb::Coord C1=iter1->origin(); - iter1.getCoord(G); - CPPUNIT_ASSERT_EQUAL(C1,G); - CPPUNIT_ASSERT(C0 <= C1); - CPPUNIT_ASSERT(C1 <= C0 + openvdb::Coord(Node1::DIM,Node1::DIM,Node1::DIM)); - for (Node2::ChildOnCIter iter2=iter1->cbeginChildOn(); iter2; ++iter2) {//leafs - openvdb::Coord C2=iter2->origin(); - iter2.getCoord(G); - CPPUNIT_ASSERT_EQUAL(C2,G); - CPPUNIT_ASSERT(C1 <= C2); - CPPUNIT_ASSERT(C2 <= C1 + openvdb::Coord(Node2::DIM,Node2::DIM,Node2::DIM)); - for (Node3::ValueOnCIter iter3=iter2->cbeginValueOn(); iter3; ++iter3) {//leaf voxels - iter3.getCoord(G); - iter = indices.find(G); - CPPUNIT_ASSERT(iter != indices.end()); - indices.erase(iter); - } - } - } - } - CPPUNIT_ASSERT(indices.size() == 0); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLaplacian.cc b/openvdb_3_0_0_library/unittest/TestLaplacian.cc deleted file mode 100755 index 10a3f11..0000000 --- a/openvdb_3_0_0_library/unittest/TestLaplacian.cc +++ /dev/null @@ -1,497 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestLaplacian: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestLaplacian); - CPPUNIT_TEST(testISLaplacian); // Laplacian in Index Space - CPPUNIT_TEST(testISLaplacianStencil); - CPPUNIT_TEST(testWSLaplacian); // Laplacian in World Space - CPPUNIT_TEST(testWSLaplacianFrustum); // Laplacian in World Space - CPPUNIT_TEST(testWSLaplacianStencil); - CPPUNIT_TEST(testLaplacianTool); // Laplacian tool - CPPUNIT_TEST(testLaplacianMaskedTool); // Laplacian tool - CPPUNIT_TEST(testOldStyleStencils); // old stencil impl - CPPUNIT_TEST_SUITE_END(); - - void testISLaplacian(); - void testISLaplacianStencil(); - void testWSLaplacian(); - void testWSLaplacianFrustum(); - void testWSLaplacianStencil(); - void testLaplacianTool(); - void testLaplacianMaskedTool(); - void testOldStyleStencils(); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLaplacian); - -void -TestLaplacian::testISLaplacian() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64,64,64); - const Coord c(35,30,40); - const openvdb::Vec3f - center(static_cast(c[0]), static_cast(c[1]), static_cast(c[2])); - const float radius=0.0f;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - Coord xyz(35,10,40); - - // Index Space Laplacian random access - FloatGrid::ConstAccessor inAccessor = grid->getConstAccessor(); - FloatGrid::ValueType result; - result = math::ISLaplacian::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); - - result = math::ISLaplacian::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); - - result = math::ISLaplacian::result(inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); -} - - -void -TestLaplacian::testISLaplacianStencil() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64,64,64); - const Coord c(35,30,40); - const openvdb::Vec3f - center(static_cast(c[0]), static_cast(c[1]), static_cast(c[2])); - const float radius=0;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - Coord xyz(35,10,40); - - // Index Space Laplacian stencil access - FloatGrid::ValueType result; - - math::SevenPointStencil sevenpt(*grid); - sevenpt.moveTo(xyz); - result = math::ISLaplacian::result(sevenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); - - math::ThirteenPointStencil thirteenpt(*grid); - thirteenpt.moveTo(xyz); - result = math::ISLaplacian::result(thirteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); - - math::NineteenPointStencil nineteenpt(*grid); - nineteenpt.moveTo(xyz); - result = math::ISLaplacian::result(nineteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20.0, result, /*tolerance=*/0.01); -} - - -void -TestLaplacian::testWSLaplacian() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64,64,64); - const Coord c(35,30,40); - const openvdb::Vec3f - center(static_cast(c[0]), static_cast(c[1]), static_cast(c[2])); - const float radius=0.0f;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - Coord xyz(35,10,40); - - FloatGrid::ValueType result; - FloatGrid::ConstAccessor inAccessor = grid->getConstAccessor(); - - // try with a map - math::UniformScaleMap map; - math::MapBase::Ptr rotated_map = map.preRotate(1.5, math::X_AXIS); - // verify the new map is an affine map - CPPUNIT_ASSERT(rotated_map->type() == math::AffineMap::mapType()); - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - - // the laplacian is invariant to rotation - result = math::Laplacian::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result( - *affine_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - // test uniform map - math::UniformScaleMap uniform; - - result = math::Laplacian::result( - uniform, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result( - uniform, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result( - uniform, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - // test the GenericMap Grid interface - { - math::GenericMap generic_map(*grid); - result = math::Laplacian::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - result = math::Laplacian::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - } - { - // test the GenericMap Transform interface - math::GenericMap generic_map(grid->transform()); - result = math::Laplacian::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - } - { - // test the GenericMap Map interface - math::GenericMap generic_map(rotated_map); - result = math::Laplacian::result( - generic_map, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - } - -} - - -void -TestLaplacian::testWSLaplacianFrustum() -{ - using namespace openvdb; - - // Create a Frustum Map: - - openvdb::BBoxd bbox(Vec3d(0), Vec3d(100)); - math::NonlinearFrustumMap frustum(bbox, 1./6., 5); - /// frustum will have depth, far plane - near plane = 5 - /// the frustum has width 1 in the front and 6 in the back - - math::Vec3d trans(2,2,2); - math::NonlinearFrustumMap::Ptr map = - boost::static_pointer_cast( - frustum.preScale(Vec3d(10,10,10))->postTranslate(trans)); - - CPPUNIT_ASSERT(!map->hasUniformScale()); - - math::Vec3d result; - result = map->voxelSize(); - - CPPUNIT_ASSERT( math::isApproxEqual(result.x(), 0.1)); - CPPUNIT_ASSERT( math::isApproxEqual(result.y(), 0.1)); - CPPUNIT_ASSERT( math::isApproxEqual(result.z(), 0.5, 0.0001)); - - - // Create a tree - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/0.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - // Load cos(x)sin(y)cos(z) - Coord ijk(10,10,10); - for (Int32& i=ijk.x(); i < 20; ++i) { - for (Int32& j=ijk.y(); j < 20; ++j) { - for (Int32& k=ijk.z(); k < 20; ++k) { - // world space image of the ijk coord - const Vec3d ws = map->applyMap(ijk.asVec3d()); - const float value = float(cos(ws.x() ) * sin( ws.y()) * cos(ws.z())); - tree.setValue(ijk, value); - } - } - } - - const Coord testloc(16,16,16); - float test_result = math::Laplacian::result( - *map, tree, testloc); - float expected_result = -3.f * tree.getValue(testloc); - - // The exact solution of Laplacian( cos(x)sin(y)cos(z) ) = -3 cos(x) sin(y) cos(z) - - CPPUNIT_ASSERT( math::isApproxEqual(test_result, expected_result, /*tolerance=*/0.02f) ); -} - - -void -TestLaplacian::testWSLaplacianStencil() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64,64,64); - const Coord c(35,30,40); - const openvdb::Vec3f - center(static_cast(c[0]), static_cast(c[1]), static_cast(c[2])); - const float radius=0.0f;//point at {35,30,40} - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - Coord xyz(35,10,40); - - FloatGrid::ValueType result; - - // try with a map - math::UniformScaleMap map; - math::MapBase::Ptr rotated_map = map.preRotate(1.5, math::X_AXIS); - // verify the new map is an affine map - CPPUNIT_ASSERT(rotated_map->type() == math::AffineMap::mapType()); - math::AffineMap::Ptr affine_map = - boost::static_pointer_cast(rotated_map); - - // the laplacian is invariant to rotation - math::SevenPointStencil sevenpt(*grid); - math::ThirteenPointStencil thirteenpt(*grid); - math::NineteenPointStencil nineteenpt(*grid); - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - math::SixthOrderDenseStencil dense_6th(*grid); - sevenpt.moveTo(xyz); - thirteenpt.moveTo(xyz); - nineteenpt.moveTo(xyz); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - result = math::Laplacian::result(*affine_map, dense_2nd); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result(*affine_map, dense_4th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result(*affine_map, dense_6th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - // test uniform map - math::UniformScaleMap uniform; - - result = math::Laplacian::result(uniform, sevenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result(uniform, thirteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - result = math::Laplacian::result(uniform, nineteenpt); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - // test the GenericMap Grid interface - { - math::GenericMap generic_map(*grid); - result = math::Laplacian::result(generic_map, dense_2nd); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - result = math::Laplacian::result(generic_map, dense_4th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - } - { - // test the GenericMap Transform interface - math::GenericMap generic_map(grid->transform()); - result = math::Laplacian::result(generic_map, dense_2nd); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - - } - { - // test the GenericMap Map interface - math::GenericMap generic_map(rotated_map); - result = math::Laplacian::result(generic_map, dense_2nd); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/20., result, /*tolerance=*/0.01); - } -} - - -void -TestLaplacian::testOldStyleStencils() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(/*voxel size=*/0.5)); - CPPUNIT_ASSERT(grid->empty()); - - const Coord dim(32, 32, 32); - const Coord c(35,30,40); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - - math::GradStencil gs(*grid); - math::WenoStencil ws(*grid); - math::CurvatureStencil cs(*grid); - - Coord xyz(20,16,20);//i.e. 8 voxel or 4 world units away from the center - gs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/4.0, gs.laplacian(), 0.01);// 2/distance from center - - ws.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/4.0, ws.laplacian(), 0.01);// 2/distance from center - - cs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/4.0, cs.laplacian(), 0.01);// 2/distance from center - - xyz.reset(12,16,10);//i.e. 10 voxel or 5 world units away from the center - gs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/5.0, gs.laplacian(), 0.01);// 2/distance from center - - ws.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/5.0, ws.laplacian(), 0.01);// 2/distance from center - - cs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0/5.0, cs.laplacian(), 0.01);// 2/distance from center -} - - -void -TestLaplacian::testLaplacianTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64, 64, 64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - FloatGrid::Ptr lap = tools::laplacian(*grid); - CPPUNIT_ASSERT_EQUAL(int(tree.activeVoxelCount()), int(lap->activeVoxelCount())); - - Coord xyz(35,30,30); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 2.0/10.0, lap->getConstAccessor().getValue(xyz), 0.01);// 2/distance from center - - xyz.reset(35,10,40); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 2.0/20.0, lap->getConstAccessor().getValue(xyz),0.01);// 2/distance from center -} - -void -TestLaplacian::testLaplacianMaskedTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const Coord dim(64, 64, 64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - BoolGrid::Ptr maskGrid = BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - - FloatGrid::Ptr lap = tools::laplacian(*grid, *maskGrid); - - {// outside the masked region - Coord xyz(34,30,30); - - CPPUNIT_ASSERT(!maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 0, lap->getConstAccessor().getValue(xyz), 0.01);// 2/distance from center - - xyz.reset(35,10,40); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 0, lap->getConstAccessor().getValue(xyz),0.01);// 2/distance from center - } - - {// inside the masked region - Coord xyz(35,30,30); - - CPPUNIT_ASSERT(maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 2.0/10.0, lap->getConstAccessor().getValue(xyz), 0.01);// 2/distance from center - - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLeaf.cc b/openvdb_3_0_0_library/unittest/TestLeaf.cc deleted file mode 100755 index 910b335..0000000 --- a/openvdb_3_0_0_library/unittest/TestLeaf.cc +++ /dev/null @@ -1,313 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestLeaf: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestLeaf); - CPPUNIT_TEST(testBuffer); - CPPUNIT_TEST(testGetValue); - CPPUNIT_TEST(testSetValue); - CPPUNIT_TEST(testIsValueSet); - CPPUNIT_TEST(testProbeValue); - CPPUNIT_TEST(testIterators); - CPPUNIT_TEST(testEquivalence); - CPPUNIT_TEST(testGetOrigin); - CPPUNIT_TEST(testIteratorGetCoord); - CPPUNIT_TEST(testNegativeIndexing); - CPPUNIT_TEST_SUITE_END(); - - void testBuffer(); - void testGetValue(); - void testSetValue(); - void testIsValueSet(); - void testProbeValue(); - void testIterators(); - void testEquivalence(); - void testGetOrigin(); - void testIteratorGetCoord(); - void testNegativeIndexing(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeaf); - -typedef openvdb::tree::LeafNode LeafType; -typedef LeafType::Buffer BufferType; -using openvdb::Index; - -void -TestLeaf::testBuffer() -{ - {// access - BufferType buf; - - for (Index i = 0; i < BufferType::size(); ++i) { - buf.mData[i] = i; - CPPUNIT_ASSERT(buf[i] == buf.mData[i]); - } - for (Index i = 0; i < BufferType::size(); ++i) { - buf[i] = i; - CPPUNIT_ASSERT_EQUAL(int(i), buf[i]); - } - } - - {// swap - BufferType buf0, buf1, buf2; - - int *buf0Data = buf0.mData; - int *buf1Data = buf1.mData; - - for (Index i = 0; i < BufferType::size(); ++i) { - buf0[i] = i; - buf1[i] = i * 2; - } - - buf0.swap(buf1); - - CPPUNIT_ASSERT(buf0.mData == buf1Data); - CPPUNIT_ASSERT(buf1.mData == buf0Data); - - buf1.swap(buf0); - - CPPUNIT_ASSERT(buf0.mData == buf0Data); - CPPUNIT_ASSERT(buf1.mData == buf1Data); - - buf0.swap(buf2); - - CPPUNIT_ASSERT(buf2.mData == buf0Data); - - buf2.swap(buf0); - - CPPUNIT_ASSERT(buf0.mData == buf0Data); - } - -} - -void -TestLeaf::testGetValue() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - - leaf.mBuffer[0] = 2; - leaf.mBuffer[1] = 3; - leaf.mBuffer[2] = 4; - leaf.mBuffer[65] = 10; - - CPPUNIT_ASSERT_EQUAL(2, leaf.getValue(openvdb::Coord(0, 0, 0))); - CPPUNIT_ASSERT_EQUAL(3, leaf.getValue(openvdb::Coord(0, 0, 1))); - CPPUNIT_ASSERT_EQUAL(4, leaf.getValue(openvdb::Coord(0, 0, 2))); - - CPPUNIT_ASSERT_EQUAL(10, leaf.getValue(openvdb::Coord(1, 0, 1))); -} - -void -TestLeaf::testSetValue() -{ - LeafType leaf(openvdb::Coord(0, 0, 0), 3); - - openvdb::Coord xyz(0, 0, 0); - leaf.setValueOn(xyz, 10); - CPPUNIT_ASSERT_EQUAL(10, leaf.getValue(xyz)); - - xyz.reset(7, 7, 7); - leaf.setValueOn(xyz, 7); - CPPUNIT_ASSERT_EQUAL(7, leaf.getValue(xyz)); - leaf.setValueOnly(xyz, 10); - CPPUNIT_ASSERT_EQUAL(10, leaf.getValue(xyz)); - - xyz.reset(2, 3, 6); - leaf.setValueOn(xyz, 236); - CPPUNIT_ASSERT_EQUAL(236, leaf.getValue(xyz)); - - leaf.setValueOff(xyz, 1); - CPPUNIT_ASSERT_EQUAL(1, leaf.getValue(xyz)); - CPPUNIT_ASSERT(!leaf.isValueOn(xyz)); -} - -void -TestLeaf::testIsValueSet() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - leaf.setValueOn(openvdb::Coord(1, 5, 7), 10); - - CPPUNIT_ASSERT(leaf.isValueOn(openvdb::Coord(1, 5, 7))); - - CPPUNIT_ASSERT(!leaf.isValueOn(openvdb::Coord(0, 5, 7))); - CPPUNIT_ASSERT(!leaf.isValueOn(openvdb::Coord(1, 6, 7))); - CPPUNIT_ASSERT(!leaf.isValueOn(openvdb::Coord(0, 5, 6))); -} - -void -TestLeaf::testProbeValue() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - leaf.setValueOn(openvdb::Coord(1, 6, 5), 10); - - LeafType::ValueType val; - CPPUNIT_ASSERT(leaf.probeValue(openvdb::Coord(1, 6, 5), val)); - CPPUNIT_ASSERT(!leaf.probeValue(openvdb::Coord(1, 6, 4), val)); -} - -void -TestLeaf::testIterators() -{ - LeafType leaf(openvdb::Coord(0, 0, 0), 2); - leaf.setValueOn(openvdb::Coord(1, 2, 3), -3); - leaf.setValueOn(openvdb::Coord(5, 2, 3), 4); - LeafType::ValueType sum = 0; - for (LeafType::ValueOnIter iter = leaf.beginValueOn(); iter; ++iter) sum += *iter; - CPPUNIT_ASSERT_EQUAL((-3 + 4), sum); -} - -void -TestLeaf::testEquivalence() -{ - LeafType leaf( openvdb::Coord(0, 0, 0), 2); - LeafType leaf2(openvdb::Coord(0, 0, 0), 3); - - CPPUNIT_ASSERT(leaf != leaf2); - - for(openvdb::Index32 i = 0; i < LeafType::size(); ++i) { - leaf.setValueOnly(i, i); - leaf2.setValueOnly(i, i); - } - CPPUNIT_ASSERT(leaf == leaf2); - - // set some values. - leaf.setValueOn(openvdb::Coord(0, 0, 0), 1); - leaf.setValueOn(openvdb::Coord(0, 1, 0), 1); - leaf.setValueOn(openvdb::Coord(1, 1, 0), 1); - leaf.setValueOn(openvdb::Coord(1, 1, 2), 1); - - leaf2.setValueOn(openvdb::Coord(0, 0, 0), 1); - leaf2.setValueOn(openvdb::Coord(0, 1, 0), 1); - leaf2.setValueOn(openvdb::Coord(1, 1, 0), 1); - leaf2.setValueOn(openvdb::Coord(1, 1, 2), 1); - - CPPUNIT_ASSERT(leaf == leaf2); - - leaf2.setValueOn(openvdb::Coord(0, 0, 1), 1); - - CPPUNIT_ASSERT(leaf != leaf2); - - leaf2.setValueOff(openvdb::Coord(0, 0, 1), 1); - - CPPUNIT_ASSERT(leaf == leaf2); -} - -void -TestLeaf::testGetOrigin() -{ - { - LeafType leaf(openvdb::Coord(1, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(0, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(8, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(8, 1, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(1024, 1, 3), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(128*8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(1023, 1, 3), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(127*8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(512, 512, 512), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(512, 512, 512), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(2, 52, 515), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 48, 512), leaf.origin()); - } -} - -void -TestLeaf::testIteratorGetCoord() -{ - using namespace openvdb; - - LeafType leaf(openvdb::Coord(8, 8, 0), 2); - - CPPUNIT_ASSERT_EQUAL(Coord(8, 8, 0), leaf.origin()); - - leaf.setValueOn(Coord(1, 2, 3), -3); - leaf.setValueOn(Coord(5, 2, 3), 4); - - LeafType::ValueOnIter iter = leaf.beginValueOn(); - Coord xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(9, 10, 3), xyz); - - ++iter; - xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(13, 10, 3), xyz); -} - -void -TestLeaf::testNegativeIndexing() -{ - using namespace openvdb; - - LeafType leaf(openvdb::Coord(-9, -2, -8), 1); - - CPPUNIT_ASSERT_EQUAL(Coord(-16, -8, -8), leaf.origin()); - - leaf.setValueOn(Coord(1, 2, 3), -3); - leaf.setValueOn(Coord(5, 2, 3), 4); - - CPPUNIT_ASSERT_EQUAL(-3, leaf.getValue(Coord(1, 2, 3))); - CPPUNIT_ASSERT_EQUAL(4, leaf.getValue(Coord(5, 2, 3))); - - LeafType::ValueOnIter iter = leaf.beginValueOn(); - Coord xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(-15, -6, -5), xyz); - - ++iter; - xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(-11, -6, -5), xyz); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLeafBool.cc b/openvdb_3_0_0_library/unittest/TestLeafBool.cc deleted file mode 100755 index d5c4ae9..0000000 --- a/openvdb_3_0_0_library/unittest/TestLeafBool.cc +++ /dev/null @@ -1,546 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - - -class TestLeafBool: public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestLeafBool); - CPPUNIT_TEST(testGetValue); - CPPUNIT_TEST(testSetValue); - CPPUNIT_TEST(testProbeValue); - CPPUNIT_TEST(testIterators); - CPPUNIT_TEST(testIteratorGetCoord); - CPPUNIT_TEST(testEquivalence); - CPPUNIT_TEST(testGetOrigin); - CPPUNIT_TEST(testNegativeIndexing); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testTopologyCopy); - CPPUNIT_TEST(testMerge); - CPPUNIT_TEST(testCombine); - CPPUNIT_TEST(testBoolTree); - //CPPUNIT_TEST(testFilter); - CPPUNIT_TEST_SUITE_END(); - - void testGetValue(); - void testSetValue(); - void testProbeValue(); - void testIterators(); - void testEquivalence(); - void testGetOrigin(); - void testIteratorGetCoord(); - void testNegativeIndexing(); - void testIO(); - void testTopologyCopy(); - void testMerge(); - void testCombine(); - void testBoolTree(); - //void testFilter(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafBool); - -typedef openvdb::tree::LeafNode LeafType; - - -//////////////////////////////////////// - - -void -TestLeafBool::testGetValue() -{ - { - LeafType leaf(openvdb::Coord(0, 0, 0), /*background=*/false); - for (openvdb::Index n = 0; n < leaf.numValues(); ++n) { - CPPUNIT_ASSERT_EQUAL(false, leaf.getValue(leaf.offsetToLocalCoord(n))); - } - } - { - LeafType leaf(openvdb::Coord(0, 0, 0), /*background=*/true); - for (openvdb::Index n = 0; n < leaf.numValues(); ++n) { - CPPUNIT_ASSERT_EQUAL(true, leaf.getValue(leaf.offsetToLocalCoord(n))); - } - } -} - - -void -TestLeafBool::testSetValue() -{ - LeafType leaf(openvdb::Coord(0, 0, 0), false); - - openvdb::Coord xyz(0, 0, 0); - CPPUNIT_ASSERT(!leaf.isValueOn(xyz)); - leaf.setValueOn(xyz); - CPPUNIT_ASSERT(leaf.isValueOn(xyz)); - - xyz.reset(7, 7, 7); - CPPUNIT_ASSERT(!leaf.isValueOn(xyz)); - leaf.setValueOn(xyz); - CPPUNIT_ASSERT(leaf.isValueOn(xyz)); - leaf.setValueOn(xyz, /*value=*/true); // value argument should be ignored - CPPUNIT_ASSERT(leaf.isValueOn(xyz)); - leaf.setValueOn(xyz, /*value=*/false); // value argument should be ignored - CPPUNIT_ASSERT(leaf.isValueOn(xyz)); - - leaf.setValueOff(xyz); - CPPUNIT_ASSERT(!leaf.isValueOn(xyz)); - - xyz.reset(2, 3, 6); - leaf.setValueOn(xyz); - CPPUNIT_ASSERT(leaf.isValueOn(xyz)); - - leaf.setValueOff(xyz); - CPPUNIT_ASSERT(!leaf.isValueOn(xyz)); -} - - -void -TestLeafBool::testProbeValue() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - leaf.setValueOn(openvdb::Coord(1, 6, 5)); - - bool val; - CPPUNIT_ASSERT(leaf.probeValue(openvdb::Coord(1, 6, 5), val)); - CPPUNIT_ASSERT(!leaf.probeValue(openvdb::Coord(1, 6, 4), val)); -} - - -void -TestLeafBool::testIterators() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - leaf.setValueOn(openvdb::Coord(1, 2, 3)); - leaf.setValueOn(openvdb::Coord(5, 2, 3)); - openvdb::Coord sum; - for (LeafType::ValueOnIter iter = leaf.beginValueOn(); iter; ++iter) { - sum += iter.getCoord(); - } - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(1 + 5, 2 + 2, 3 + 3), sum); - - openvdb::Index count = 0; - for (LeafType::ValueOffIter iter = leaf.beginValueOff(); iter; ++iter, ++count); - CPPUNIT_ASSERT_EQUAL(leaf.numValues() - 2, count); - - count = 0; - for (LeafType::ValueAllIter iter = leaf.beginValueAll(); iter; ++iter, ++count); - CPPUNIT_ASSERT_EQUAL(leaf.numValues(), count); - - count = 0; - for (LeafType::ChildOnIter iter = leaf.beginChildOn(); iter; ++iter, ++count); - CPPUNIT_ASSERT_EQUAL(openvdb::Index(0), count); - - count = 0; - for (LeafType::ChildOffIter iter = leaf.beginChildOff(); iter; ++iter, ++count); - CPPUNIT_ASSERT_EQUAL(openvdb::Index(0), count); - - count = 0; - for (LeafType::ChildAllIter iter = leaf.beginChildAll(); iter; ++iter, ++count); - CPPUNIT_ASSERT_EQUAL(leaf.numValues(), count); -} - - -void -TestLeafBool::testIteratorGetCoord() -{ - using namespace openvdb; - - LeafType leaf(openvdb::Coord(8, 8, 0)); - - CPPUNIT_ASSERT_EQUAL(Coord(8, 8, 0), leaf.origin()); - - leaf.setValueOn(Coord(1, 2, 3), -3); - leaf.setValueOn(Coord(5, 2, 3), 4); - - LeafType::ValueOnIter iter = leaf.beginValueOn(); - Coord xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(9, 10, 3), xyz); - - ++iter; - xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(13, 10, 3), xyz); -} - - -void -TestLeafBool::testEquivalence() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - - LeafType leaf(Coord(0, 0, 0), false); // false and inactive - LeafType leaf2(Coord(0, 0, 0), true); // true and inactive - - CPPUNIT_ASSERT(leaf != leaf2); - - leaf.fill(CoordBBox(Coord(0), Coord(LeafType::DIM - 1)), true, /*active=*/false); - CPPUNIT_ASSERT(leaf == leaf2); // true and inactive - - leaf.setValuesOn(); // true and active - - leaf2.fill(CoordBBox(Coord(0), Coord(LeafType::DIM - 1)), false); // false and active - CPPUNIT_ASSERT(leaf != leaf2); - - leaf.negate(); // false and active - CPPUNIT_ASSERT(leaf == leaf2); - - // Set some values. - leaf.setValueOn(Coord(0, 0, 0), true); - leaf.setValueOn(Coord(0, 1, 0), true); - leaf.setValueOn(Coord(1, 1, 0), true); - leaf.setValueOn(Coord(1, 1, 2), true); - - leaf2.setValueOn(Coord(0, 0, 0), true); - leaf2.setValueOn(Coord(0, 1, 0), true); - leaf2.setValueOn(Coord(1, 1, 0), true); - leaf2.setValueOn(Coord(1, 1, 2), true); - - CPPUNIT_ASSERT(leaf == leaf2); - - leaf2.setValueOn(Coord(0, 0, 1), true); - - CPPUNIT_ASSERT(leaf != leaf2); - - leaf2.setValueOff(Coord(0, 0, 1), false); - - CPPUNIT_ASSERT(leaf != leaf2); - - leaf2.setValueOn(Coord(0, 0, 1)); - - CPPUNIT_ASSERT(leaf == leaf2); -} - - -void -TestLeafBool::testGetOrigin() -{ - { - LeafType leaf(openvdb::Coord(1, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(0, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(8, 0, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(8, 1, 0), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(1024, 1, 3), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(128*8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(1023, 1, 3), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(127*8, 0, 0), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(512, 512, 512), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(512, 512, 512), leaf.origin()); - } - { - LeafType leaf(openvdb::Coord(2, 52, 515), 1); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0, 48, 512), leaf.origin()); - } -} - - -void -TestLeafBool::testNegativeIndexing() -{ - using namespace openvdb; - - LeafType leaf(openvdb::Coord(-9, -2, -8)); - - CPPUNIT_ASSERT_EQUAL(Coord(-16, -8, -8), leaf.origin()); - - leaf.setValueOn(Coord(1, 2, 3)); - leaf.setValueOn(Coord(5, 2, 3)); - - CPPUNIT_ASSERT(leaf.isValueOn(Coord(1, 2, 3))); - CPPUNIT_ASSERT(leaf.isValueOn(Coord(5, 2, 3))); - - LeafType::ValueOnIter iter = leaf.beginValueOn(); - Coord xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(-15, -6, -5), xyz); - - ++iter; - xyz = iter.getCoord(); - CPPUNIT_ASSERT_EQUAL(Coord(-11, -6, -5), xyz); -} - - -void -TestLeafBool::testIO() -{ - LeafType leaf(openvdb::Coord(1, 3, 5)); - const openvdb::Coord origin = leaf.origin(); - - leaf.setValueOn(openvdb::Coord(0, 1, 0)); - leaf.setValueOn(openvdb::Coord(1, 0, 0)); - - std::ostringstream ostr(std::ios_base::binary); - - leaf.writeBuffers(ostr); - - leaf.setValueOff(openvdb::Coord(0, 1, 0)); - leaf.setValueOn(openvdb::Coord(0, 1, 1)); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - // Since the input stream doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(istr); - - leaf.readBuffers(istr); - - CPPUNIT_ASSERT_EQUAL(origin, leaf.origin()); - - CPPUNIT_ASSERT(leaf.isValueOn(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT(leaf.isValueOn(openvdb::Coord(1, 0, 0))); - - CPPUNIT_ASSERT(leaf.onVoxelCount() == 2); -} - - -void -TestLeafBool::testTopologyCopy() -{ - using openvdb::Coord; - - // LeafNode having the same Log2Dim as LeafType - typedef LeafType::ValueConverter::Type FloatLeafType; - - FloatLeafType fleaf(Coord(10, 20, 30), /*background=*/-1.0); - std::set coords; - for (openvdb::Index n = 0; n < fleaf.numValues(); n += 10) { - Coord xyz = fleaf.offsetToGlobalCoord(n); - fleaf.setValueOn(xyz, float(n)); - coords.insert(xyz); - } - - LeafType leaf(fleaf, openvdb::TopologyCopy()); - CPPUNIT_ASSERT_EQUAL(fleaf.onVoxelCount(), leaf.onVoxelCount()); - - CPPUNIT_ASSERT(leaf.hasSameTopology(&fleaf)); - - for (LeafType::ValueOnIter iter = leaf.beginValueOn(); iter; ++iter) { - coords.erase(iter.getCoord()); - } - CPPUNIT_ASSERT(coords.empty()); -} - - -void -TestLeafBool::testMerge() -{ - LeafType leaf(openvdb::Coord(0, 0, 0)); - for (openvdb::Index n = 0; n < leaf.numValues(); n += 10) { - leaf.setValueOn(n); - } - CPPUNIT_ASSERT(!leaf.isValueMaskOn()); - CPPUNIT_ASSERT(!leaf.isValueMaskOff()); - bool val = false, active = false; - CPPUNIT_ASSERT(!leaf.isConstant(val, active)); - - LeafType leaf2(leaf); - leaf2.getValueMask().toggle(); - CPPUNIT_ASSERT(!leaf2.isValueMaskOn()); - CPPUNIT_ASSERT(!leaf2.isValueMaskOff()); - val = active = false; - CPPUNIT_ASSERT(!leaf2.isConstant(val, active)); - - leaf.merge(leaf2); - CPPUNIT_ASSERT(leaf.isValueMaskOn()); - CPPUNIT_ASSERT(!leaf.isValueMaskOff()); - val = active = false; - CPPUNIT_ASSERT(leaf.isConstant(val, active)); - CPPUNIT_ASSERT(active); -} - - -void -TestLeafBool::testCombine() -{ - struct Local { - static void op(openvdb::CombineArgs& args) { - args.setResult(false); // result should be ignored - args.setResultIsActive(args.aIsActive() ^ args.bIsActive()); - } - }; - - LeafType leaf(openvdb::Coord(0, 0, 0)); - for (openvdb::Index n = 0; n < leaf.numValues(); n += 10) { - leaf.setValueOn(n); - } - CPPUNIT_ASSERT(!leaf.isValueMaskOn()); - CPPUNIT_ASSERT(!leaf.isValueMaskOff()); - const LeafType::NodeMaskType savedMask = leaf.getValueMask(); - OPENVDB_LOG_DEBUG_RUNTIME(leaf.str()); - - LeafType leaf2(leaf); - for (openvdb::Index n = 0; n < leaf.numValues(); n += 4) { - leaf2.setValueOn(n); - } - CPPUNIT_ASSERT(!leaf2.isValueMaskOn()); - CPPUNIT_ASSERT(!leaf2.isValueMaskOff()); - OPENVDB_LOG_DEBUG_RUNTIME(leaf2.str()); - - leaf.combine(leaf2, Local::op); - OPENVDB_LOG_DEBUG_RUNTIME(leaf.str()); - - CPPUNIT_ASSERT(leaf.getValueMask() == (savedMask ^ leaf2.getValueMask())); -} - - -void -TestLeafBool::testBoolTree() -{ - using namespace openvdb; - -#if 0 - FloatGrid::Ptr inGrid; - FloatTree::Ptr inTree; - { - //io::File vdbFile("/work/rd/fx_tools/vdb_unittest/TestGridCombine::testCsg/large1.vdb2"); - io::File vdbFile("/hosts/whitestar/usr/pic1/VDB/bunny_0256.vdb2"); - vdbFile.open(); - inGrid = gridPtrCast(vdbFile.readGrid("LevelSet")); - CPPUNIT_ASSERT(inGrid.get() != NULL); - inTree = inGrid->treePtr(); - CPPUNIT_ASSERT(inTree.get() != NULL); - } -#else - FloatGrid::Ptr inGrid = FloatGrid::create(); - CPPUNIT_ASSERT(inGrid.get() != NULL); - FloatTree& inTree = inGrid->tree(); - inGrid->setName("LevelSet"); - - unittest_util::makeSphere(/*dim =*/Coord(128), - /*center=*/Vec3f(0, 0, 0), - /*radius=*/5, - *inGrid, unittest_util::SPHERE_DENSE); -#endif - - const Index64 - floatTreeMem = inTree.memUsage(), - floatTreeLeafCount = inTree.leafCount(), - floatTreeVoxelCount = inTree.activeVoxelCount(); - - TreeBase::Ptr outTree(new BoolTree(inTree, false, true, TopologyCopy())); - CPPUNIT_ASSERT(outTree.get() != NULL); - - BoolGrid::Ptr outGrid = BoolGrid::create(*inGrid); // copy transform and metadata - outGrid->setTree(outTree); - outGrid->setName("Boolean"); - - const Index64 - boolTreeMem = outTree->memUsage(), - boolTreeLeafCount = outTree->leafCount(), - boolTreeVoxelCount = outTree->activeVoxelCount(); - -#if 0 - GridPtrVec grids; - grids.push_back(inGrid); - grids.push_back(outGrid); - io::File vdbFile("/tmp/bool_tree.vdb2"); - vdbFile.write(grids); - vdbFile.close(); -#endif - - CPPUNIT_ASSERT_EQUAL(floatTreeLeafCount, boolTreeLeafCount); - CPPUNIT_ASSERT_EQUAL(floatTreeVoxelCount, boolTreeVoxelCount); - - //std::cerr << "\nboolTree mem=" << boolTreeMem << " bytes" << std::endl; - //std::cerr << "floatTree mem=" << floatTreeMem << " bytes" << std::endl; - - // Considering only voxel buffer memory usage, the BoolTree would be expected - // to use (2 mask bits/voxel / ((32 value bits + 1 mask bit)/voxel)) = ~1/16 - // as much memory as the FloatTree. Considering total memory usage, verify that - // the BoolTree is no more than 1/10 the size of the FloatTree. - CPPUNIT_ASSERT(boolTreeMem * 10 <= floatTreeMem); -} - - -// void -// TestLeafBool::testFilter() -// { -// using namespace openvdb; - -// BoolGrid::Ptr grid = BoolGrid::create(); -// CPPUNIT_ASSERT(grid.get() != NULL); -// BoolTree::Ptr tree = grid->treePtr(); -// CPPUNIT_ASSERT(tree.get() != NULL); -// grid->setName("filtered"); - -// unittest_util::makeSphere(/*dim=*/Coord(32), -// /*ctr=*/Vec3f(0, 0, 0), -// /*radius=*/10, -// *grid, unittest_util::SPHERE_DENSE); - -// BoolTree::Ptr copyOfTree(new BoolTree(*tree)); -// BoolGrid::Ptr copyOfGrid = BoolGrid::create(copyOfTree); -// copyOfGrid->setName("original"); - -// tools::Filter filter(*grid); -// filter.offset(1); - -// #if 0 -// GridPtrVec grids; -// grids.push_back(copyOfGrid); -// grids.push_back(grid); -// io::File vdbFile("/tmp/TestLeafBool::testFilter.vdb2"); -// vdbFile.write(grids); -// vdbFile.close(); -// #endif - -// // Verify that offsetting all active voxels by 1 (true) has no effect, -// // since the active voxels were all true to begin with. -// CPPUNIT_ASSERT(tree->hasSameTopology(*copyOfTree)); -// } - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLeafIO.cc b/openvdb_3_0_0_library/unittest/TestLeafIO.cc deleted file mode 100755 index 2b6600a..0000000 --- a/openvdb_3_0_0_library/unittest/TestLeafIO.cc +++ /dev/null @@ -1,172 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include // for toupper() -#include -#include - -// CPPUNIT_TEST_SUITE() invokes CPPUNIT_TESTNAMER_DECL() to generate a suite name -// from the FixtureType. But if FixtureType is a templated type, the generated name -// can become long and messy. This macro overrides the normal naming logic, -// instead invoking FixtureType::testSuiteName(), which should be a static member -// function that returns a std::string containing the suite name for the specific -// template instantiation. -#undef CPPUNIT_TESTNAMER_DECL -#define CPPUNIT_TESTNAMER_DECL( variableName, FixtureType ) \ - CPPUNIT_NS::TestNamer variableName( FixtureType::testSuiteName() ) - - -template -class TestLeafIO: public CppUnit::TestCase -{ -public: - static std::string testSuiteName() - { - std::string name = openvdb::typeNameAsString(); - if (!name.empty()) name[0] = static_cast(::toupper(name[0])); - return "TestLeafIO" + name; - } - - CPPUNIT_TEST_SUITE(TestLeafIO); - CPPUNIT_TEST(testBuffer); - CPPUNIT_TEST_SUITE_END(); - - void testBuffer(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafIO); - - -template -void -TestLeafIO::testBuffer() -{ - openvdb::tree::LeafNode leaf(openvdb::Coord(0, 0, 0)); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), T(1)); - leaf.setValueOn(openvdb::Coord(1, 0, 0), T(1)); - - std::ostringstream ostr(std::ios_base::binary); - - leaf.writeBuffers(ostr); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), T(0)); - leaf.setValueOn(openvdb::Coord(0, 1, 1), T(1)); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - // Since the input stream doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(istr); - - leaf.readBuffers(istr); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(T(1), leaf.getValue(openvdb::Coord(0, 1, 0)), /*tolerance=*/0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(T(1), leaf.getValue(openvdb::Coord(1, 0, 0)), /*tolerance=*/0); - - CPPUNIT_ASSERT(leaf.onVoxelCount() == 2); -} - - -template<> -void -TestLeafIO::testBuffer() -{ - openvdb::tree::LeafNode - leaf(openvdb::Coord(0, 0, 0), std::string()); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), std::string("test")); - leaf.setValueOn(openvdb::Coord(1, 0, 0), std::string("test")); - - std::ostringstream ostr(std::ios_base::binary); - - leaf.writeBuffers(ostr); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), std::string("douche")); - leaf.setValueOn(openvdb::Coord(0, 1, 1), std::string("douche")); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - // Since the input stream doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(istr); - - leaf.readBuffers(istr); - - CPPUNIT_ASSERT_EQUAL(std::string("test"), leaf.getValue(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT_EQUAL(std::string("test"), leaf.getValue(openvdb::Coord(1, 0, 0))); - - CPPUNIT_ASSERT(leaf.onVoxelCount() == 2); -} - - -template<> -void -TestLeafIO::testBuffer() -{ - openvdb::tree::LeafNode leaf(openvdb::Coord(0, 0, 0)); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), openvdb::Vec3R(1, 1, 1)); - leaf.setValueOn(openvdb::Coord(1, 0, 0), openvdb::Vec3R(1, 1, 1)); - - std::ostringstream ostr(std::ios_base::binary); - - leaf.writeBuffers(ostr); - - leaf.setValueOn(openvdb::Coord(0, 1, 0), openvdb::Vec3R(0, 0, 0)); - leaf.setValueOn(openvdb::Coord(0, 1, 1), openvdb::Vec3R(1, 1, 1)); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - // Since the input stream doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(istr); - - leaf.readBuffers(istr); - - CPPUNIT_ASSERT(leaf.getValue(openvdb::Coord(0, 1, 0)) == openvdb::Vec3R(1, 1, 1)); - CPPUNIT_ASSERT(leaf.getValue(openvdb::Coord(1, 0, 0)) == openvdb::Vec3R(1, 1, 1)); - - CPPUNIT_ASSERT(leaf.onVoxelCount() == 2); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLeafOrigin.cc b/openvdb_3_0_0_library/unittest/TestLeafOrigin.cc deleted file mode 100755 index 41f9149..0000000 --- a/openvdb_3_0_0_library/unittest/TestLeafOrigin.cc +++ /dev/null @@ -1,138 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include - - -class TestLeafOrigin: public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestLeafOrigin); - CPPUNIT_TEST(test); - CPPUNIT_TEST(test2Values); - CPPUNIT_TEST(testGetValue); - CPPUNIT_TEST_SUITE_END(); - - void test(); - void test2Values(); - void testGetValue(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLeafOrigin); - - -//////////////////////////////////////// - - -void -TestLeafOrigin::test() -{ - using namespace openvdb; - - std::set indices; - indices.insert(Coord( 0, 0, 0)); - indices.insert(Coord( 1, 0, 0)); - indices.insert(Coord( 0, 100, 8)); - indices.insert(Coord(-9, 0, 8)); - indices.insert(Coord(32, 0, 16)); - indices.insert(Coord(33, -5, 16)); - indices.insert(Coord(42, 17, 35)); - indices.insert(Coord(43, 17, 64)); - - FloatTree tree(/*bg=*/256.0); - std::set::iterator iter = indices.begin(); - for ( ; iter != indices.end(); ++iter) tree.setValue(*iter, 1.0); - - for (FloatTree::LeafCIter leafIter = tree.cbeginLeaf(); leafIter; ++leafIter) { - const Int32 mask = ~((1 << leafIter->log2dim()) - 1); - const Coord leafOrigin = leafIter->origin(); - for (FloatTree::LeafNodeType::ValueOnCIter valIter = leafIter->cbeginValueOn(); - valIter; ++valIter) - { - Coord xyz = valIter.getCoord(); - CPPUNIT_ASSERT_EQUAL(leafOrigin, xyz & mask); - - iter = indices.find(xyz); - CPPUNIT_ASSERT(iter != indices.end()); - indices.erase(iter); - } - } - CPPUNIT_ASSERT(indices.empty()); -} - - -void -TestLeafOrigin::test2Values() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*bg=*/1.0f); - FloatTree& tree = grid->tree(); - - tree.setValue(Coord(0, 0, 0), 5); - tree.setValue(Coord(100, 0, 0), 6); - - grid->setTransform(math::Transform::createLinearTransform(0.1)); - - FloatTree::LeafCIter iter = tree.cbeginLeaf(); - CPPUNIT_ASSERT_EQUAL(Coord(0, 0, 0), iter->origin()); - ++iter; - CPPUNIT_ASSERT_EQUAL(Coord(96, 0, 0), iter->origin()); -} - -void -TestLeafOrigin::testGetValue() -{ - const openvdb::Coord c0(0,-10,0), c1(100,13,0); - const float v0=5.0f, v1=6.0f, v2=1.0f; - openvdb::FloatTree::Ptr tree(new openvdb::FloatTree(v2)); - - tree->setValue(c0, v0); - tree->setValue(c1, v1); - - openvdb::FloatTree::LeafCIter iter = tree->cbeginLeaf(); - CPPUNIT_ASSERT_EQUAL(v0, iter->getValue(c0)); - ++iter; - CPPUNIT_ASSERT_EQUAL(v1, iter->getValue(c1)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLevelSetRayIntersector.cc b/openvdb_3_0_0_library/unittest/TestLevelSetRayIntersector.cc deleted file mode 100755 index 6a56535..0000000 --- a/openvdb_3_0_0_library/unittest/TestLevelSetRayIntersector.cc +++ /dev/null @@ -1,416 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -/// @author Ken Museth - -// Uncomment to enable statistics of ray-intersections -//#define STATS_TEST - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for Film -#ifdef STATS_TEST -//only needed for statistics -#include -#include -#include -#endif - - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -#define ASSERT_DOUBLES_APPROX_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/1.e-6); - - -class TestLevelSetRayIntersector : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestLevelSetRayIntersector); - CPPUNIT_TEST(tests); - -#ifdef STATS_TEST - CPPUNIT_TEST(stats); -#endif - - CPPUNIT_TEST_SUITE_END(); - - void tests(); -#ifdef STATS_TEST - void stats(); -#endif -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLevelSetRayIntersector); - -void -TestLevelSetRayIntersector::tests() -{ - using namespace openvdb; - typedef math::Ray RayT; - typedef RayT::Vec3Type Vec3T; - - {// voxel intersection against a level set sphere - const float r = 5.0f; - const Vec3f c(20.0f, 0.0f, 0.0f); - const float s = 0.5f, w = 2.0f; - - FloatGrid::Ptr ls = tools::createLevelSetSphere(r, c, s, w); - - tools::LevelSetRayIntersector lsri(*ls); - - const Vec3T dir(1.0, 0.0, 0.0); - const Vec3T eye(2.0, 0.0, 0.0); - const RayT ray(eye, dir); - //std::cerr << ray << std::endl; - Vec3T xyz(0); - Real time = 0; - CPPUNIT_ASSERT(lsri.intersectsWS(ray, xyz, time)); - ASSERT_DOUBLES_APPROX_EQUAL(15.0, xyz[0]); - ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[1]); - ASSERT_DOUBLES_APPROX_EQUAL( 0.0, xyz[2]); - ASSERT_DOUBLES_APPROX_EQUAL(13.0, time); - double t0=0, t1=0; - CPPUNIT_ASSERT(ray.intersects(c, r, t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL(t0, time); - //std::cerr << "\nray("< 0.01) { - film.pixel(i, j) = tools::Film::RGBA(1.0f, 0.0f, 0.0f); - } else { - film.pixel(i, j) = tools::Film::RGBA(0.0f, 1.0f, 0.0f); - } - } - } - } - timer.stop(); - - film.savePPM("/tmp/sphere_serial"); - stats.print("First hit"); - hist.print("First hit"); - } -} -#endif // STATS_TEST - -#undef STATS_TEST - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLevelSetUtil.cc b/openvdb_3_0_0_library/unittest/TestLevelSetUtil.cc deleted file mode 100755 index efb8869..0000000 --- a/openvdb_3_0_0_library/unittest/TestLevelSetUtil.cc +++ /dev/null @@ -1,102 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include -#include -#include - -class TestLevelSetUtil: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestLevelSetUtil); - CPPUNIT_TEST(testMinMaxVoxel); - CPPUNIT_TEST(testLevelSetToFogVolume); - CPPUNIT_TEST_SUITE_END(); - - void testMinMaxVoxel(); - void testRelativeIsoOffset(); - void testLevelSetToFogVolume(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLevelSetUtil); - - -//////////////////////////////////////// - - -void -TestLevelSetUtil::testMinMaxVoxel() -{ - - openvdb::FloatTree myTree(std::numeric_limits::max()); - - openvdb::tree::ValueAccessor acc(myTree); - - for (int i = -9; i < 10; ++i) { - for (int j = -9; j < 10; ++j) { - acc.setValue(openvdb::Coord(i,j,0), static_cast(j)); - } - } - - openvdb::tree::LeafManager leafs(myTree); - - openvdb::tools::MinMaxVoxel minmax(leafs); - minmax.runParallel(); - - CPPUNIT_ASSERT(!(minmax.minVoxel() < -9.0)); - CPPUNIT_ASSERT(!(minmax.maxVoxel() > 9.0)); -} - -void -TestLevelSetUtil::testLevelSetToFogVolume() -{ - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(10.0); - - grid->fill(openvdb::CoordBBox(openvdb::Coord(-100), openvdb::Coord(100)), 9.0); - grid->fill(openvdb::CoordBBox(openvdb::Coord(-50), openvdb::Coord(50)), -9.0); - - - openvdb::tools::sdfToFogVolume(*grid); - - CPPUNIT_ASSERT(grid->background() < 1e-7); - - openvdb::FloatGrid::ValueOnIter iter = grid->beginValueOn(); - for (; iter; ++iter) { - CPPUNIT_ASSERT(iter.getValue() > 0.0); - CPPUNIT_ASSERT(std::abs(iter.getValue() - 1.0) < 1e-7); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestLinearInterp.cc b/openvdb_3_0_0_library/unittest/TestLinearInterp.cc deleted file mode 100755 index 47f5708..0000000 --- a/openvdb_3_0_0_library/unittest/TestLinearInterp.cc +++ /dev/null @@ -1,1003 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -// CPPUNIT_TEST_SUITE() invokes CPPUNIT_TESTNAMER_DECL() to generate a suite name -// from the FixtureType. But if FixtureType is a templated type, the generated name -// can become long and messy. This macro overrides the normal naming logic, -// instead invoking FixtureType::testSuiteName(), which should be a static member -// function that returns a std::string containing the suite name for the specific -// template instantiation. -#undef CPPUNIT_TESTNAMER_DECL -#define CPPUNIT_TESTNAMER_DECL( variableName, FixtureType ) \ - CPPUNIT_NS::TestNamer variableName( FixtureType::testSuiteName() ) - -namespace { -// Absolute tolerance for floating-point equality comparisons -const double TOLERANCE = 1.e-6; -} - -template -class TestLinearInterp: public CppUnit::TestCase -{ -public: - static std::string testSuiteName() - { - std::string name = openvdb::typeNameAsString(); - if (!name.empty()) name[0] = static_cast(::toupper(name[0])); - return "TestLinearInterp" + name; - } - - CPPUNIT_TEST_SUITE(TestLinearInterp); - CPPUNIT_TEST(test); - CPPUNIT_TEST(testTree); - CPPUNIT_TEST(testAccessor); - CPPUNIT_TEST(testConstantValues); - CPPUNIT_TEST(testFillValues); - CPPUNIT_TEST(testNegativeIndices); - CPPUNIT_TEST_SUITE_END(); - - void test(); - void testTree(); - void testAccessor(); - void testConstantValues(); - void testFillValues(); - void testNegativeIndices(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestLinearInterp); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLinearInterp); -CPPUNIT_TEST_SUITE_REGISTRATION(TestLinearInterp); - - -template -void -TestLinearInterp::test() -{ - typename GridType::TreeType TreeType; - float fillValue = 256.0f; - - GridType grid(fillValue); - typename GridType::TreeType& tree = grid.tree(); - - tree.setValue(openvdb::Coord(10, 10, 10), 1.0); - - tree.setValue(openvdb::Coord(11, 10, 10), 2.0); - tree.setValue(openvdb::Coord(11, 11, 10), 2.0); - tree.setValue(openvdb::Coord(10, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 10, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 9, 10), 2.0); - tree.setValue(openvdb::Coord(10, 9, 10), 2.0); - tree.setValue(openvdb::Coord(11, 9, 10), 2.0); - - tree.setValue(openvdb::Coord(10, 10, 11), 3.0); - tree.setValue(openvdb::Coord(11, 10, 11), 3.0); - tree.setValue(openvdb::Coord(11, 11, 11), 3.0); - tree.setValue(openvdb::Coord(10, 11, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 11, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 10, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 9, 11), 3.0); - tree.setValue(openvdb::Coord(10, 9, 11), 3.0); - tree.setValue(openvdb::Coord(11, 9, 11), 3.0); - - tree.setValue(openvdb::Coord(10, 10, 9), 4.0); - tree.setValue(openvdb::Coord(11, 10, 9), 4.0); - tree.setValue(openvdb::Coord(11, 11, 9), 4.0); - tree.setValue(openvdb::Coord(10, 11, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 11, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 10, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 9, 9), 4.0); - tree.setValue(openvdb::Coord(10, 9, 9), 4.0); - tree.setValue(openvdb::Coord(11, 9, 9), 4.0); - - // transform used for worldspace interpolation) - openvdb::tools::GridSampler - interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - typename GridType::ValueType val = - interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.375, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.1, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.792, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.71, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.01, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::test() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3SGrid grid(fillValue); - Vec3STree& tree = grid.tree(); - - tree.setValue(openvdb::Coord(10, 10, 10), Vec3s(1.0, 1.0, 1.0)); - - tree.setValue(openvdb::Coord(11, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 9, 10), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(10, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(10, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 9, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(10, 9, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 9, 11), Vec3s(3.0, 3.0, 3.0)); - - tree.setValue(openvdb::Coord(10, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(10, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 9, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(10, 9, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 9, 9), Vec3s(4.0, 4.0, 4.0)); - - openvdb::tools::GridSampler - interpolator(grid); - - //openvdb::tools::LinearInterp interpolator(*tree); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.375f))); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.f))); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT(val.eq(Vec3s(3.f))); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.f))); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.f))); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.1f))); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.792f))); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.71f))); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(2.01f))); -} - -template -void -TestLinearInterp::testTree() -{ - float fillValue = 256.0f; - typedef typename GridType::TreeType TreeType; - TreeType tree(fillValue); - - tree.setValue(openvdb::Coord(10, 10, 10), 1.0); - - tree.setValue(openvdb::Coord(11, 10, 10), 2.0); - tree.setValue(openvdb::Coord(11, 11, 10), 2.0); - tree.setValue(openvdb::Coord(10, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 10, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 9, 10), 2.0); - tree.setValue(openvdb::Coord(10, 9, 10), 2.0); - tree.setValue(openvdb::Coord(11, 9, 10), 2.0); - - tree.setValue(openvdb::Coord(10, 10, 11), 3.0); - tree.setValue(openvdb::Coord(11, 10, 11), 3.0); - tree.setValue(openvdb::Coord(11, 11, 11), 3.0); - tree.setValue(openvdb::Coord(10, 11, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 11, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 10, 11), 3.0); - tree.setValue(openvdb::Coord( 9, 9, 11), 3.0); - tree.setValue(openvdb::Coord(10, 9, 11), 3.0); - tree.setValue(openvdb::Coord(11, 9, 11), 3.0); - - tree.setValue(openvdb::Coord(10, 10, 9), 4.0); - tree.setValue(openvdb::Coord(11, 10, 9), 4.0); - tree.setValue(openvdb::Coord(11, 11, 9), 4.0); - tree.setValue(openvdb::Coord(10, 11, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 11, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 10, 9), 4.0); - tree.setValue(openvdb::Coord( 9, 9, 9), 4.0); - tree.setValue(openvdb::Coord(10, 9, 9), 4.0); - tree.setValue(openvdb::Coord(11, 9, 9), 4.0); - - // transform used for worldspace interpolation) - openvdb::tools::GridSampler - interpolator(tree, openvdb::math::Transform()); - - typename GridType::ValueType val = - interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.375, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.1, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.792, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.71, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.01, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::testTree() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3STree tree(fillValue); - - tree.setValue(openvdb::Coord(10, 10, 10), Vec3s(1.0, 1.0, 1.0)); - - tree.setValue(openvdb::Coord(11, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 9, 10), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(10, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(10, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 11, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 10, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( 9, 9, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(10, 9, 11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(11, 9, 11), Vec3s(3.0, 3.0, 3.0)); - - tree.setValue(openvdb::Coord(10, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(10, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 11, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 10, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( 9, 9, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(10, 9, 9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(11, 9, 9), Vec3s(4.0, 4.0, 4.0)); - - openvdb::tools::GridSampler - interpolator(tree, openvdb::math::Transform()); - - //openvdb::tools::LinearInterp interpolator(*tree); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.375f))); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.f))); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT(val.eq(Vec3s(3.f))); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.f))); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.f))); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.1f))); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.792f))); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.71f))); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(2.01f))); -} - -template -void -TestLinearInterp::testAccessor() -{ - float fillValue = 256.0f; - - GridType grid(fillValue); - typedef typename GridType::Accessor AccessorType; - - AccessorType acc = grid.getAccessor(); - - acc.setValue(openvdb::Coord(10, 10, 10), 1.0); - - acc.setValue(openvdb::Coord(11, 10, 10), 2.0); - acc.setValue(openvdb::Coord(11, 11, 10), 2.0); - acc.setValue(openvdb::Coord(10, 11, 10), 2.0); - acc.setValue(openvdb::Coord( 9, 11, 10), 2.0); - acc.setValue(openvdb::Coord( 9, 10, 10), 2.0); - acc.setValue(openvdb::Coord( 9, 9, 10), 2.0); - acc.setValue(openvdb::Coord(10, 9, 10), 2.0); - acc.setValue(openvdb::Coord(11, 9, 10), 2.0); - - acc.setValue(openvdb::Coord(10, 10, 11), 3.0); - acc.setValue(openvdb::Coord(11, 10, 11), 3.0); - acc.setValue(openvdb::Coord(11, 11, 11), 3.0); - acc.setValue(openvdb::Coord(10, 11, 11), 3.0); - acc.setValue(openvdb::Coord( 9, 11, 11), 3.0); - acc.setValue(openvdb::Coord( 9, 10, 11), 3.0); - acc.setValue(openvdb::Coord( 9, 9, 11), 3.0); - acc.setValue(openvdb::Coord(10, 9, 11), 3.0); - acc.setValue(openvdb::Coord(11, 9, 11), 3.0); - - acc.setValue(openvdb::Coord(10, 10, 9), 4.0); - acc.setValue(openvdb::Coord(11, 10, 9), 4.0); - acc.setValue(openvdb::Coord(11, 11, 9), 4.0); - acc.setValue(openvdb::Coord(10, 11, 9), 4.0); - acc.setValue(openvdb::Coord( 9, 11, 9), 4.0); - acc.setValue(openvdb::Coord( 9, 10, 9), 4.0); - acc.setValue(openvdb::Coord( 9, 9, 9), 4.0); - acc.setValue(openvdb::Coord(10, 9, 9), 4.0); - acc.setValue(openvdb::Coord(11, 9, 9), 4.0); - - // transform used for worldspace interpolation) - openvdb::tools::GridSampler - interpolator(acc, grid.transform()); - - typename GridType::ValueType val = - interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.375, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.1, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.792, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.71, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.01, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::testAccessor() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3SGrid grid(fillValue); - typedef Vec3SGrid::Accessor AccessorType; - AccessorType acc = grid.getAccessor(); - - acc.setValue(openvdb::Coord(10, 10, 10), Vec3s(1.0, 1.0, 1.0)); - - acc.setValue(openvdb::Coord(11, 10, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord(11, 11, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord(10, 11, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord( 9, 11, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord( 9, 10, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord( 9, 9, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord(10, 9, 10), Vec3s(2.0, 2.0, 2.0)); - acc.setValue(openvdb::Coord(11, 9, 10), Vec3s(2.0, 2.0, 2.0)); - - acc.setValue(openvdb::Coord(10, 10, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord(11, 10, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord(11, 11, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord(10, 11, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord( 9, 11, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord( 9, 10, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord( 9, 9, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord(10, 9, 11), Vec3s(3.0, 3.0, 3.0)); - acc.setValue(openvdb::Coord(11, 9, 11), Vec3s(3.0, 3.0, 3.0)); - - acc.setValue(openvdb::Coord(10, 10, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord(11, 10, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord(11, 11, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord(10, 11, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord( 9, 11, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord( 9, 10, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord( 9, 9, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord(10, 9, 9), Vec3s(4.0, 4.0, 4.0)); - acc.setValue(openvdb::Coord(11, 9, 9), Vec3s(4.0, 4.0, 4.0)); - - openvdb::tools::GridSampler - interpolator(acc, grid.transform()); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.375f))); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.0f))); - - val = interpolator.sampleVoxel(11.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0f))); - - val = interpolator.sampleVoxel(11.0, 11.0, 11.0); - CPPUNIT_ASSERT(val.eq(Vec3s(3.0f))); - - val = interpolator.sampleVoxel(9.0, 11.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.0f))); - - val = interpolator.sampleVoxel(9.0, 10.0, 9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.0f))); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.1f))); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.792f))); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.71f))); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(2.01f))); -} - -template -void -TestLinearInterp::testConstantValues() -{ - typedef typename GridType::TreeType TreeType; - float fillValue = 256.0f; - - GridType grid(fillValue); - TreeType& tree = grid.tree(); - - // Add values to buffer zero. - tree.setValue(openvdb::Coord(10, 10, 10), 2.0); - - tree.setValue(openvdb::Coord(11, 10, 10), 2.0); - tree.setValue(openvdb::Coord(11, 11, 10), 2.0); - tree.setValue(openvdb::Coord(10, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 11, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 10, 10), 2.0); - tree.setValue(openvdb::Coord( 9, 9, 10), 2.0); - tree.setValue(openvdb::Coord(10, 9, 10), 2.0); - tree.setValue(openvdb::Coord(11, 9, 10), 2.0); - - tree.setValue(openvdb::Coord(10, 10, 11), 2.0); - tree.setValue(openvdb::Coord(11, 10, 11), 2.0); - tree.setValue(openvdb::Coord(11, 11, 11), 2.0); - tree.setValue(openvdb::Coord(10, 11, 11), 2.0); - tree.setValue(openvdb::Coord( 9, 11, 11), 2.0); - tree.setValue(openvdb::Coord( 9, 10, 11), 2.0); - tree.setValue(openvdb::Coord( 9, 9, 11), 2.0); - tree.setValue(openvdb::Coord(10, 9, 11), 2.0); - tree.setValue(openvdb::Coord(11, 9, 11), 2.0); - - tree.setValue(openvdb::Coord(10, 10, 9), 2.0); - tree.setValue(openvdb::Coord(11, 10, 9), 2.0); - tree.setValue(openvdb::Coord(11, 11, 9), 2.0); - tree.setValue(openvdb::Coord(10, 11, 9), 2.0); - tree.setValue(openvdb::Coord( 9, 11, 9), 2.0); - tree.setValue(openvdb::Coord( 9, 10, 9), 2.0); - tree.setValue(openvdb::Coord( 9, 9, 9), 2.0); - tree.setValue(openvdb::Coord(10, 9, 9), 2.0); - tree.setValue(openvdb::Coord(11, 9, 9), 2.0); - - openvdb::tools::GridSampler interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - typename GridType::ValueType val = - interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::testConstantValues() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3SGrid grid(fillValue); - Vec3STree& tree = grid.tree(); - - // Add values to buffer zero. - tree.setValue(openvdb::Coord(10, 10, 10), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(11, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 11, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 10, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 9, 10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 9, 10), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(10, 10, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 10, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 11, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 11, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 11, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 10, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 9, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 9, 11), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 9, 11), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(10, 10, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 10, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 11, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 11, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 11, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 10, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( 9, 9, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(10, 9, 9), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(11, 9, 9), Vec3s(2.0, 2.0, 2.0)); - - openvdb::tools::GridSampler interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0, 2.0, 2.0))); -} - - -template -void -TestLinearInterp::testFillValues() -{ - //typedef typename GridType::TreeType TreeType; - float fillValue = 256.0f; - - GridType grid(fillValue); - //typename GridType::TreeType& tree = grid.tree(); - - openvdb::tools::GridSampler - interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - typename GridType::ValueType val = - interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(256.0, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::testFillValues() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3SGrid grid(fillValue); - //Vec3STree& tree = grid.tree(); - - openvdb::tools::GridSampler - interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(10.5, 10.5, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.0, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.1, 10.0, 10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.8, 10.8, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.1, 10.8, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.8, 10.1, 10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.5, 10.1, 10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); - - val = interpolator.sampleVoxel(10.5, 10.8, 10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(256.0, 256.0, 256.0))); -} - - -template -void -TestLinearInterp::testNegativeIndices() -{ - typedef typename GridType::TreeType TreeType; - float fillValue = 256.0f; - - GridType grid(fillValue); - TreeType& tree = grid.tree(); - - tree.setValue(openvdb::Coord(-10, -10, -10), 1.0); - - tree.setValue(openvdb::Coord(-11, -10, -10), 2.0); - tree.setValue(openvdb::Coord(-11, -11, -10), 2.0); - tree.setValue(openvdb::Coord(-10, -11, -10), 2.0); - tree.setValue(openvdb::Coord( -9, -11, -10), 2.0); - tree.setValue(openvdb::Coord( -9, -10, -10), 2.0); - tree.setValue(openvdb::Coord( -9, -9, -10), 2.0); - tree.setValue(openvdb::Coord(-10, -9, -10), 2.0); - tree.setValue(openvdb::Coord(-11, -9, -10), 2.0); - - tree.setValue(openvdb::Coord(-10, -10, -11), 3.0); - tree.setValue(openvdb::Coord(-11, -10, -11), 3.0); - tree.setValue(openvdb::Coord(-11, -11, -11), 3.0); - tree.setValue(openvdb::Coord(-10, -11, -11), 3.0); - tree.setValue(openvdb::Coord( -9, -11, -11), 3.0); - tree.setValue(openvdb::Coord( -9, -10, -11), 3.0); - tree.setValue(openvdb::Coord( -9, -9, -11), 3.0); - tree.setValue(openvdb::Coord(-10, -9, -11), 3.0); - tree.setValue(openvdb::Coord(-11, -9, -11), 3.0); - - tree.setValue(openvdb::Coord(-10, -10, -9), 4.0); - tree.setValue(openvdb::Coord(-11, -10, -9), 4.0); - tree.setValue(openvdb::Coord(-11, -11, -9), 4.0); - tree.setValue(openvdb::Coord(-10, -11, -9), 4.0); - tree.setValue(openvdb::Coord( -9, -11, -9), 4.0); - tree.setValue(openvdb::Coord( -9, -10, -9), 4.0); - tree.setValue(openvdb::Coord( -9, -9, -9), 4.0); - tree.setValue(openvdb::Coord(-10, -9, -9), 4.0); - tree.setValue(openvdb::Coord(-11, -9, -9), 4.0); - - //openvdb::tools::LinearInterp interpolator(*tree); - openvdb::tools::GridSampler interpolator(grid); - - typename GridType::ValueType val = - interpolator.sampleVoxel(-10.5, -10.5, -10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.375, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.0, -10.0, -10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-11.0, -10.0, -10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-11.0, -11.0, -10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-11.0, -11.0, -11.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-9.0, -11.0, -9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-9.0, -10.0, -9.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.1, -10.0, -10.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.1, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.8, -10.8, -10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.792, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.1, -10.8, -10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.8, -10.1, -10.5); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.41, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.5, -10.1, -10.8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.71, val, TOLERANCE); - - val = interpolator.sampleVoxel(-10.5, -10.8, -10.1); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.01, val, TOLERANCE); -} - - -template<> -void -TestLinearInterp::testNegativeIndices() -{ - using namespace openvdb; - - Vec3s fillValue = Vec3s(256.0f, 256.0f, 256.0f); - - Vec3SGrid grid(fillValue); - Vec3STree& tree = grid.tree(); - - tree.setValue(openvdb::Coord(-10, -10, -10), Vec3s(1.0, 1.0, 1.0)); - - tree.setValue(openvdb::Coord(-11, -10, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(-11, -11, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(-10, -11, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( -9, -11, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( -9, -10, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord( -9, -9, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(-10, -9, -10), Vec3s(2.0, 2.0, 2.0)); - tree.setValue(openvdb::Coord(-11, -9, -10), Vec3s(2.0, 2.0, 2.0)); - - tree.setValue(openvdb::Coord(-10, -10, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(-11, -10, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(-11, -11, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(-10, -11, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( -9, -11, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( -9, -10, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord( -9, -9, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(-10, -9, -11), Vec3s(3.0, 3.0, 3.0)); - tree.setValue(openvdb::Coord(-11, -9, -11), Vec3s(3.0, 3.0, 3.0)); - - tree.setValue(openvdb::Coord(-10, -10, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(-11, -10, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(-11, -11, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(-10, -11, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( -9, -11, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( -9, -10, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord( -9, -9, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(-10, -9, -9), Vec3s(4.0, 4.0, 4.0)); - tree.setValue(openvdb::Coord(-11, -9, -9), Vec3s(4.0, 4.0, 4.0)); - - openvdb::tools::GridSampler interpolator(grid); - //openvdb::tools::LinearInterp interpolator(*tree); - - Vec3SGrid::ValueType val = interpolator.sampleVoxel(-10.5, -10.5, -10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.375f))); - - val = interpolator.sampleVoxel(-10.0, -10.0, -10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.0f))); - - val = interpolator.sampleVoxel(-11.0, -10.0, -10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0f))); - - val = interpolator.sampleVoxel(-11.0, -11.0, -10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(2.0f))); - - val = interpolator.sampleVoxel(-11.0, -11.0, -11.0); - CPPUNIT_ASSERT(val.eq(Vec3s(3.0f))); - - val = interpolator.sampleVoxel(-9.0, -11.0, -9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.0f))); - - val = interpolator.sampleVoxel(-9.0, -10.0, -9.0); - CPPUNIT_ASSERT(val.eq(Vec3s(4.0f))); - - val = interpolator.sampleVoxel(-10.1, -10.0, -10.0); - CPPUNIT_ASSERT(val.eq(Vec3s(1.1f))); - - val = interpolator.sampleVoxel(-10.8, -10.8, -10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.792f))); - - val = interpolator.sampleVoxel(-10.1, -10.8, -10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(-10.8, -10.1, -10.5); - CPPUNIT_ASSERT(val.eq(Vec3s(2.41f))); - - val = interpolator.sampleVoxel(-10.5, -10.1, -10.8); - CPPUNIT_ASSERT(val.eq(Vec3s(2.71f))); - - val = interpolator.sampleVoxel(-10.5, -10.8, -10.1); - CPPUNIT_ASSERT(val.eq(Vec3s(2.01f))); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMaps.cc b/openvdb_3_0_0_library/unittest/TestMaps.cc deleted file mode 100755 index 2d94483..0000000 --- a/openvdb_3_0_0_library/unittest/TestMaps.cc +++ /dev/null @@ -1,834 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - - -class TestMaps: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestMaps); - CPPUNIT_TEST(testTranslation); - CPPUNIT_TEST(testRotation); - CPPUNIT_TEST(testScaleDefault); - CPPUNIT_TEST(testScaleTranslate); - CPPUNIT_TEST(testUniformScaleTranslate); - CPPUNIT_TEST(testDecomposition); - CPPUNIT_TEST(testFrustum); - CPPUNIT_TEST(testCalcBoundingBox); - CPPUNIT_TEST(testApproxInverse); - CPPUNIT_TEST(testUniformScale); - CPPUNIT_TEST(testJacobians); - CPPUNIT_TEST_SUITE_END(); - - void testTranslation(); - void testRotation(); - void testScaleDefault(); - void testScaleTranslate(); - void testUniformScaleTranslate(); - void testDecomposition(); - void testFrustum(); - void testCalcBoundingBox(); - void testApproxInverse(); - void testUniformScale(); - void testJacobians(); - //void testIsType(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMaps); - -void -TestMaps::testApproxInverse() -{ - using namespace openvdb::math; - - Mat4d singular = Mat4d::identity(); - singular[1][1] = 0.f; - { - Mat4d singularInv = approxInverse(singular); - - CPPUNIT_ASSERT( singular == singularInv ); - } - { - Mat4d rot = Mat4d::identity(); - rot.setToRotation(X_AXIS, M_PI/4.); - - Mat4d rotInv = rot.inverse(); - Mat4d mat = rotInv * singular * rot; - - Mat4d singularInv = approxInverse(mat); - - // this matrix is equal to its own singular inverse - CPPUNIT_ASSERT( mat == singularInv ); - - } - { - Mat4d m = Mat4d::identity(); - m[0][1] = 1; - - // should give true inverse, since this matrix has det=1 - Mat4d minv = approxInverse(m); - - Mat4d prod = m * minv; - CPPUNIT_ASSERT( prod.eq( Mat4d::identity() ) ); - } - { - Mat4d m = Mat4d::identity(); - m[0][1] = 1; - m[1][1] = 0; - // should give true inverse, since this matrix has det=1 - Mat4d minv = approxInverse(m); - - Mat4d expected = Mat4d::zero(); - expected[3][3] = 1; - CPPUNIT_ASSERT( minv.eq(expected ) ); - } - - -} - - -void -TestMaps::testUniformScale() -{ - using namespace openvdb::math; - - AffineMap map; - - CPPUNIT_ASSERT(map.hasUniformScale()); - - // Apply uniform scale: should still have square voxels - map.accumPreScale(Vec3d(2, 2, 2)); - - CPPUNIT_ASSERT(map.hasUniformScale()); - - // Apply a rotation, should still have squaure voxels. - map.accumPostRotation(X_AXIS, 2.5); - - CPPUNIT_ASSERT(map.hasUniformScale()); - - // non uniform scaling will stretch the voxels - map.accumPostScale(Vec3d(1, 3, 1) ); - - CPPUNIT_ASSERT(!map.hasUniformScale()); -} - -void -TestMaps::testTranslation() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - TranslationMap::Ptr translation(new TranslationMap(Vec3d(1,1,1))); - CPPUNIT_ASSERT(is_linear::value); - - TranslationMap another_translation(Vec3d(1,1,1)); - CPPUNIT_ASSERT(another_translation == *translation); - - TranslationMap::Ptr translate_by_two(new TranslationMap(Vec3d(2,2,2))); - - CPPUNIT_ASSERT(*translate_by_two != *translation); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(translate_by_two->determinant(), 1, TOL); - - CPPUNIT_ASSERT(translate_by_two->hasUniformScale()); - - /// apply the map forward - Vec3d unit(1,0,0); - Vec3d result = translate_by_two->applyMap(unit); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), 3, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), 2, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), 2, TOL); - - /// invert the map - result = translate_by_two->applyInverseMap(result); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), 0, TOL); - - /// Inverse Jacobian Transpose - result = translate_by_two->applyIJT(result); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), 0, TOL); - - /// Jacobian Transpose - result = translate_by_two->applyJT(translate_by_two->applyIJT(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - - - MapBase::Ptr inverse = translation->inverseMap(); - CPPUNIT_ASSERT(inverse->type() == TranslationMap::mapType()); - // apply the map forward and the inverse map back - result = inverse->applyMap(translation->applyMap(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), 0, TOL); - - -} - -void -TestMaps::testScaleDefault() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - // testing default constructor - // should be the identity - ScaleMap::Ptr scale(new ScaleMap()); - Vec3d unit(1, 1, 1); - - Vec3d result = scale->applyMap(unit); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(0), result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(1), result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(2), result(2), TOL); - - result = scale->applyInverseMap(unit); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(0), result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(1), result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(unit(2), result(2), TOL); - - - MapBase::Ptr inverse = scale->inverseMap(); - CPPUNIT_ASSERT(inverse->type() == ScaleMap::mapType()); - // apply the map forward and the inverse map back - result = inverse->applyMap(scale->applyMap(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - - -} - -void -TestMaps::testRotation() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - double pi = 4.*atan(1.); - UnitaryMap::Ptr rotation(new UnitaryMap(Vec3d(1,0,0), pi/2)); - - CPPUNIT_ASSERT(is_linear::value); - - UnitaryMap another_rotation(Vec3d(1,0,0), pi/2.); - CPPUNIT_ASSERT(another_rotation == *rotation); - - UnitaryMap::Ptr rotation_two(new UnitaryMap(Vec3d(1,0,0), pi/4.)); - - CPPUNIT_ASSERT(*rotation_two != *rotation); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(rotation->determinant(), 1, TOL); - - CPPUNIT_ASSERT(rotation_two->hasUniformScale()); - - /// apply the map forward - Vec3d unit(0,1,0); - Vec3d result = rotation->applyMap(unit); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(2), TOL); - - /// invert the map - result = rotation->applyInverseMap(result); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(2), TOL); - - /// Inverse Jacobian Transpose - result = rotation_two->applyIJT(result); // rotate backwards - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(sqrt(2.)/2, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(sqrt(2.)/2, result(2), TOL); - - /// Jacobian Transpose - result = rotation_two->applyJT(rotation_two->applyIJT(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - - - // Test inverse map - MapBase::Ptr inverse = rotation->inverseMap(); - CPPUNIT_ASSERT(inverse->type() == UnitaryMap::mapType()); - // apply the map forward and the inverse map back - result = inverse->applyMap(rotation->applyMap(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); -} - - -void -TestMaps::testScaleTranslate() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - CPPUNIT_ASSERT(is_linear::value); - - TranslationMap::Ptr translation(new TranslationMap(Vec3d(1,1,1))); - ScaleMap::Ptr scale(new ScaleMap(Vec3d(1,2,3))); - - ScaleTranslateMap::Ptr scaleAndTranslate( - new ScaleTranslateMap(*scale, *translation)); - - TranslationMap translate_by_two(Vec3d(2,2,2)); - ScaleTranslateMap another_scaleAndTranslate(*scale, translate_by_two); - - CPPUNIT_ASSERT(another_scaleAndTranslate != *scaleAndTranslate); - - CPPUNIT_ASSERT(!scaleAndTranslate->hasUniformScale()); - //CPPUNIT_ASSERT_DOUBLES_EQUAL(scaleAndTranslate->determinant(), 6, TOL); - - /// apply the map forward - Vec3d unit(1,0,0); - Vec3d result = scaleAndTranslate->applyMap(unit); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(2), TOL); - - /// invert the map - result = scaleAndTranslate->applyInverseMap(result); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(2), TOL); - - /// Inverse Jacobian Transpose - result = Vec3d(0,2,0); - result = scaleAndTranslate->applyIJT(result ); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(2), TOL); - - - /// Jacobian Transpose - result = scaleAndTranslate->applyJT(scaleAndTranslate->applyIJT(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - - - // Test inverse map - MapBase::Ptr inverse = scaleAndTranslate->inverseMap(); - CPPUNIT_ASSERT(inverse->type() == ScaleTranslateMap::mapType()); - // apply the map forward and the inverse map back - result = inverse->applyMap(scaleAndTranslate->applyMap(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - -} - - -void -TestMaps::testUniformScaleTranslate() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - CPPUNIT_ASSERT(is_linear::value); - CPPUNIT_ASSERT(is_linear::value); - - TranslationMap::Ptr translation(new TranslationMap(Vec3d(1,1,1))); - UniformScaleMap::Ptr scale(new UniformScaleMap(2)); - - UniformScaleTranslateMap::Ptr scaleAndTranslate( - new UniformScaleTranslateMap(*scale, *translation)); - - TranslationMap translate_by_two(Vec3d(2,2,2)); - UniformScaleTranslateMap another_scaleAndTranslate(*scale, translate_by_two); - - CPPUNIT_ASSERT(another_scaleAndTranslate != *scaleAndTranslate); - CPPUNIT_ASSERT(scaleAndTranslate->hasUniformScale()); - //CPPUNIT_ASSERT_DOUBLES_EQUAL(scaleAndTranslate->determinant(), 6, TOL); - - /// apply the map forward - Vec3d unit(1,0,0); - Vec3d result = scaleAndTranslate->applyMap(unit); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(2), TOL); - - /// invert the map - result = scaleAndTranslate->applyInverseMap(result); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(2), TOL); - - /// Inverse Jacobian Transpose - result = Vec3d(0,2,0); - result = scaleAndTranslate->applyIJT(result ); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, result(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, result(2), TOL); - - - /// Jacobian Transpose - result = scaleAndTranslate->applyJT(scaleAndTranslate->applyIJT(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - - - - // Test inverse map - MapBase::Ptr inverse = scaleAndTranslate->inverseMap(); - CPPUNIT_ASSERT(inverse->type() == UniformScaleTranslateMap::mapType()); - // apply the map forward and the inverse map back - result = inverse->applyMap(scaleAndTranslate->applyMap(unit)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), unit(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), unit(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), unit(2), TOL); - -} - - -void -TestMaps::testDecomposition() -{ - using namespace openvdb::math; - - //double TOL = 1e-7; - - CPPUNIT_ASSERT(is_linear::value); - CPPUNIT_ASSERT(is_linear::value); - CPPUNIT_ASSERT(is_linear::value); - CPPUNIT_ASSERT(is_linear::value); - - Mat4d matrix(Mat4d::identity()); - Vec3d input_translation(0,0,1); - matrix.setTranslation(input_translation); - - - matrix(0,0) = 1.8930039; - matrix(1,0) = -0.120080537; - matrix(2,0) = -0.497615212; - - matrix(0,1) = -0.120080537; - matrix(1,1) = 2.643265436; - matrix(2,1) = 0.6176957495; - - matrix(0,2) = -0.497615212; - matrix(1,2) = 0.6176957495; - matrix(2,2) = 1.4637305884; - - FullyDecomposedMap::Ptr decomp = createFullyDecomposedMap(matrix); - - /// the singular values - const Vec3& singular_values = - decomp->firstMap().firstMap().secondMap().getScale(); - /// expected values - Vec3d expected_values(2, 3, 1); - - CPPUNIT_ASSERT( isApproxEqual(singular_values, expected_values) ); - - const Vec3& the_translation = decomp->secondMap().secondMap().getTranslation(); - CPPUNIT_ASSERT( isApproxEqual(the_translation, input_translation)); -} - - -void -TestMaps::testFrustum() -{ - using namespace openvdb::math; - - openvdb::BBoxd bbox(Vec3d(0), Vec3d(100)); - NonlinearFrustumMap frustum(bbox, 1./6., 5); - /// frustum will have depth, far plane - near plane = 5 - /// the frustum has width 1 in the front and 6 in the back - - Vec3d trans(2,2,2); - NonlinearFrustumMap::Ptr map = - boost::static_pointer_cast( - frustum.preScale(Vec3d(10,10,10))->postTranslate(trans)); - - CPPUNIT_ASSERT(!map->hasUniformScale()); - - Vec3d result; - result = map->voxelSize(); - - CPPUNIT_ASSERT( isApproxEqual(result.x(), 0.1)); - CPPUNIT_ASSERT( isApproxEqual(result.y(), 0.1)); - CPPUNIT_ASSERT( isApproxEqual(result.z(), 0.5, 0.0001)); - //--------- Front face - Vec3d corner(0,0,0); - result = map->applyMap(corner); - CPPUNIT_ASSERT(isApproxEqual(result, Vec3d(-5, -5, 0) + trans)); - - corner = Vec3d(100,0,0); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(5, -5, 0) + trans)); - - corner = Vec3d(0,100,0); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(-5, 5, 0) + trans)); - - corner = Vec3d(100,100,0); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(5, 5, 0) + trans)); - - //--------- Back face - corner = Vec3d(0,0,100); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(-30, -30, 50) + trans)); // 10*(5/2 + 1/2) = 30 - - corner = Vec3d(100,0,100); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(30, -30, 50) + trans)); - - corner = Vec3d(0,100,100); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(-30, 30, 50) + trans)); - - corner = Vec3d(100,100,100); - result = map->applyMap(corner); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(30, 30, 50) + trans)); - - - // invert a single corner - result = map->applyInverseMap(Vec3d(30,30,50) + trans); - CPPUNIT_ASSERT( isApproxEqual(result, Vec3d(100, 100, 100))); - - CPPUNIT_ASSERT(map->hasSimpleAffine()); - - /// create a frustum from from camera type information - - // the location of the camera - Vec3d position(100,10,1); - // the direction the camera is pointing - Vec3d direction(0,1,1); - direction.normalize(); - - // the up-direction for the camera - Vec3d up(10,3,-3); - - // distance from camera to near-plane measured in the direction 'direction' - double z_near = 100.; - // depth of frustum to far-plane to near-plane - double depth = 500.; - //aspect ratio of frustum: width/height - double aspect = 2; - - // voxel count in frustum. the y_count = x_count / aspect - Coord::ValueType x_count = 500; - Coord::ValueType z_count = 5000; - - - NonlinearFrustumMap frustumMap_from_camera( - position, direction, up, aspect, z_near, depth, x_count, z_count); - Vec3d center; - // find the center of the near plane and make sure it is in the correct place - center = Vec3d(0,0,0); - center += frustumMap_from_camera.applyMap(Vec3d(0,0,0)); - center += frustumMap_from_camera.applyMap(Vec3d(500,0,0)); - center += frustumMap_from_camera.applyMap(Vec3d(0,250,0)); - center += frustumMap_from_camera.applyMap(Vec3d(500,250,0)); - center = center /4.; - CPPUNIT_ASSERT( isApproxEqual(center, position + z_near * direction)); - // find the center of the far plane and make sure it is in the correct place - center = Vec3d(0,0,0); - center += frustumMap_from_camera.applyMap(Vec3d( 0, 0,5000)); - center += frustumMap_from_camera.applyMap(Vec3d(500, 0,5000)); - center += frustumMap_from_camera.applyMap(Vec3d( 0,250,5000)); - center += frustumMap_from_camera.applyMap(Vec3d(500,250,5000)); - center = center /4.; - CPPUNIT_ASSERT( isApproxEqual(center, position + (z_near+depth) * direction)); - // check that the frustum has the correct heigh on the near plane - Vec3d corner1 = frustumMap_from_camera.applyMap(Vec3d(0,0,0)); - Vec3d corner2 = frustumMap_from_camera.applyMap(Vec3d(0,250,0)); - Vec3d side = corner2-corner1; - CPPUNIT_ASSERT( isApproxEqual( side.length(), 2 * up.length())); - // check that the frustum is correctly oriented w.r.t up - side.normalize(); - CPPUNIT_ASSERT( isApproxEqual( side * (up.length()), up)); - // check that the linear map inside the frustum is a simple affine map (i.e. has no shear) - CPPUNIT_ASSERT(frustumMap_from_camera.hasSimpleAffine()); -} - - -void -TestMaps::testCalcBoundingBox() -{ - using namespace openvdb::math; - - openvdb::BBoxd world_bbox(Vec3d(0,0,0), Vec3d(1,1,1)); - openvdb::BBoxd voxel_bbox; - openvdb::BBoxd expected; - { - AffineMap affine; - affine.accumPreScale(Vec3d(2,2,2)); - - openvdb::util::calculateBounds(affine, world_bbox, voxel_bbox); - - expected = openvdb::BBoxd(Vec3d(0,0,0), Vec3d(0.5, 0.5, 0.5)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - - affine.accumPostTranslation(Vec3d(1,1,1)); - openvdb::util::calculateBounds(affine, world_bbox, voxel_bbox); - expected = openvdb::BBoxd(Vec3d(-0.5,-0.5,-0.5), Vec3d(0, 0, 0)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - } - { - AffineMap affine; - affine.accumPreScale(Vec3d(2,2,2)); - affine.accumPostTranslation(Vec3d(1,1,1)); - // test a sphere: - Vec3d center(0,0,0); - double radius = 10; - - openvdb::util::calculateBounds(affine, center, radius, voxel_bbox); - expected = openvdb::BBoxd(Vec3d(-5.5,-5.5,-5.5), Vec3d(4.5, 4.5, 4.5)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - } - { - AffineMap affine; - affine.accumPreScale(Vec3d(2,2,2)); - double pi = 4.*atan(1.); - affine.accumPreRotation(X_AXIS, pi/4.); - Vec3d center(0,0,0); - double radius = 10; - - openvdb::util::calculateBounds(affine, center, radius, voxel_bbox); - expected = openvdb::BBoxd(Vec3d(-5,-5,-5), Vec3d(5, 5, 5)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - } - { - AffineMap affine; - affine.accumPreScale(Vec3d(2,1,1)); - double pi = 4.*atan(1.); - affine.accumPreRotation(X_AXIS, pi/4.); - Vec3d center(0,0,0); - double radius = 10; - - openvdb::util::calculateBounds(affine, center, radius, voxel_bbox); - expected = openvdb::BBoxd(Vec3d(-5,-10,-10), Vec3d(5, 10, 10)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - } - { - AffineMap affine; - affine.accumPreScale(Vec3d(2,1,1)); - double pi = 4.*atan(1.); - affine.accumPreRotation(X_AXIS, pi/4.); - affine.accumPostTranslation(Vec3d(1,1,1)); - Vec3d center(1,1,1); - double radius = 10; - - openvdb::util::calculateBounds(affine, center, radius, voxel_bbox); - expected = openvdb::BBoxd(Vec3d(-5,-10,-10), Vec3d(5, 10, 10)); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.min(), expected.min())); - CPPUNIT_ASSERT(isApproxEqual(voxel_bbox.max(), expected.max())); - } - { - openvdb::BBoxd bbox(Vec3d(0), Vec3d(100)); - NonlinearFrustumMap frustum(bbox, 2, 5); - NonlinearFrustumMap::Ptr map = - boost::static_pointer_cast( - frustum.preScale(Vec3d(2,2,2))); - Vec3d center(20,20,10); - double radius(1); - - openvdb::util::calculateBounds(*map, center, radius, voxel_bbox); - } -} -void -TestMaps::testJacobians() -{ - using namespace openvdb::math; - const double TOL = 1e-7; - { - AffineMap affine; - - const int n = 10; - const double dtheta = M_PI / n; - - const Vec3d test(1,2,3); - const Vec3d origin(0,0,0); - - for (int i = 0; i < n; ++i) { - double theta = i * dtheta; - - affine.accumPostRotation(X_AXIS, theta); - - Vec3d result = affine.applyJacobian(test); - Vec3d expected = affine.applyMap(test) - affine.applyMap(origin); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), expected(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), expected(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), expected(2), TOL); - - Vec3d tmp = affine.applyInverseJacobian(result); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - } - } - - { - UniformScaleMap scale(3); - const Vec3d test(1,2,3); - const Vec3d origin(0,0,0); - - - Vec3d result = scale.applyJacobian(test); - Vec3d expected = scale.applyMap(test) - scale.applyMap(origin); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), expected(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), expected(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), expected(2), TOL); - - Vec3d tmp = scale.applyInverseJacobian(result); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - } - - { - ScaleMap scale(Vec3d(1,2,3)); - const Vec3d test(1,2,3); - const Vec3d origin(0,0,0); - - - Vec3d result = scale.applyJacobian(test); - Vec3d expected = scale.applyMap(test) - scale.applyMap(origin); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), expected(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), expected(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), expected(2), TOL); - - Vec3d tmp = scale.applyInverseJacobian(result); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - } - { - TranslationMap map(Vec3d(1,2,3)); - const Vec3d test(1,2,3); - const Vec3d origin(0,0,0); - - - Vec3d result = map.applyJacobian(test); - Vec3d expected = map.applyMap(test) - map.applyMap(origin); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), expected(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), expected(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), expected(2), TOL); - - Vec3d tmp = map.applyInverseJacobian(result); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - } - { - ScaleTranslateMap map(Vec3d(1,2,3), Vec3d(3,5,4)); - const Vec3d test(1,2,3); - const Vec3d origin(0,0,0); - - - Vec3d result = map.applyJacobian(test); - Vec3d expected = map.applyMap(test) - map.applyMap(origin); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(0), expected(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(1), expected(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(result(2), expected(2), TOL); - - Vec3d tmp = map.applyInverseJacobian(result); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - } - { - - openvdb::BBoxd bbox(Vec3d(0), Vec3d(100)); - NonlinearFrustumMap frustum(bbox, 1./6., 5); - /// frustum will have depth, far plane - near plane = 5 - /// the frustum has width 1 in the front and 6 in the back - - Vec3d trans(2,2,2); - NonlinearFrustumMap::Ptr map = - boost::static_pointer_cast( - frustum.preScale(Vec3d(10,10,10))->postTranslate(trans)); - - - const Vec3d test(1,2,3); - const Vec3d origin(0, 0, 0); - - // these two drop down to just the linear part - Vec3d lresult = map->applyJacobian(test); - Vec3d ltmp = map->applyInverseJacobian(lresult); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(ltmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(ltmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(ltmp(2), test(2), TOL); - - Vec3d isloc(4,5,6); - // these two drop down to just the linear part - Vec3d result = map->applyJacobian(test, isloc); - Vec3d tmp = map->applyInverseJacobian(result, isloc); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(0), test(0), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(1), test(1), TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(tmp(2), test(2), TOL); - - - - } - - -} - - - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMat4Metadata.cc b/openvdb_3_0_0_library/unittest/TestMat4Metadata.cc deleted file mode 100755 index 3904e3a..0000000 --- a/openvdb_3_0_0_library/unittest/TestMat4Metadata.cc +++ /dev/null @@ -1,131 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestMat4Metadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestMat4Metadata); - CPPUNIT_TEST(testMat4s); - CPPUNIT_TEST(testMat4d); - CPPUNIT_TEST_SUITE_END(); - - void testMat4s(); - void testMat4d(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMat4Metadata); - -void -TestMat4Metadata::testMat4s() -{ - using namespace openvdb; - - Metadata::Ptr m(new Mat4SMetadata(openvdb::math::Mat4s(1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f))); - Metadata::Ptr m3 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast( m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m3.get()) != 0); - - CPPUNIT_ASSERT( m->typeName().compare("mat4s") == 0); - CPPUNIT_ASSERT(m3->typeName().compare("mat4s") == 0); - - Mat4SMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4s(1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f)); - s->value() = openvdb::math::Mat4s(3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4s(3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f)); - - m3->copy(*s); - - s = dynamic_cast(m3.get()); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4s(3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f, - 3.0f, 3.0f, 3.0f, 3.0f)); -} - -void -TestMat4Metadata::testMat4d() -{ - using namespace openvdb; - - Metadata::Ptr m(new Mat4DMetadata(openvdb::math::Mat4d(1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0))); - Metadata::Ptr m3 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast( m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m3.get()) != 0); - - CPPUNIT_ASSERT( m->typeName().compare("mat4d") == 0); - CPPUNIT_ASSERT(m3->typeName().compare("mat4d") == 0); - - Mat4DMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4d(1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, 1.0)); - s->value() = openvdb::math::Mat4d(3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4d(3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0)); - - m3->copy(*s); - - s = dynamic_cast(m3.get()); - CPPUNIT_ASSERT(s->value() == openvdb::math::Mat4d(3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0, - 3.0, 3.0, 3.0, 3.0)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMath.cc b/openvdb_3_0_0_library/unittest/TestMath.cc deleted file mode 100755 index ecc3847..0000000 --- a/openvdb_3_0_0_library/unittest/TestMath.cc +++ /dev/null @@ -1,221 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - - -class TestMath: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestMath); - CPPUNIT_TEST(testAll); - CPPUNIT_TEST(testRandomInt); - CPPUNIT_TEST(testRandom01); - CPPUNIT_TEST(testMinMaxIndex); - CPPUNIT_TEST_SUITE_END(); - - void testAll(); - void testRandomInt(); - void testRandom01(); - void testMinMaxIndex(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMath); - - -// This suite of tests obviously needs to be expanded! -void -TestMath::testAll() -{ - using namespace openvdb; - - {// Sign - CPPUNIT_ASSERT_EQUAL(math::Sign( 3 ), 1); - CPPUNIT_ASSERT_EQUAL(math::Sign(-1.0 ),-1); - CPPUNIT_ASSERT_EQUAL(math::Sign( 0.0f), 0); - } - {// SignChange - CPPUNIT_ASSERT( math::SignChange( -1, 1)); - CPPUNIT_ASSERT(!math::SignChange( 0.0f, 0.5f)); - CPPUNIT_ASSERT( math::SignChange( 0.0f,-0.5f)); - CPPUNIT_ASSERT( math::SignChange(-0.1, 0.0001)); - - } - {// isApproxZero - CPPUNIT_ASSERT( math::isApproxZero( 0.0f)); - CPPUNIT_ASSERT(!math::isApproxZero( 9.0e-6f)); - CPPUNIT_ASSERT(!math::isApproxZero(-9.0e-6f)); - CPPUNIT_ASSERT( math::isApproxZero( 9.0e-9f)); - CPPUNIT_ASSERT( math::isApproxZero(-9.0e-9f)); - CPPUNIT_ASSERT( math::isApproxZero( 0.01, 0.1)); - } - {// Cbrt - const double a = math::Cbrt(3.0); - CPPUNIT_ASSERT(math::isApproxEqual(a*a*a, 3.0, 1e-6)); - } -} - - -void -TestMath::testRandomInt() -{ - using openvdb::math::RandomInt; - - int imin = -3, imax = 11; - RandomInt rnd(/*seed=*/42, imin, imax); - - // Generate a sequence of random integers and verify that they all fall - // in the interval [imin, imax]. - std::vector seq(100); - for (int i = 0; i < 100; ++i) { - seq[i] = rnd(); - CPPUNIT_ASSERT(seq[i] >= imin); - CPPUNIT_ASSERT(seq[i] <= imax); - } - - // Verify that generators with the same seed produce the same sequence. - rnd = RandomInt(42, imin, imax); - for (int i = 0; i < 100; ++i) { - int r = rnd(); - CPPUNIT_ASSERT_EQUAL(seq[i], r); - } - - // Verify that generators with different seeds produce different sequences. - rnd = RandomInt(101, imin, imax); - std::vector newSeq(100); - for (int i = 0; i < 100; ++i) newSeq[i] = rnd(); - CPPUNIT_ASSERT(newSeq != seq); - - // Temporarily change the range. - imin = -5; imax = 6; - for (int i = 0; i < 100; ++i) { - int r = rnd(imin, imax); - CPPUNIT_ASSERT(r >= imin); - CPPUNIT_ASSERT(r <= imax); - } - // Verify that the range change was temporary. - imin = -3; imax = 11; - for (int i = 0; i < 100; ++i) { - int r = rnd(); - CPPUNIT_ASSERT(r >= imin); - CPPUNIT_ASSERT(r <= imax); - } - - // Permanently change the range. - imin = -5; imax = 6; - rnd.setRange(imin, imax); - for (int i = 0; i < 100; ++i) { - int r = rnd(); - CPPUNIT_ASSERT(r >= imin); - CPPUNIT_ASSERT(r <= imax); - } - - // Verify that it is OK to specify imin > imax (they are automatically swapped). - imin = 5; imax = -6; - rnd.setRange(imin, imax); - - rnd = RandomInt(42, imin, imax); -} - - -void -TestMath::testRandom01() -{ - using openvdb::math::Random01; - using openvdb::math::isApproxEqual; - - Random01 rnd(/*seed=*/42); - - // Generate a sequence of random numbers and verify that they all fall - // in the interval [0, 1). - std::vector seq(100); - for (int i = 0; i < 100; ++i) { - seq[i] = rnd(); - CPPUNIT_ASSERT(seq[i] >= 0.0); - CPPUNIT_ASSERT(seq[i] < 1.0); - } - - // Verify that generators with the same seed produce the same sequence. - rnd = Random01(42); - for (int i = 0; i < 100; ++i) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(seq[i], rnd(), /*tolerance=*/1.0e-6); - } - - // Verify that generators with different seeds produce different sequences. - rnd = Random01(101); - bool allEqual = true; - for (int i = 0; allEqual && i < 100; ++i) { - if (!isApproxEqual(rnd(), seq[i])) allEqual = false; - } - CPPUNIT_ASSERT(!allEqual); -} - -void -TestMath::testMinMaxIndex() -{ - const openvdb::Vec3R a(-1, 2, 0); - CPPUNIT_ASSERT_EQUAL(size_t(0), openvdb::math::MinIndex(a)); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MaxIndex(a)); - const openvdb::Vec3R b(-1, -2, 0); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MinIndex(b)); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MaxIndex(b)); - const openvdb::Vec3R c(5, 2, 1); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MinIndex(c)); - CPPUNIT_ASSERT_EQUAL(size_t(0), openvdb::math::MaxIndex(c)); - const openvdb::Vec3R d(0, 0, 1); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MinIndex(d)); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MaxIndex(d)); - const openvdb::Vec3R e(1, 0, 0); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MinIndex(e)); - CPPUNIT_ASSERT_EQUAL(size_t(0), openvdb::math::MaxIndex(e)); - const openvdb::Vec3R f(0, 1, 0); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MinIndex(f)); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MaxIndex(f)); - const openvdb::Vec3R g(1, 1, 0); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MinIndex(g)); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MaxIndex(g)); - const openvdb::Vec3R h(1, 0, 1); - CPPUNIT_ASSERT_EQUAL(size_t(1), openvdb::math::MinIndex(h)); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MaxIndex(h)); - const openvdb::Vec3R i(0, 1, 1); - CPPUNIT_ASSERT_EQUAL(size_t(0), openvdb::math::MinIndex(i)); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MaxIndex(i)); - const openvdb::Vec3R j(1, 1, 1); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MinIndex(j)); - CPPUNIT_ASSERT_EQUAL(size_t(2), openvdb::math::MaxIndex(j)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMeanCurvature.cc b/openvdb_3_0_0_library/unittest/TestMeanCurvature.cc deleted file mode 100755 index 31b457b..0000000 --- a/openvdb_3_0_0_library/unittest/TestMeanCurvature.cc +++ /dev/null @@ -1,742 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestMeanCurvature: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestMeanCurvature); - CPPUNIT_TEST(testISMeanCurvature); // MeanCurvature in Index Space - CPPUNIT_TEST(testISMeanCurvatureStencil); - CPPUNIT_TEST(testWSMeanCurvature); // MeanCurvature in World Space - CPPUNIT_TEST(testWSMeanCurvatureStencil); - CPPUNIT_TEST(testMeanCurvatureTool); // MeanCurvature tool - CPPUNIT_TEST(testMeanCurvatureMaskedTool); // MeanCurvature tool - CPPUNIT_TEST(testOldStyleStencils); // old stencil impl - deprecate - - CPPUNIT_TEST_SUITE_END(); - - void testISMeanCurvature(); - void testISMeanCurvatureStencil(); - void testWSMeanCurvature(); - void testWSMeanCurvatureStencil(); - void testMeanCurvatureTool(); - void testMeanCurvatureMaskedTool(); - void testOldStyleStencils(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMeanCurvature); - - -void -TestMeanCurvature::testISMeanCurvature() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - AccessorType inAccessor = grid->getConstAccessor(); - AccessorType::ValueType alpha, beta, meancurv, normGrad; - Coord xyz(35,30,30); - - // First test an empty grid - CPPUNIT_ASSERT(tree.empty()); - typedef math::ISMeanCurvature SecondOrder; - CPPUNIT_ASSERT(!SecondOrder::result(inAccessor, xyz, alpha, beta)); - - typedef math::ISMeanCurvature FourthOrder; - CPPUNIT_ASSERT(!FourthOrder::result(inAccessor, xyz, alpha, beta)); - - typedef math::ISMeanCurvature SixthOrder; - CPPUNIT_ASSERT(!SixthOrder::result(inAccessor, xyz, alpha, beta)); - - // Next test a level set sphere - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - - SecondOrder::result(inAccessor, xyz, alpha, beta); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - FourthOrder::result(inAccessor, xyz, alpha, beta); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - SixthOrder::result(inAccessor, xyz, alpha, beta); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - xyz.reset(35,10,40); - - SecondOrder::result(inAccessor, xyz, alpha, beta); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, normGrad, 0.001); -} - - -void -TestMeanCurvature::testISMeanCurvatureStencil() -{ - using namespace openvdb; - - typedef FloatGrid::ConstAccessor AccessorType; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - math::SixthOrderDenseStencil dense_6th(*grid); - AccessorType::ValueType alpha, beta; - Coord xyz(35,30,30); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - // First test on an empty grid - CPPUNIT_ASSERT(tree.empty()); - - typedef math::ISMeanCurvature SecondOrder; - CPPUNIT_ASSERT(!SecondOrder::result(dense_2nd, alpha, beta)); - - typedef math::ISMeanCurvature FourthOrder; - CPPUNIT_ASSERT(!FourthOrder::result(dense_4th, alpha, beta)); - - typedef math::ISMeanCurvature SixthOrder; - CPPUNIT_ASSERT(!SixthOrder::result(dense_6th, alpha, beta)); - - // Next test on a level set sphere - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - CPPUNIT_ASSERT(!tree.empty()); - - CPPUNIT_ASSERT(SecondOrder::result(dense_2nd, alpha, beta)); - - AccessorType::ValueType meancurv = alpha/(2*math::Pow3(beta) ); - AccessorType::ValueType normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - CPPUNIT_ASSERT(FourthOrder::result(dense_4th, alpha, beta)); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - CPPUNIT_ASSERT(SixthOrder::result(dense_6th, alpha, beta)); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - xyz.reset(35,10,40); - dense_2nd.moveTo(xyz); - CPPUNIT_ASSERT(SecondOrder::result(dense_2nd, alpha, beta)); - - meancurv = alpha/(2*math::Pow3(beta) ); - normGrad = alpha/(2*math::Pow2(beta) ); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, normGrad, 0.001); -} - - -void -TestMeanCurvature::testWSMeanCurvature() -{ - using namespace openvdb; - using math::AffineMap; - using math::TranslationMap; - using math::UniformScaleMap; - - typedef FloatGrid::ConstAccessor AccessorType; - - {// Empty grid test - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - AccessorType inAccessor = grid->getConstAccessor(); - Coord xyz(35,30,30); - CPPUNIT_ASSERT(tree.empty()); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - AffineMap affine; - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - - UniformScaleMap uniform; - meancurv = math::MeanCurvature::result( - uniform, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - uniform, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - - xyz.reset(35,10,40); - - TranslationMap trans; - meancurv = math::MeanCurvature::result( - trans, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - trans, inAccessor, xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - } - - { // unit size voxel test - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f ,30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - Coord xyz(35,30,30); - - AccessorType inAccessor = grid->getConstAccessor(); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - AffineMap affine; - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - UniformScaleMap uniform; - meancurv = math::MeanCurvature::result( - uniform, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - uniform, inAccessor, xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - xyz.reset(35,10,40); - - TranslationMap trans; - meancurv = math::MeanCurvature::result( - trans, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - trans, inAccessor, xyz); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, normGrad, 0.001); - } - { // non-unit sized voxel - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - AccessorType inAccessor = grid->getConstAccessor(); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - Coord xyz(20,16,20); - AffineMap affine(voxel_size*math::Mat3d::identity()); - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - affine, inAccessor, xyz); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - - UniformScaleMap uniform(voxel_size); - meancurv = math::MeanCurvature::result( - uniform, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - uniform, inAccessor, xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - - } - { // NON-UNIFORM SCALING AND ROTATION - - Vec3d voxel_sizes(0.25, 0.45, 0.75); - FloatGrid::Ptr grid = FloatGrid::create(); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - // apply rotation - math::MapBase::Ptr rotated_map = base_map->preRotate(1.5, math::X_AXIS); - grid->setTransform(math::Transform::Ptr(new math::Transform(rotated_map))); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - AccessorType inAccessor = grid->getConstAccessor(); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - Coord xyz(20,16,20); - Vec3d location = grid->indexToWorld(xyz); - double dist = (center - location).length(); - AffineMap::ConstPtr affine = grid->transform().map(); - meancurv = math::MeanCurvature::result( - *affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - *affine, inAccessor, xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - *affine, inAccessor, xyz); - normGrad = math::MeanCurvature::normGrad( - *affine, inAccessor, xyz); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, normGrad, 0.001); - } -} - - -void -TestMeanCurvature::testWSMeanCurvatureStencil() -{ - using namespace openvdb; - using math::AffineMap; - using math::TranslationMap; - using math::UniformScaleMap; - - typedef FloatGrid::ConstAccessor AccessorType; - - {// empty grid test - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - Coord xyz(35,30,30); - - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - math::SixthOrderDenseStencil dense_6th(*grid); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - AffineMap affine; - meancurv = math::MeanCurvature::result( - affine, dense_2nd); - normGrad = math::MeanCurvature::normGrad( - affine, dense_2nd); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.00); - - meancurv = math::MeanCurvature::result( - affine, dense_4th); - normGrad = math::MeanCurvature::normGrad( - affine, dense_4th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.00); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.00); - - UniformScaleMap uniform; - meancurv = math::MeanCurvature::result( - uniform, dense_6th); - normGrad = math::MeanCurvature::normGrad( - uniform, dense_6th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - - xyz.reset(35,10,40); - dense_6th.moveTo(xyz); - - TranslationMap trans; - meancurv = math::MeanCurvature::result( - trans, dense_6th); - normGrad = math::MeanCurvature::normGrad( - trans, dense_6th); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, meancurv, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, normGrad, 0.0); - } - - { // unit-sized voxels - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f);//i.e. (35,30,40) in index space - const float radius=0.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - Coord xyz(35,30,30); - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - math::SixthOrderDenseStencil dense_6th(*grid); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - AffineMap affine; - meancurv = math::MeanCurvature::result( - affine, dense_2nd); - normGrad = math::MeanCurvature::normGrad( - affine, dense_2nd); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - affine, dense_4th); - normGrad = math::MeanCurvature::normGrad( - affine, dense_4th); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - UniformScaleMap uniform; - meancurv = math::MeanCurvature::result( - uniform, dense_6th); - normGrad = math::MeanCurvature::normGrad( - uniform, dense_6th); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, normGrad, 0.001); - - xyz.reset(35,10,40); - dense_6th.moveTo(xyz); - - TranslationMap trans; - meancurv = math::MeanCurvature::result( - trans, dense_6th); - normGrad = math::MeanCurvature::normGrad( - trans, dense_6th); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, normGrad, 0.001); - } - { // non-unit sized voxel - - double voxel_size = 0.5; - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(voxel_size)); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - Coord xyz(20,16,20); - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - math::SixthOrderDenseStencil dense_6th(*grid); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - dense_6th.moveTo(xyz); - - AffineMap affine(voxel_size*math::Mat3d::identity()); - meancurv = math::MeanCurvature::result( - affine, dense_2nd); - normGrad = math::MeanCurvature::normGrad( - affine, dense_2nd); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - affine, dense_4th); - normGrad = math::MeanCurvature::normGrad( - affine, dense_4th); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - - UniformScaleMap uniform(voxel_size); - meancurv = math::MeanCurvature::result( - uniform, dense_6th); - normGrad = math::MeanCurvature::normGrad( - uniform, dense_6th); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, normGrad, 0.001); - } - { // NON-UNIFORM SCALING AND ROTATION - - Vec3d voxel_sizes(0.25, 0.45, 0.75); - FloatGrid::Ptr grid = FloatGrid::create(); - math::MapBase::Ptr base_map( new math::ScaleMap(voxel_sizes)); - // apply rotation - math::MapBase::Ptr rotated_map = base_map->preRotate(1.5, math::X_AXIS); - grid->setTransform(math::Transform::Ptr(new math::Transform(rotated_map))); - CPPUNIT_ASSERT(grid->empty()); - - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - AccessorType::ValueType meancurv; - AccessorType::ValueType normGrad; - - Coord xyz(20,16,20); - math::SecondOrderDenseStencil dense_2nd(*grid); - math::FourthOrderDenseStencil dense_4th(*grid); - dense_2nd.moveTo(xyz); - dense_4th.moveTo(xyz); - - - Vec3d location = grid->indexToWorld(xyz); - double dist = (center - location).length(); - AffineMap::ConstPtr affine = grid->transform().map(); - meancurv = math::MeanCurvature::result( - *affine, dense_2nd); - normGrad = math::MeanCurvature::normGrad( - *affine, dense_2nd); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, normGrad, 0.001); - meancurv = math::MeanCurvature::result( - *affine, dense_4th); - normGrad = math::MeanCurvature::normGrad( - *affine, dense_4th); - - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, meancurv, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/dist, normGrad, 0.001); - } -} - - -void -TestMeanCurvature::testMeanCurvatureTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f);//i.e. (35,30,40) in index space - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - FloatGrid::Ptr curv = tools::meanCurvature(*grid); - FloatGrid::ConstAccessor accessor = curv->getConstAccessor(); - - Coord xyz(35,30,30); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, accessor.getValue(xyz), 0.001); - - xyz.reset(35,10,40); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/20.0, accessor.getValue(xyz), 0.001); -} - - -void -TestMeanCurvature::testMeanCurvatureMaskedTool() -{ - using namespace openvdb; - - FloatGrid::Ptr grid = createGrid(/*background=*/5.0); - FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f);//i.e. (35,30,40) in index space - const float radius=0.0f; - unittest_util::makeSphere(dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - BoolGrid::Ptr maskGrid = BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - - FloatGrid::Ptr curv = tools::meanCurvature(*grid, *maskGrid); - FloatGrid::ConstAccessor accessor = curv->getConstAccessor(); - - // test inside - Coord xyz(35,30,30); - CPPUNIT_ASSERT(maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/10.0, accessor.getValue(xyz), 0.001); - - // test outside - xyz.reset(35,10,40); - CPPUNIT_ASSERT(!maskbbox.isInside(xyz)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, accessor.getValue(xyz), 0.001); -} - - -void -TestMeanCurvature::testOldStyleStencils() -{ - using namespace openvdb; - - {// test of level set to sphere at (6,8,10) with R=10 and dx=0.5 - - FloatGrid::Ptr grid = FloatGrid::create(/*backgroundValue=*/5.0); - grid->setTransform(math::Transform::createLinearTransform(/*voxel size=*/0.5)); - CPPUNIT_ASSERT(grid->empty()); - math::CurvatureStencil cs(*grid); - Coord xyz(20,16,20);//i.e. 8 voxel or 4 world units away from the center - cs.moveTo(xyz); - - // First test on an empty grid - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, cs.meanCurvature(), 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, cs.meanCurvatureNormGrad(), 0.0); - - // Next test on a level set sphere - const openvdb::Coord dim(32,32,32); - const openvdb::Vec3f center(6.0f, 8.0f, 10.0f);//i.e. (12,16,20) in index space - const float radius=10.0f; - unittest_util::makeSphere( - dim, center, radius, *grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!grid->empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(grid->activeVoxelCount())); - cs.moveTo(xyz); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/4.0, cs.meanCurvature(), 0.01);// 1/distance from center - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 1.0/4.0, cs.meanCurvatureNormGrad(), 0.01);// 1/distance from center - - xyz.reset(12,16,10);//i.e. 10 voxel or 5 world units away from the center - cs.moveTo(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0/5.0, cs.meanCurvature(), 0.01);// 1/distance from center - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 1.0/5.0, cs.meanCurvatureNormGrad(), 0.01);// 1/distance from center - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMeshToVolume.cc b/openvdb_3_0_0_library/unittest/TestMeshToVolume.cc deleted file mode 100755 index a99bacd..0000000 --- a/openvdb_3_0_0_library/unittest/TestMeshToVolume.cc +++ /dev/null @@ -1,381 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include -#include - -#include -#include - - -class TestMeshToVolume: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestMeshToVolume); - CPPUNIT_TEST(testUtils); - CPPUNIT_TEST(testVoxelizer); - CPPUNIT_TEST(testPrimitiveVoxelRatio); - CPPUNIT_TEST(testIntersectingVoxelCleaner); - CPPUNIT_TEST(testShellVoxelCleaner); - CPPUNIT_TEST(testConversion); - CPPUNIT_TEST_SUITE_END(); - - void testUtils(); - void testVoxelizer(); - void testPrimitiveVoxelRatio(); - void testIntersectingVoxelCleaner(); - void testShellVoxelCleaner(); - void testConversion(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMeshToVolume); - - -//////////////////////////////////////// - - -void -TestMeshToVolume::testUtils() -{ - /// Test nearestCoord - openvdb::Vec3d xyz(0.7, 2.2, -2.7); - openvdb::Coord ijk = openvdb::util::nearestCoord(xyz); - CPPUNIT_ASSERT(ijk[0] == 0 && ijk[1] == 2 && ijk[2] == -3); - - xyz = openvdb::Vec3d(-22.1, 4.6, 202.34); - ijk = openvdb::util::nearestCoord(xyz); - CPPUNIT_ASSERT(ijk[0] == -23 && ijk[1] == 4 && ijk[2] == 202); - - /// Test the coordinate offset table for neghbouring voxels - openvdb::Coord sum(0, 0, 0); - - unsigned int pX = 0, pY = 0, pZ = 0, mX = 0, mY = 0, mZ = 0; - - for (unsigned int i = 0; i < 26; ++i) { - ijk = openvdb::util::COORD_OFFSETS[i]; - sum += ijk; - - if (ijk[0] == 1) ++pX; - else if (ijk[0] == -1) ++mX; - - if (ijk[1] == 1) ++pY; - else if (ijk[1] == -1) ++mY; - - if (ijk[2] == 1) ++pZ; - else if (ijk[2] == -1) ++mZ; - } - - CPPUNIT_ASSERT(sum == openvdb::Coord(0, 0, 0)); - - CPPUNIT_ASSERT( pX == 9); - CPPUNIT_ASSERT( pY == 9); - CPPUNIT_ASSERT( pZ == 9); - CPPUNIT_ASSERT( mX == 9); - CPPUNIT_ASSERT( mY == 9); - CPPUNIT_ASSERT( mZ == 9); -} - - -void -TestMeshToVolume::testVoxelizer() -{ - std::vector pointList; - std::vector polygonList; - - typedef openvdb::tools::internal::MeshVoxelizer MeshVoxelizer; - - // CASE 1: One triangle - - pointList.push_back(openvdb::Vec3s(0.0, 0.0, 0.0)); - pointList.push_back(openvdb::Vec3s(0.0, 0.0, 3.0)); - pointList.push_back(openvdb::Vec3s(0.0, 3.0, 0.0)); - - polygonList.push_back(openvdb::Vec4I(0, 1, 2, openvdb::util::INVALID_IDX)); - - { - MeshVoxelizer voxelizer(pointList, polygonList); - voxelizer.run(); - - // Check for mesh intersecting voxels - CPPUNIT_ASSERT(13== voxelizer.intersectionTree().activeVoxelCount()); - - // topologically unique voxels. - CPPUNIT_ASSERT(99 == voxelizer.sqrDistTree().activeVoxelCount()); - CPPUNIT_ASSERT(99 == voxelizer.primIndexTree().activeVoxelCount()); - } - - // CASE 2: Two triangles - - pointList.push_back(openvdb::Vec3s(0.0, 3.0, 3.0)); - polygonList.push_back(openvdb::Vec4I(1, 3, 2, openvdb::util::INVALID_IDX)); - - { - MeshVoxelizer voxelizer(pointList, polygonList); - voxelizer.run(); - - // Check for mesh intersecting voxels - CPPUNIT_ASSERT(16 == voxelizer.intersectionTree().activeVoxelCount()); - - // topologically unique voxels. - CPPUNIT_ASSERT(108 == voxelizer.sqrDistTree().activeVoxelCount()); - CPPUNIT_ASSERT(108 == voxelizer.primIndexTree().activeVoxelCount()); - } - - // CASE 3: One quad - - polygonList.clear(); - polygonList.push_back(openvdb::Vec4I(0, 1, 3, 2)); - - { - MeshVoxelizer voxelizer(pointList, polygonList); - voxelizer.run(); - - // Check for mesh intersecting voxels - CPPUNIT_ASSERT(16 == voxelizer.intersectionTree().activeVoxelCount()); - - // topologically unique voxels. - CPPUNIT_ASSERT(108 == voxelizer.sqrDistTree().activeVoxelCount()); - CPPUNIT_ASSERT(108 == voxelizer.primIndexTree().activeVoxelCount()); - } - - // CASE 4: Two triangles and one quad - - pointList.push_back(openvdb::Vec3s(0.0, 0.0, 6.0)); - pointList.push_back(openvdb::Vec3s(0.0, 3.0, 6.0)); - - polygonList.clear(); - polygonList.push_back(openvdb::Vec4I(0, 1, 2, openvdb::util::INVALID_IDX)); - polygonList.push_back(openvdb::Vec4I(1, 3, 2, openvdb::util::INVALID_IDX)); - polygonList.push_back(openvdb::Vec4I(1, 4, 5, 3)); - - { - MeshVoxelizer voxelizer(pointList, polygonList); - voxelizer.run(); - - // Check for 28 mesh intersecting voxels - CPPUNIT_ASSERT(28 == voxelizer.intersectionTree().activeVoxelCount()); - - // 154 topologically unique voxels. - CPPUNIT_ASSERT(162 == voxelizer.sqrDistTree().activeVoxelCount()); - CPPUNIT_ASSERT(162 == voxelizer.primIndexTree().activeVoxelCount()); - } -} - - -void -TestMeshToVolume::testPrimitiveVoxelRatio() -{ - std::vector pointList; - std::vector polygonList; - - // Create one big triangle - pointList.push_back(openvdb::Vec3s(0.0, 0.0, 0.0)); - pointList.push_back(openvdb::Vec3s(0.0, 0.0, 250.0)); - pointList.push_back(openvdb::Vec3s(0.0, 100.0, 0.0)); - - polygonList.push_back(openvdb::Vec4I(0, 1, 2, openvdb::util::INVALID_IDX)); - - openvdb::tools::internal::MeshVoxelizer - voxelizer(pointList, polygonList); - - voxelizer.run(); - - CPPUNIT_ASSERT(0 != voxelizer.intersectionTree().activeVoxelCount()); -} - - -void -TestMeshToVolume::testIntersectingVoxelCleaner() -{ - // Empty tree's - - openvdb::FloatTree distTree(std::numeric_limits::max()); - openvdb::BoolTree intersectionTree(false); - openvdb::Int32Tree indexTree(openvdb::util::INVALID_IDX); - - openvdb::tree::ValueAccessor distAcc(distTree); - openvdb::tree::ValueAccessor intersectionAcc(intersectionTree); - openvdb::tree::ValueAccessor indexAcc(indexTree); - - // Add a row of intersecting voxels surrounded by both positive and negative distance values. - for (int i = 0; i < 10; ++i) { - for (int j = -1; j < 2; ++j) { - distAcc.setValue(openvdb::Coord(i,j,0), (float)j); - indexAcc.setValue(openvdb::Coord(i,j,0), 10); - } - intersectionAcc.setValue(openvdb::Coord(i,0,0), 1); - } - - openvdb::Index64 - numSDFVoxels = distTree.activeVoxelCount(), - numIVoxels = intersectionTree.activeVoxelCount(), - numCPVoxels = indexTree.activeVoxelCount(); - - { - openvdb::tree::LeafManager leafs(intersectionTree); - - openvdb::tools::internal::IntersectingVoxelCleaner - cleaner(distTree, indexTree, intersectionTree, leafs); - - cleaner.run(); - } - - CPPUNIT_ASSERT_EQUAL(numSDFVoxels, distTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numIVoxels, intersectionTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numCPVoxels, indexTree.activeVoxelCount()); - - - // Add a row of intersecting voxels that are not surrounded by any positive distance values. - for (int i = 0; i < 10; ++i) { - for (int j = -1; j < 2; ++j) { - distAcc.setValue(openvdb::Coord(i,j,0), -1.0); - indexAcc.setValue(openvdb::Coord(i,j,0), 10); - } - intersectionAcc.setValue(openvdb::Coord(i,0,0), 1); - } - - numIVoxels = 0; - - { - openvdb::tree::LeafManager leafs(intersectionTree); - - openvdb::tools::internal::IntersectingVoxelCleaner - cleaner(distTree, indexTree, intersectionTree, leafs); - - cleaner.run(); - } - - CPPUNIT_ASSERT_EQUAL(numSDFVoxels, distTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numIVoxels, intersectionTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numCPVoxels, indexTree.activeVoxelCount()); -} - - -void -TestMeshToVolume::testShellVoxelCleaner() -{ - // Empty tree's - - openvdb::FloatTree distTree(std::numeric_limits::max()); - openvdb::BoolTree intersectionTree(false); - openvdb::Int32Tree indexTree(openvdb::util::INVALID_IDX); - - openvdb::tree::ValueAccessor distAcc(distTree); - openvdb::tree::ValueAccessor intersectionAcc(intersectionTree); - openvdb::tree::ValueAccessor indexAcc(indexTree); - - /// Add a row of intersecting voxels surrounded by negative distance values. - for (int i = 0; i < 10; ++i) { - for (int j = -1; j < 2; ++j) { - distAcc.setValue(openvdb::Coord(i,j,0), -1.0); - indexAcc.setValue(openvdb::Coord(i,j,0), 10); - } - intersectionAcc.setValue(openvdb::Coord(i,0,0), 1); - } - - openvdb::Index64 - numSDFVoxels = distTree.activeVoxelCount(), - numIVoxels = intersectionTree.activeVoxelCount(), - numCPVoxels = indexTree.activeVoxelCount(); - - { - openvdb::tree::LeafManager leafs(distTree); - - openvdb::tools::internal::ShellVoxelCleaner - cleaner(distTree, leafs, indexTree, intersectionTree); - - cleaner.run(); - } - - CPPUNIT_ASSERT_EQUAL(numSDFVoxels, distTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numIVoxels, intersectionTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(numCPVoxels, indexTree.activeVoxelCount()); - - intersectionTree.clear(); - - { - openvdb::tree::LeafManager leafs(distTree); - - openvdb::tools::internal::ShellVoxelCleaner - cleaner(distTree, leafs, indexTree, intersectionTree); - - cleaner.run(); - } - - const openvdb::Index64 zero(0); - CPPUNIT_ASSERT_EQUAL(zero, distTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(zero, intersectionTree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(zero, indexTree.activeVoxelCount());; -} - - -void -TestMeshToVolume::testConversion() -{ - using namespace openvdb; - - std::vector points; - std::vector quads; - - // cube vertices - points.push_back(Vec3s(2, 2, 2)); // 0 6--------7 - points.push_back(Vec3s(5, 2, 2)); // 1 /| /| - points.push_back(Vec3s(2, 5, 2)); // 2 2--------3 | - points.push_back(Vec3s(5, 5, 2)); // 3 | | | | - points.push_back(Vec3s(2, 2, 5)); // 4 | 4----- |-5 - points.push_back(Vec3s(5, 2, 5)); // 5 |/ |/ - points.push_back(Vec3s(2, 5, 5)); // 6 0--------1 - points.push_back(Vec3s(5, 5, 5)); // 7 - - // cube faces - quads.push_back(Vec4I(0, 1, 3, 2)); // front - quads.push_back(Vec4I(5, 4, 6, 7)); // back - quads.push_back(Vec4I(0, 2, 6, 4)); // left - quads.push_back(Vec4I(1, 5, 7, 3)); // right - quads.push_back(Vec4I(2, 3, 7, 6)); // top - quads.push_back(Vec4I(0, 4, 5, 1)); // bottom - - FloatGrid::Ptr grid = tools::meshToLevelSet( - *math::Transform::createLinearTransform(), points, quads); - - //io::File("/tmp/cube.vdb").write(GridPtrVec(1, grid)); - - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT_EQUAL(int(GRID_LEVEL_SET), int(grid->getGridClass())); - CPPUNIT_ASSERT_EQUAL(1, int(grid->baseTree().leafCount())); - /// @todo validate output -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMetaMap.cc b/openvdb_3_0_0_library/unittest/TestMetaMap.cc deleted file mode 100755 index d093b8d..0000000 --- a/openvdb_3_0_0_library/unittest/TestMetaMap.cc +++ /dev/null @@ -1,317 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - -class TestMetaMap: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestMetaMap); - CPPUNIT_TEST(testInsert); - CPPUNIT_TEST(testRemove); - CPPUNIT_TEST(testGetMetadata); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testEmptyIO); - CPPUNIT_TEST(testCopyConstructor); - CPPUNIT_TEST(testCopyConstructorEmpty); - CPPUNIT_TEST(testAssignment); - CPPUNIT_TEST_SUITE_END(); - - void testInsert(); - void testRemove(); - void testGetMetadata(); - void testIO(); - void testEmptyIO(); - void testCopyConstructor(); - void testCopyConstructorEmpty(); - void testAssignment(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetaMap); - -void -TestMetaMap::testInsert() -{ - using namespace openvdb; - - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", FloatMetadata(2.0)); - - MetaMap::MetaIterator iter = meta.beginMeta(); - int i = 1; - for( ; iter != meta.endMeta(); ++iter, ++i) { - if(i == 1) { - CPPUNIT_ASSERT(iter->first.compare("meta1") == 0); - std::string val = meta.metaValue("meta1"); - CPPUNIT_ASSERT(val == "testing"); - } else if(i == 2) { - CPPUNIT_ASSERT(iter->first.compare("meta2") == 0); - int32_t val = meta.metaValue("meta2"); - CPPUNIT_ASSERT(val == 20); - } else if(i == 3) { - CPPUNIT_ASSERT(iter->first.compare("meta3") == 0); - float val = meta.metaValue("meta3"); - //CPPUNIT_ASSERT(val == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0f,val,0); - } - } -} - -void -TestMetaMap::testRemove() -{ - using namespace openvdb; - - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", FloatMetadata(2.0)); - - meta.removeMeta("meta2"); - - MetaMap::MetaIterator iter = meta.beginMeta(); - int i = 1; - for( ; iter != meta.endMeta(); ++iter, ++i) { - if(i == 1) { - CPPUNIT_ASSERT(iter->first.compare("meta1") == 0); - std::string val = meta.metaValue("meta1"); - CPPUNIT_ASSERT(val == "testing"); - } else if(i == 2) { - CPPUNIT_ASSERT(iter->first.compare("meta3") == 0); - float val = meta.metaValue("meta3"); - //CPPUNIT_ASSERT(val == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0f,val,0); - } - } - - meta.removeMeta("meta1"); - - iter = meta.beginMeta(); - for( ; iter != meta.endMeta(); ++iter, ++i) { - CPPUNIT_ASSERT(iter->first.compare("meta3") == 0); - float val = meta.metaValue("meta3"); - //CPPUNIT_ASSERT(val == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0f,val,0); - } - - meta.removeMeta("meta3"); - - CPPUNIT_ASSERT_EQUAL(0, int(meta.metaCount())); -} - -void -TestMetaMap::testGetMetadata() -{ - using namespace openvdb; - - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", DoubleMetadata(2.0)); - - Metadata::Ptr metadata = meta["meta2"]; - CPPUNIT_ASSERT(metadata); - CPPUNIT_ASSERT(metadata->typeName().compare("int32") == 0); - - DoubleMetadata::Ptr dm = meta.getMetadata("meta3"); - //CPPUNIT_ASSERT(dm->value() == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0,dm->value(),0); - - const DoubleMetadata::Ptr cdm = meta.getMetadata("meta3"); - //CPPUNIT_ASSERT(dm->value() == 2.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0,cdm->value(),0); - - CPPUNIT_ASSERT(meta.getMetadata("meta2") == NULL); - - CPPUNIT_ASSERT_THROW(meta.metaValue("meta3"), - openvdb::TypeError); - - CPPUNIT_ASSERT_THROW(meta.metaValue("meta5"), - openvdb::LookupError); -} - -void -TestMetaMap::testIO() -{ - using namespace openvdb; - - Metadata::clearRegistry(); - - // Write some metadata using unregistered types. - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", DoubleMetadata(2.0)); - std::ostringstream ostr(std::ios_base::binary); - meta.writeMeta(ostr); - - // Verify that reading metadata of unregistered types is possible, - // though the values cannot be retrieved. - MetaMap meta2; - std::istringstream istr(ostr.str(), std::ios_base::binary); - CPPUNIT_ASSERT_NO_THROW(meta2.readMeta(istr)); - CPPUNIT_ASSERT_EQUAL(0, int(meta2.metaCount())); - - // Register just one of the three types, then reread and verify that - // the value of the registered type can be retrieved. - Int32Metadata::registerType(); - istr.seekg(0, std::ios_base::beg); - CPPUNIT_ASSERT_NO_THROW(meta2.readMeta(istr)); - CPPUNIT_ASSERT_EQUAL(size_t(1), meta2.metaCount()); - CPPUNIT_ASSERT_EQUAL(meta.metaValue("meta2"), meta2.metaValue("meta2")); - - // Register the remaining types. - StringMetadata::registerType(); - DoubleMetadata::registerType(); - - // Now seek to beginning and read again. - istr.seekg(0, std::ios_base::beg); - meta2.clearMetadata(); - - CPPUNIT_ASSERT_NO_THROW(meta2.readMeta(istr)); - CPPUNIT_ASSERT_EQUAL(meta.metaCount(), meta2.metaCount()); - - std::string val = meta.metaValue("meta1"); - std::string val2 = meta2.metaValue("meta1"); - CPPUNIT_ASSERT_EQUAL(0, val.compare(val2)); - - int intval = meta.metaValue("meta2"); - int intval2 = meta2.metaValue("meta2"); - CPPUNIT_ASSERT_EQUAL(intval, intval2); - - double dval = meta.metaValue("meta3"); - double dval2 = meta2.metaValue("meta3"); - CPPUNIT_ASSERT_DOUBLES_EQUAL(dval, dval2,0); - - // Clear the registry once the test is done. - Metadata::clearRegistry(); -} - -void -TestMetaMap::testEmptyIO() -{ - using namespace openvdb; - - MetaMap meta; - - // Write out an empty metadata - std::ostringstream ostr(std::ios_base::binary); - - // Read in the metadata; - MetaMap meta2; - std::istringstream istr(ostr.str(), std::ios_base::binary); - CPPUNIT_ASSERT_NO_THROW(meta2.readMeta(istr)); - - CPPUNIT_ASSERT(meta2.metaCount() == 0); -} - -void -TestMetaMap::testCopyConstructor() -{ - using namespace openvdb; - - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", FloatMetadata(2.0)); - - // copy constructor - MetaMap meta2(meta); - - CPPUNIT_ASSERT(meta.metaCount() == meta2.metaCount()); - - std::string str = meta.metaValue("meta1"); - std::string str2 = meta2.metaValue("meta1"); - CPPUNIT_ASSERT(str == str2); - - CPPUNIT_ASSERT(meta.metaValue("meta2") == - meta2.metaValue("meta2")); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(meta.metaValue("meta3"), - meta2.metaValue("meta3"),0); - //CPPUNIT_ASSERT(meta.metaValue("meta3") == - // meta2.metaValue("meta3")); -} - - -void -TestMetaMap::testCopyConstructorEmpty() -{ - using namespace openvdb; - - MetaMap meta; - - MetaMap meta2(meta); - - CPPUNIT_ASSERT(meta.metaCount() == 0); - CPPUNIT_ASSERT(meta2.metaCount() == meta.metaCount()); -} - - -void -TestMetaMap::testAssignment() -{ - using namespace openvdb; - - // Populate a map with data. - MetaMap meta; - meta.insertMeta("meta1", StringMetadata("testing")); - meta.insertMeta("meta2", Int32Metadata(20)); - meta.insertMeta("meta3", FloatMetadata(2.0)); - - // Create an empty map. - MetaMap meta2; - CPPUNIT_ASSERT_EQUAL(0, int(meta2.metaCount())); - - // Copy the first map to the second. - meta2 = meta; - CPPUNIT_ASSERT_EQUAL(meta.metaCount(), meta2.metaCount()); - - // Verify that the contents of the two maps are the same. - CPPUNIT_ASSERT_EQUAL( - meta.metaValue("meta1"), meta2.metaValue("meta1")); - CPPUNIT_ASSERT_EQUAL(meta.metaValue("meta2"), meta2.metaValue("meta2")); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - meta.metaValue("meta3"), meta2.metaValue("meta3"), /*tolerance=*/0); - - // Verify that changing one map doesn't affect the other. - meta.insertMeta("meta1", StringMetadata("changed")); - std::string str = meta.metaValue("meta1"); - CPPUNIT_ASSERT_EQUAL(std::string("testing"), meta2.metaValue("meta1")); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMetadata.cc b/openvdb_3_0_0_library/unittest/TestMetadata.cc deleted file mode 100755 index 8177b55..0000000 --- a/openvdb_3_0_0_library/unittest/TestMetadata.cc +++ /dev/null @@ -1,127 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestMetadata : public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::Metadata::clearRegistry(); } - virtual void tearDown() { openvdb::Metadata::clearRegistry(); } - - CPPUNIT_TEST_SUITE(TestMetadata); - CPPUNIT_TEST(testMetadataRegistry); - CPPUNIT_TEST(testMetadataAsBool); - CPPUNIT_TEST_SUITE_END(); - - void testMetadataRegistry(); - void testMetadataAsBool(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadata); - -void -TestMetadata::testMetadataRegistry() -{ - using namespace openvdb; - - Int32Metadata::registerType(); - - StringMetadata strMetadata; - - CPPUNIT_ASSERT(!Metadata::isRegisteredType(strMetadata.typeName())); - - StringMetadata::registerType(); - - CPPUNIT_ASSERT(Metadata::isRegisteredType(strMetadata.typeName())); - CPPUNIT_ASSERT( - Metadata::isRegisteredType(Int32Metadata::staticTypeName())); - - Metadata::Ptr stringMetadata = - Metadata::createMetadata(strMetadata.typeName()); - - CPPUNIT_ASSERT(stringMetadata->typeName() == strMetadata.typeName()); - - StringMetadata::unregisterType(); - - CPPUNIT_ASSERT_THROW(Metadata::createMetadata(strMetadata.typeName()), - openvdb::LookupError); -} - -void -TestMetadata::testMetadataAsBool() -{ - using namespace openvdb; - - { - FloatMetadata meta(0.0); - CPPUNIT_ASSERT(!meta.asBool()); - meta.setValue(1.0); - CPPUNIT_ASSERT(meta.asBool()); - meta.setValue(-1.0); - CPPUNIT_ASSERT(meta.asBool()); - meta.setValue(999.0); - CPPUNIT_ASSERT(meta.asBool()); - } - { - Int32Metadata meta(0); - CPPUNIT_ASSERT(!meta.asBool()); - meta.setValue(1); - CPPUNIT_ASSERT(meta.asBool()); - meta.setValue(-1); - CPPUNIT_ASSERT(meta.asBool()); - meta.setValue(999); - CPPUNIT_ASSERT(meta.asBool()); - } - { - StringMetadata meta(""); - CPPUNIT_ASSERT(!meta.asBool()); - meta.setValue("abc"); - CPPUNIT_ASSERT(meta.asBool()); - } - { - Vec3IMetadata meta(Vec3i(0)); - CPPUNIT_ASSERT(!meta.asBool()); - meta.setValue(Vec3i(-1, 0, 1)); - CPPUNIT_ASSERT(meta.asBool()); - } - { - Vec3SMetadata meta(Vec3s(0.0)); - CPPUNIT_ASSERT(!meta.asBool()); - meta.setValue(Vec3s(-1.0, 0.0, 1.0)); - CPPUNIT_ASSERT(meta.asBool()); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestMetadataIO.cc b/openvdb_3_0_0_library/unittest/TestMetadataIO.cc deleted file mode 100755 index ca230fd..0000000 --- a/openvdb_3_0_0_library/unittest/TestMetadataIO.cc +++ /dev/null @@ -1,264 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -// CPPUNIT_TEST_SUITE() invokes CPPUNIT_TESTNAMER_DECL() to generate a suite name -// from the FixtureType. But if FixtureType is a templated type, the generated name -// can become long and messy. This macro overrides the normal naming logic, -// instead invoking FixtureType::testSuiteName(), which should be a static member -// function that returns a std::string containing the suite name for the specific -// template instantiation. -#undef CPPUNIT_TESTNAMER_DECL -#define CPPUNIT_TESTNAMER_DECL( variableName, FixtureType ) \ - CPPUNIT_NS::TestNamer variableName( FixtureType::testSuiteName() ) - -template -class TestMetadataIO: public CppUnit::TestCase -{ -public: - static std::string testSuiteName() - { - std::string name = openvdb::typeNameAsString(); - if (!name.empty()) name[0] = static_cast(::toupper(name[0])); - return "TestMetadataIO" + name; - } - - CPPUNIT_TEST_SUITE(TestMetadataIO); - CPPUNIT_TEST(test); - CPPUNIT_TEST(testMultiple); - CPPUNIT_TEST_SUITE_END(); - - void test(); - void testMultiple(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); -CPPUNIT_TEST_SUITE_REGISTRATION(TestMetadataIO); - - -template -void -TestMetadataIO::test() -{ - using namespace openvdb; - - TypedMetadata m(1); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm; - tm.read(istr); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(T(1),tm.value(),0); - //CPPUNIT_ASSERT(tm.value() == T(1)); -} - - -template -void -TestMetadataIO::testMultiple() -{ - using namespace openvdb; - - TypedMetadata m(1); - TypedMetadata m2(2); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - m2.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm, tm2; - tm.read(istr); - tm2.read(istr); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(T(1),tm.value(),0); - //CPPUNIT_ASSERT(tm.value() == T(1)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(T(2),tm2.value(),0); - //CPPUNIT_ASSERT(tm2.value() == T(2)); -} - - -template<> -void -TestMetadataIO::test() -{ - using namespace openvdb; - - TypedMetadata m("test"); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm; - tm.read(istr); - - CPPUNIT_ASSERT(tm.value() == "test"); -} - - -template<> -void -TestMetadataIO::testMultiple() -{ - using namespace openvdb; - - TypedMetadata m("test"); - TypedMetadata m2("test2"); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - m2.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm, tm2; - tm.read(istr); - tm2.read(istr); - - CPPUNIT_ASSERT(tm.value() == "test"); - CPPUNIT_ASSERT(tm2.value() == "test2"); -} - - -template<> -void -TestMetadataIO::test() -{ - using namespace openvdb; - - TypedMetadata m(Vec3R(1, 2, 3)); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm; - tm.read(istr); - - CPPUNIT_ASSERT(tm.value() == Vec3R(1, 2, 3)); -} - - -template<> -void -TestMetadataIO::testMultiple() -{ - using namespace openvdb; - - TypedMetadata m(Vec3R(1, 2, 3)); - TypedMetadata m2(Vec3R(4, 5, 6)); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - m2.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm, tm2; - tm.read(istr); - tm2.read(istr); - - CPPUNIT_ASSERT(tm.value() == Vec3R(1, 2, 3)); - CPPUNIT_ASSERT(tm2.value() == Vec3R(4, 5, 6)); -} - - -template<> -void -TestMetadataIO::test() -{ - using namespace openvdb; - - TypedMetadata m(Vec2i(1, 2)); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm; - tm.read(istr); - - CPPUNIT_ASSERT(tm.value() == Vec2i(1, 2)); -} - - -template<> -void -TestMetadataIO::testMultiple() -{ - using namespace openvdb; - - TypedMetadata m(Vec2i(1, 2)); - TypedMetadata m2(Vec2i(3, 4)); - - std::ostringstream ostr(std::ios_base::binary); - - m.write(ostr); - m2.write(ostr); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - TypedMetadata tm, tm2; - tm.read(istr); - tm2.read(istr); - - CPPUNIT_ASSERT(tm.value() == Vec2i(1, 2)); - CPPUNIT_ASSERT(tm2.value() == Vec2i(3, 4)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestName.cc b/openvdb_3_0_0_library/unittest/TestName.cc deleted file mode 100755 index b91b2f2..0000000 --- a/openvdb_3_0_0_library/unittest/TestName.cc +++ /dev/null @@ -1,112 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestName : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestName); - CPPUNIT_TEST(test); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testMultipleIO); - CPPUNIT_TEST_SUITE_END(); - - void test(); - void testIO(); - void testMultipleIO(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestName); - -void -TestName::test() -{ - using namespace openvdb; - - Name name; - Name name2("something"); - Name name3 = std::string("something2"); - name = "something"; - - CPPUNIT_ASSERT(name == name2); - CPPUNIT_ASSERT(name != name3); - CPPUNIT_ASSERT(name != Name("testing")); - CPPUNIT_ASSERT(name == Name("something")); -} - -void -TestName::testIO() -{ - using namespace openvdb; - - Name name("some name that i made up"); - - std::ostringstream ostr(std::ios_base::binary); - - openvdb::writeString(ostr, name); - - name = "some other name"; - - CPPUNIT_ASSERT(name == Name("some other name")); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - name = openvdb::readString(istr); - - CPPUNIT_ASSERT(name == Name("some name that i made up")); -} - -void -TestName::testMultipleIO() -{ - using namespace openvdb; - - Name name("some name that i made up"); - Name name2("something else"); - - std::ostringstream ostr(std::ios_base::binary); - - openvdb::writeString(ostr, name); - openvdb::writeString(ostr, name2); - - std::istringstream istr(ostr.str(), std::ios_base::binary); - - Name n = openvdb::readString(istr), n2 = openvdb::readString(istr); - - CPPUNIT_ASSERT(name == n); - CPPUNIT_ASSERT(name2 == n2); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestNodeIterator.cc b/openvdb_3_0_0_library/unittest/TestNodeIterator.cc deleted file mode 100755 index ece2ef4..0000000 --- a/openvdb_3_0_0_library/unittest/TestNodeIterator.cc +++ /dev/null @@ -1,406 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include - - -class TestNodeIterator: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestNodeIterator); - CPPUNIT_TEST(testEmpty); - CPPUNIT_TEST(testSinglePositive); - CPPUNIT_TEST(testSingleNegative); - CPPUNIT_TEST(testMultipleBlocks); - CPPUNIT_TEST(testDepthBounds); - CPPUNIT_TEST_SUITE_END(); - - void testEmpty(); - void testSinglePositive(); - void testSingleNegative(); - void testMultipleBlocks(); - void testDepthBounds(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestNodeIterator); - -namespace { -typedef openvdb::tree::Tree4::Type Tree323f; -} - - -//////////////////////////////////////// - - -void -TestNodeIterator::testEmpty() -{ - Tree323f tree(/*fillValue=*/256.0f); - { - Tree323f::NodeCIter iter(tree); - CPPUNIT_ASSERT(!iter.next()); - } - { - tree.setValue(openvdb::Coord(8, 16, 24), 10.f); - Tree323f::NodeIter iter(tree); // non-const - CPPUNIT_ASSERT(iter); - - // Try modifying the tree through a non-const iterator. - Tree323f::RootNodeType* root = NULL; - iter.getNode(root); - CPPUNIT_ASSERT(root != NULL); - root->clear(); - - // Verify that the tree is now empty. - iter = Tree323f::NodeIter(tree); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT(!iter.next()); - } -} - - -void -TestNodeIterator::testSinglePositive() -{ - { - Tree323f tree(/*fillValue=*/256.0f); - - tree.setValue(openvdb::Coord(8, 16, 24), 10.f); - - Tree323f::NodeCIter iter(tree); - - CPPUNIT_ASSERT(Tree323f::LeafNodeType::DIM == 8); - - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getDepth()); - CPPUNIT_ASSERT_EQUAL(tree.treeDepth(), 1 + iter.getLevel()); - openvdb::CoordBBox range, bbox; - tree.getIndexRange(range); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(bbox.min(), range.min()); - CPPUNIT_ASSERT_EQUAL(bbox.max(), range.max()); - - // Descend to the depth-1 internal node with bounding box - // (0, 0, 0) -> (255, 255, 255) containing voxel (8, 16, 24). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord((1 << (3 + 2 + 3)) - 1), bbox.max()); - - // Descend to the depth-2 internal node with bounding box - // (0, 0, 0) -> (31, 31, 31) containing voxel (8, 16, 24). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord((1 << (2 + 3)) - 1), bbox.max()); - - // Descend to the leaf node with bounding box (8, 16, 24) -> (15, 23, 31) - // containing voxel (8, 16, 24). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - iter.getBoundingBox(bbox); - range.min().reset(8, 16, 24); - range.max() = range.min().offsetBy((1 << 3) - 1); // add leaf node size - CPPUNIT_ASSERT_EQUAL(range.min(), bbox.min()); - CPPUNIT_ASSERT_EQUAL(range.max(), bbox.max()); - - iter.next(); - CPPUNIT_ASSERT(!iter); - } - { - Tree323f tree(/*fillValue=*/256.0f); - - tree.setValue(openvdb::Coord(129), 10.f); - - Tree323f::NodeCIter iter(tree); - - CPPUNIT_ASSERT(Tree323f::LeafNodeType::DIM == 8); - - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getDepth()); - CPPUNIT_ASSERT_EQUAL(tree.treeDepth(), 1 + iter.getLevel()); - openvdb::CoordBBox range, bbox; - tree.getIndexRange(range); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(bbox.min(), range.min()); - CPPUNIT_ASSERT_EQUAL(bbox.max(), range.max()); - - // Descend to the depth-1 internal node with bounding box - // (0, 0, 0) -> (255, 255, 255) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord((1 << (3 + 2 + 3)) - 1), bbox.max()); - - // Descend to the depth-2 internal node with bounding box - // (128, 128, 128) -> (159, 159, 159) containing voxel (129, 129, 129). - // (128 is the nearest multiple of 32 less than 129.) - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - iter.getBoundingBox(bbox); - range.min().reset(128, 128, 128); - CPPUNIT_ASSERT_EQUAL(range.min(), bbox.min()); - CPPUNIT_ASSERT_EQUAL(range.min().offsetBy((1 << (2 + 3)) - 1), bbox.max()); - - // Descend to the leaf node with bounding box - // (128, 128, 128) -> (135, 135, 135) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - iter.getBoundingBox(bbox); - range.max() = range.min().offsetBy((1 << 3) - 1); // add leaf node size - CPPUNIT_ASSERT_EQUAL(range.min(), bbox.min()); - CPPUNIT_ASSERT_EQUAL(range.max(), bbox.max()); - - iter.next(); - CPPUNIT_ASSERT(!iter); - } -} - - -void -TestNodeIterator::testSingleNegative() -{ - Tree323f tree(/*fillValue=*/256.0f); - - tree.setValue(openvdb::Coord(-1), 10.f); - - Tree323f::NodeCIter iter(tree); - - CPPUNIT_ASSERT(Tree323f::LeafNodeType::DIM == 8); - - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getDepth()); - CPPUNIT_ASSERT_EQUAL(tree.treeDepth(), 1 + iter.getLevel()); - openvdb::CoordBBox range, bbox; - tree.getIndexRange(range); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(bbox.min(), range.min()); - CPPUNIT_ASSERT_EQUAL(bbox.max(), range.max()); - - // Descend to the depth-1 internal node with bounding box - // (-256, -256, -256) -> (-1, -1, -1) containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-(1 << (3 + 2 + 3))), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-1), bbox.max()); - - // Descend to the depth-2 internal node with bounding box - // (-32, -32, -32) -> (-1, -1, -1) containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-(1 << (2 + 3))), bbox.min()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(-1), bbox.max()); - - // Descend to the leaf node with bounding box (-8, -8, -8) -> (-1, -1, -1) - // containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - iter.getBoundingBox(bbox); - range.max().reset(-1, -1, -1); - range.min() = range.max().offsetBy(-((1 << 3) - 1)); // add leaf node size - CPPUNIT_ASSERT_EQUAL(range.min(), bbox.min()); - CPPUNIT_ASSERT_EQUAL(range.max(), bbox.max()); - - iter.next(); - CPPUNIT_ASSERT(!iter); -} - - -void -TestNodeIterator::testMultipleBlocks() -{ - Tree323f tree(/*fillValue=*/256.0f); - - tree.setValue(openvdb::Coord(-1), 10.f); - tree.setValue(openvdb::Coord(129), 10.f); - - Tree323f::NodeCIter iter(tree); - - CPPUNIT_ASSERT(Tree323f::LeafNodeType::DIM == 8); - - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getDepth()); - CPPUNIT_ASSERT_EQUAL(tree.treeDepth(), 1 + iter.getLevel()); - - // Descend to the depth-1 internal node with bounding box - // (-256, -256, -256) -> (-1, -1, -1) containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Descend to the depth-2 internal node with bounding box - // (-32, -32, -32) -> (-1, -1, -1) containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - - // Descend to the leaf node with bounding box (-8, -8, -8) -> (-1, -1, -1) - // containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - openvdb::Coord expectedMin, expectedMax(-1, -1, -1); - expectedMin = expectedMax.offsetBy(-((1 << 3) - 1)); // add leaf node size - openvdb::CoordBBox bbox; - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(expectedMin, bbox.min()); - CPPUNIT_ASSERT_EQUAL(expectedMax, bbox.max()); - - // Ascend to the depth-1 internal node with bounding box (0, 0, 0) -> (255, 255, 255) - // containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Descend to the depth-2 internal node with bounding box - // (128, 128, 128) -> (159, 159, 159) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - - // Descend to the leaf node with bounding box (128, 128, 128) -> (135, 135, 135) - // containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - expectedMin.reset(128, 128, 128); - expectedMax = expectedMin.offsetBy((1 << 3) - 1); // add leaf node size - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(expectedMin, bbox.min()); - CPPUNIT_ASSERT_EQUAL(expectedMax, bbox.max()); - - iter.next(); - CPPUNIT_ASSERT(!iter); -} - - -void -TestNodeIterator::testDepthBounds() -{ - Tree323f tree(/*fillValue=*/256.0f); - - tree.setValue(openvdb::Coord(-1), 10.f); - tree.setValue(openvdb::Coord(129), 10.f); - - { - // Iterate over internal nodes only. - Tree323f::NodeCIter iter(tree); - iter.setMaxDepth(2); - iter.setMinDepth(1); - - // Begin at the depth-1 internal node with bounding box - // (-256, -256, -256) -> (-1, -1, -1) containing voxel (-1, -1, -1). - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Descend to the depth-2 internal node with bounding box - // (-32, -32, -32) -> (-1, -1, -1) containing voxel (-1, -1, -1). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - - // Skipping the leaf node, ascend to the depth-1 internal node with bounding box - // (0, 0, 0) -> (255, 255, 255) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Descend to the depth-2 internal node with bounding box - // (128, 128, 128) -> (159, 159, 159) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(2U, iter.getDepth()); - - // Verify that no internal nodes remain unvisited. - iter.next(); - CPPUNIT_ASSERT(!iter); - } - { - // Iterate over depth-1 internal nodes only. - Tree323f::NodeCIter iter(tree); - iter.setMaxDepth(1); - iter.setMinDepth(1); - - // Begin at the depth-1 internal node with bounding box - // (-256, -256, -256) -> (-1, -1, -1) containing voxel (-1, -1, -1). - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Skip to the depth-1 internal node with bounding box - // (0, 0, 0) -> (255, 255, 255) containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(1U, iter.getDepth()); - - // Verify that no depth-1 nodes remain unvisited. - iter.next(); - CPPUNIT_ASSERT(!iter); - } - { - // Iterate over leaf nodes only. - Tree323f::NodeCIter iter = tree.cbeginNode(); - iter.setMaxDepth(3); - iter.setMinDepth(3); - - // Begin at the leaf node with bounding box (-8, -8, -8) -> (-1, -1, -1) - // containing voxel (-1, -1, -1). - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - - // Skip to the leaf node with bounding box (128, 128, 128) -> (135, 135, 135) - // containing voxel (129, 129, 129). - iter.next(); - CPPUNIT_ASSERT(iter); - CPPUNIT_ASSERT_EQUAL(0U, iter.getLevel()); - - // Verify that no leaf nodes remain unvisited. - iter.next(); - CPPUNIT_ASSERT(!iter); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestNodeMask.cc b/openvdb_3_0_0_library/unittest/TestNodeMask.cc deleted file mode 100755 index 4c4d89f..0000000 --- a/openvdb_3_0_0_library/unittest/TestNodeMask.cc +++ /dev/null @@ -1,172 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -using openvdb::Index; - -template void TestAll(); - -class TestNodeMask: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestNodeMask); - CPPUNIT_TEST(testAll4); - CPPUNIT_TEST(testAll3); - CPPUNIT_TEST(testAll2); - CPPUNIT_TEST(testAll1); - CPPUNIT_TEST_SUITE_END(); - - void testAll4() { TestAll >(); } - void testAll3() { TestAll >(); } - void testAll2() { TestAll >(); } - void testAll1() { TestAll >(); } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestNodeMask); - -template -void TestAll() -{ - CPPUNIT_ASSERT(MaskType::memUsage() == MaskType::SIZE/8); - const Index SIZE = MaskType::SIZE > 512 ? 512 : MaskType::SIZE; - - {// default constructor - MaskType m;//all bits are off - for (Index i=0; i -#include -#include -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - - -class TestParticlesToLevelSet: public CppUnit::TestFixture -{ -public: - virtual void setUp() {openvdb::initialize();} - virtual void tearDown() {openvdb::uninitialize();} - - void writeGrid(openvdb::GridBase::Ptr grid, std::string fileName) const - { - std::cout << "\nWriting \""<setName("TestParticlesToLevelSet"); - openvdb::GridPtrVec grids; - grids.push_back(grid); - openvdb::io::File file("/tmp/" + fileName + ".vdb"); - file.write(grids); - file.close(); - } - - CPPUNIT_TEST_SUITE(TestParticlesToLevelSet); - CPPUNIT_TEST(testMyParticleList); - CPPUNIT_TEST(testRasterizeSpheres); - CPPUNIT_TEST(testRasterizeSpheresAndId); - CPPUNIT_TEST(testRasterizeTrails); - CPPUNIT_TEST(testRasterizeTrailsAndId); - CPPUNIT_TEST_SUITE_END(); - - void testMyParticleList(); - void testRasterizeSpheres(); - void testRasterizeSpheresAndId(); - void testRasterizeTrails(); - void testRasterizeTrailsAndId(); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestParticlesToLevelSet); - -class MyParticleList -{ -protected: - struct MyParticle { - openvdb::Vec3R p, v; - openvdb::Real r; - }; - openvdb::Real mRadiusScale; - openvdb::Real mVelocityScale; - std::vector mParticleList; -public: - - typedef openvdb::Vec3R value_type; - - MyParticleList(openvdb::Real rScale=1, openvdb::Real vScale=1) - : mRadiusScale(rScale), mVelocityScale(vScale) {} - void add(const openvdb::Vec3R &p, const openvdb::Real &r, - const openvdb::Vec3R &v=openvdb::Vec3R(0,0,0)) - { - MyParticle pa; - pa.p = p; - pa.r = r; - pa.v = v; - mParticleList.push_back(pa); - } - /// @return coordinate bbox in the space of the specified transfrom - openvdb::CoordBBox getBBox(const openvdb::GridBase& grid) { - openvdb::CoordBBox bbox; - openvdb::Coord &min= bbox.min(), &max = bbox.max(); - openvdb::Vec3R pos; - openvdb::Real rad, invDx = 1/grid.voxelSize()[0]; - for (size_t n=0, e=this->size(); ngetPosRad(n, pos, rad); - const openvdb::Vec3d xyz = grid.worldToIndex(pos); - const openvdb::Real r = rad * invDx; - for (int i=0; i<3; ++i) { - min[i] = openvdb::math::Min(min[i], openvdb::math::Floor(xyz[i] - r)); - max[i] = openvdb::math::Max(max[i], openvdb::math::Ceil( xyz[i] + r)); - } - } - return bbox; - } - //typedef int AttributeType; - // The methods below are only required for the unit-tests - openvdb::Vec3R pos(int n) const {return mParticleList[n].p;} - openvdb::Vec3R vel(int n) const {return mVelocityScale*mParticleList[n].v;} - openvdb::Real radius(int n) const {return mRadiusScale*mParticleList[n].r;} - - ////////////////////////////////////////////////////////////////////////////// - /// The methods below are the only ones required by tools::ParticleToLevelSet - /// @note We return by value since the radius and velocities are modified - /// by the scaling factors! Also these methods are all assumed to - /// be thread-safe. - - /// Return the total number of particles in list. - /// Always required! - size_t size() const { return mParticleList.size(); } - - /// Get the world space position of n'th particle. - /// Required by ParticledToLevelSet::rasterizeSphere(*this,radius). - void getPos(size_t n, openvdb::Vec3R&pos) const { pos = mParticleList[n].p; } - - - void getPosRad(size_t n, openvdb::Vec3R& pos, openvdb::Real& rad) const { - pos = mParticleList[n].p; - rad = mRadiusScale*mParticleList[n].r; - } - void getPosRadVel(size_t n, openvdb::Vec3R& pos, openvdb::Real& rad, openvdb::Vec3R& vel) const { - pos = mParticleList[n].p; - rad = mRadiusScale*mParticleList[n].r; - vel = mVelocityScale*mParticleList[n].v; - } - // The method below is only required for attribute transfer - void getAtt(size_t n, openvdb::Index32& att) const { att = openvdb::Index32(n); } -}; - - -void -TestParticlesToLevelSet::testMyParticleList() -{ - MyParticleList pa; - CPPUNIT_ASSERT_EQUAL(0, int(pa.size())); - pa.add(openvdb::Vec3R(10,10,10), 2, openvdb::Vec3R(1,0,0)); - CPPUNIT_ASSERT_EQUAL(1, int(pa.size())); - ASSERT_DOUBLES_EXACTLY_EQUAL(10, pa.pos(0)[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(10, pa.pos(0)[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(10, pa.pos(0)[2]); - ASSERT_DOUBLES_EXACTLY_EQUAL(1 , pa.vel(0)[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0 , pa.vel(0)[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0 , pa.vel(0)[2]); - ASSERT_DOUBLES_EXACTLY_EQUAL(2 , pa.radius(0)); - pa.add(openvdb::Vec3R(20,20,20), 3); - CPPUNIT_ASSERT_EQUAL(2, int(pa.size())); - ASSERT_DOUBLES_EXACTLY_EQUAL(20, pa.pos(1)[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20, pa.pos(1)[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(20, pa.pos(1)[2]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0 , pa.vel(1)[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0 , pa.vel(1)[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL(0 , pa.vel(1)[2]); - ASSERT_DOUBLES_EXACTLY_EQUAL(3 , pa.radius(1)); - - const float voxelSize = 0.5f, halfWidth = 4.0f; - openvdb::FloatGrid::Ptr ls = openvdb::createLevelSet(voxelSize, halfWidth); - openvdb::CoordBBox bbox = pa.getBBox(*ls); - ASSERT_DOUBLES_EXACTLY_EQUAL((10-2)/voxelSize, bbox.min()[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL((10-2)/voxelSize, bbox.min()[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL((10-2)/voxelSize, bbox.min()[2]); - ASSERT_DOUBLES_EXACTLY_EQUAL((20+3)/voxelSize, bbox.max()[0]); - ASSERT_DOUBLES_EXACTLY_EQUAL((20+3)/voxelSize, bbox.max()[1]); - ASSERT_DOUBLES_EXACTLY_EQUAL((20+3)/voxelSize, bbox.max()[2]); -} - - -void -TestParticlesToLevelSet::testRasterizeSpheres() -{ - MyParticleList pa; - pa.add(openvdb::Vec3R(10,10,10), 2); - pa.add(openvdb::Vec3R(20,20,20), 2); - // testing CSG - pa.add(openvdb::Vec3R(31.0,31,31), 5); - pa.add(openvdb::Vec3R(31.5,31,31), 5); - pa.add(openvdb::Vec3R(32.0,31,31), 5); - pa.add(openvdb::Vec3R(32.5,31,31), 5); - pa.add(openvdb::Vec3R(33.0,31,31), 5); - pa.add(openvdb::Vec3R(33.5,31,31), 5); - pa.add(openvdb::Vec3R(34.0,31,31), 5); - pa.add(openvdb::Vec3R(34.5,31,31), 5); - pa.add(openvdb::Vec3R(35.0,31,31), 5); - pa.add(openvdb::Vec3R(35.5,31,31), 5); - pa.add(openvdb::Vec3R(36.0,31,31), 5); - CPPUNIT_ASSERT_EQUAL(13, int(pa.size())); - - const float voxelSize = 1.0f, halfWidth = 2.0f; - openvdb::FloatGrid::Ptr ls = openvdb::createLevelSet(voxelSize, halfWidth); - openvdb::tools::ParticlesToLevelSet raster(*ls); - - raster.setGrainSize(1);//a value of zero disables threading - raster.rasterizeSpheres(pa); - raster.finalize(); - //openvdb::FloatGrid::Ptr ls = raster.getSdfGrid(); - - //ls->tree().print(std::cout,4); - //this->writeGrid(ls, "testRasterizeSpheres"); - - ASSERT_DOUBLES_EXACTLY_EQUAL(halfWidth * voxelSize, - ls->tree().getValue(openvdb::Coord( 0, 0, 0))); - - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord( 6,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord( 7,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord( 8,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord( 9,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-2, ls->tree().getValue(openvdb::Coord(10,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(11,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(12,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(13,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(14,10,10))); - - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(20,16,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(20,17,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(20,18,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(20,19,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-2, ls->tree().getValue(openvdb::Coord(20,20,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(20,21,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(20,22,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(20,23,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(20,24,20))); - {// full but slow test of all voxels - openvdb::CoordBBox bbox = pa.getBBox(*ls); - bbox.expand(static_cast(halfWidth)+1); - openvdb::Index64 count=0; - const float outside = ls->background(), inside = -outside; - const openvdb::Coord &min=bbox.min(), &max=bbox.max(); - for (openvdb::Coord ijk=min; ijk[0]indexToWorld(ijk.asVec3d()); - double dist = (xyz-pa.pos(0)).length()-pa.radius(0); - for (int i = 1, s = int(pa.size()); i < s; ++i) { - dist=openvdb::math::Min(dist,(xyz-pa.pos(i)).length()-pa.radius(i)); - } - const float val = ls->tree().getValue(ijk); - if (dist >= outside) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(outside, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOff(ijk)); - } else if( dist <= inside ) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(inside, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOff(ijk)); - } else { - CPPUNIT_ASSERT_DOUBLES_EQUAL( dist, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOn(ijk)); - ++count; - } - } - } - } - //std::cerr << "\nExpected active voxel count = " << count - // << ", actual active voxle count = " - // << ls->activeVoxelCount() << std::endl; - CPPUNIT_ASSERT_EQUAL(count, ls->activeVoxelCount()); - } -} - - -void -TestParticlesToLevelSet::testRasterizeSpheresAndId() -{ - MyParticleList pa(0.5f); - pa.add(openvdb::Vec3R(10,10,10), 4); - pa.add(openvdb::Vec3R(20,20,20), 4); - // testing CSG - pa.add(openvdb::Vec3R(31.0,31,31),10); - pa.add(openvdb::Vec3R(31.5,31,31),10); - pa.add(openvdb::Vec3R(32.0,31,31),10); - pa.add(openvdb::Vec3R(32.5,31,31),10); - pa.add(openvdb::Vec3R(33.0,31,31),10); - pa.add(openvdb::Vec3R(33.5,31,31),10); - pa.add(openvdb::Vec3R(34.0,31,31),10); - pa.add(openvdb::Vec3R(34.5,31,31),10); - pa.add(openvdb::Vec3R(35.0,31,31),10); - pa.add(openvdb::Vec3R(35.5,31,31),10); - pa.add(openvdb::Vec3R(36.0,31,31),10); - CPPUNIT_ASSERT_EQUAL(13, int(pa.size())); - - typedef openvdb::tools::ParticlesToLevelSet RasterT; - const float voxelSize = 1.0f, halfWidth = 2.0f; - openvdb::FloatGrid::Ptr ls = openvdb::createLevelSet(voxelSize, halfWidth); - - RasterT raster(*ls); - raster.setGrainSize(1);//a value of zero disables threading - raster.rasterizeSpheres(pa); - raster.finalize(); - const RasterT::AttGridType::Ptr id = raster.attributeGrid(); - - int minVal = std::numeric_limits::max(), maxVal = -minVal; - for (RasterT::AttGridType::ValueOnCIter i=id->cbeginValueOn(); i; ++i) { - minVal = openvdb::math::Min(minVal, int(*i)); - maxVal = openvdb::math::Max(maxVal, int(*i)); - } - CPPUNIT_ASSERT_EQUAL(0 , minVal); - CPPUNIT_ASSERT_EQUAL(12, maxVal); - - //grid.tree().print(std::cout,4); - //id->print(std::cout,4); - //this->writeGrid(ls, "testRasterizeSpheres"); - - ASSERT_DOUBLES_EXACTLY_EQUAL(halfWidth * voxelSize, - ls->tree().getValue(openvdb::Coord( 0, 0, 0))); - - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord( 6,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord( 7,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord( 8,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord( 9,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-2, ls->tree().getValue(openvdb::Coord(10,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(11,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(12,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(13,10,10))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(14,10,10))); - - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(20,16,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(20,17,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(20,18,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(20,19,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-2, ls->tree().getValue(openvdb::Coord(20,20,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(-1, ls->tree().getValue(openvdb::Coord(20,21,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 0, ls->tree().getValue(openvdb::Coord(20,22,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 1, ls->tree().getValue(openvdb::Coord(20,23,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL( 2, ls->tree().getValue(openvdb::Coord(20,24,20))); - - {// full but slow test of all voxels - openvdb::CoordBBox bbox = pa.getBBox(*ls); - bbox.expand(static_cast(halfWidth)+1); - openvdb::Index64 count = 0; - const float outside = ls->background(), inside = -outside; - const openvdb::Coord &min=bbox.min(), &max=bbox.max(); - for (openvdb::Coord ijk=min; ijk[0]indexToWorld(ijk.asVec3d()); - double dist = (xyz-pa.pos(0)).length()-pa.radius(0); - openvdb::Index32 k =0; - for (int i = 1, s = int(pa.size()); i < s; ++i) { - double d = (xyz-pa.pos(i)).length()-pa.radius(i); - if (dtree().getValue(ijk); - openvdb::Index32 m = id->tree().getValue(ijk); - if (dist >= outside) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(outside, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOff(ijk)); - //CPPUNIT_ASSERT_EQUAL(openvdb::util::INVALID_IDX, m); - CPPUNIT_ASSERT(id->tree().isValueOff(ijk)); - } else if( dist <= inside ) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(inside, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOff(ijk)); - //CPPUNIT_ASSERT_EQUAL(openvdb::util::INVALID_IDX, m); - CPPUNIT_ASSERT(id->tree().isValueOff(ijk)); - } else { - CPPUNIT_ASSERT_DOUBLES_EQUAL( dist, val, 0.0001); - CPPUNIT_ASSERT(ls->tree().isValueOn(ijk)); - CPPUNIT_ASSERT_EQUAL(k, m); - CPPUNIT_ASSERT(id->tree().isValueOn(ijk)); - ++count; - } - } - } - } - //std::cerr << "\nExpected active voxel count = " << count - // << ", actual active voxle count = " - // << ls->activeVoxelCount() << std::endl; - CPPUNIT_ASSERT_EQUAL(count, ls->activeVoxelCount()); - } -} - - -/// This is not really a conventional unit-test since the result of -/// the tests are written to a file and need to be visually verified! -void -TestParticlesToLevelSet::testRasterizeTrails() -{ - const float voxelSize = 1.0f, halfWidth = 2.0f; - openvdb::FloatGrid::Ptr ls = openvdb::createLevelSet(voxelSize, halfWidth); - - MyParticleList pa(1,5); - - // This particle radius = 1 < 1.5 i.e. it's below the Nyquist frequency and hence ignored - pa.add(openvdb::Vec3R( 0, 0, 0), 1, openvdb::Vec3R( 0, 1, 0)); - pa.add(openvdb::Vec3R(-10,-10,-10), 2, openvdb::Vec3R( 2, 0, 0)); - pa.add(openvdb::Vec3R( 10, 10, 10), 3, openvdb::Vec3R( 0, 1, 0)); - pa.add(openvdb::Vec3R( 0, 0, 0), 6, openvdb::Vec3R( 0, 0,-5)); - pa.add(openvdb::Vec3R( 20, 0, 0), 2, openvdb::Vec3R( 0, 0, 0)); - - openvdb::tools::ParticlesToLevelSet raster(*ls); - raster.rasterizeTrails(pa, 0.75);//scale offset between two instances - - //ls->tree().print(std::cout, 4); - //this->writeGrid(ls, "testRasterizeTrails"); -} - - -void -TestParticlesToLevelSet::testRasterizeTrailsAndId() -{ - MyParticleList pa(1,5); - - // This particle radius = 1 < 1.5 i.e. it's below the Nyquist frequency and hence ignored - pa.add(openvdb::Vec3R( 0, 0, 0), 1, openvdb::Vec3R( 0, 1, 0)); - pa.add(openvdb::Vec3R(-10,-10,-10), 2, openvdb::Vec3R( 2, 0, 0)); - pa.add(openvdb::Vec3R( 10, 10, 10), 3, openvdb::Vec3R( 0, 1, 0)); - pa.add(openvdb::Vec3R( 0, 0, 0), 6, openvdb::Vec3R( 0, 0,-5)); - - typedef openvdb::tools::ParticlesToLevelSet RasterT; - const float voxelSize = 1.0f, halfWidth = 2.0f; - openvdb::FloatGrid::Ptr ls = openvdb::createLevelSet(voxelSize, halfWidth); - RasterT raster(*ls); - raster.rasterizeTrails(pa, 0.75);//scale offset between two instances - raster.finalize(); - const RasterT::AttGridType::Ptr id = raster.attributeGrid(); - CPPUNIT_ASSERT(!ls->empty()); - CPPUNIT_ASSERT(!id->empty()); - CPPUNIT_ASSERT_EQUAL(ls->activeVoxelCount(),id->activeVoxelCount()); - - int min = std::numeric_limits::max(), max = -min; - for (RasterT::AttGridType::ValueOnCIter i=id->cbeginValueOn(); i; ++i) { - min = openvdb::math::Min(min, int(*i)); - max = openvdb::math::Max(max, int(*i)); - } - CPPUNIT_ASSERT_EQUAL(1, min);//first particle is ignored because of its small rdadius! - CPPUNIT_ASSERT_EQUAL(3, max); - - //ls->tree().print(std::cout, 4); - //this->writeGrid(ls, "testRasterizeTrails"); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestPointIndexGrid.cc b/openvdb_3_0_0_library/unittest/TestPointIndexGrid.cc deleted file mode 100755 index 4c90734..0000000 --- a/openvdb_3_0_0_library/unittest/TestPointIndexGrid.cc +++ /dev/null @@ -1,338 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include // for math::Random01 -#include - -#include -#include -#include - - -class TestPointIndexGrid: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestPointIndexGrid); - CPPUNIT_TEST(testPointIndexGrid); - CPPUNIT_TEST(testPointIndexFilter); - CPPUNIT_TEST_SUITE_END(); - - void testPointIndexGrid(); - void testPointIndexFilter(); - -private: - // Generate random points by uniformly distributing points - // on a unit-sphere. - void genPoints(const int numPoints, std::vector& points) const - { - // init - openvdb::math::Random01 randNumber(0); - const int n = int(std::sqrt(double(numPoints))); - const double xScale = (2.0 * M_PI) / double(n); - const double yScale = M_PI / double(n); - - double x, y, theta, phi; - openvdb::Vec3R pos; - - points.reserve(n*n); - - // loop over a [0 to n) x [0 to n) grid. - for (int a = 0; a < n; ++a) { - for (int b = 0; b < n; ++b) { - - // jitter, move to random pos. inside the current cell - x = double(a) + randNumber(); - y = double(b) + randNumber(); - - // remap to a lat/long map - theta = y * yScale; // [0 to PI] - phi = x * xScale; // [0 to 2PI] - - // convert to cartesian coordinates on a unit sphere. - // spherical coordinate triplet (r=1, theta, phi) - pos[0] = std::sin(theta)*std::cos(phi); - pos[1] = std::sin(theta)*std::sin(phi); - pos[2] = std::cos(theta); - - points.push_back(pos); - } - } - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestPointIndexGrid); - -//////////////////////////////////////// - -namespace { - -class PointList -{ -public: - typedef openvdb::Vec3R value_type; - - PointList(const std::vector& points) - : mPoints(&points) - { - } - - size_t size() const { - return mPoints->size(); - } - - void getPos(size_t n, openvdb::Vec3R& xyz) const { - xyz = (*mPoints)[n]; - } - -protected: - std::vector const * const mPoints; -}; // PointList - - -template -bool hasDuplicates(const std::vector& items) -{ - std::vector vec(items); - std::sort(vec.begin(), vec.end()); - - size_t duplicates = 0; - for (size_t n = 1, N = vec.size(); n < N; ++n) { - if (vec[n] == vec[n-1]) ++duplicates; - } - return duplicates != 0; -} - - -template -struct WeightedAverageAccumulator { - typedef T ValueType; - WeightedAverageAccumulator(T const * const array, const T radius) - : mValues(array), mInvRadius(1.0/radius), mWeightSum(0.0), mValueSum(0.0) {} - - void reset() { mWeightSum = mValueSum = T(0.0); } - - void operator()(const T distSqr, const size_t pointIndex) { - const T weight = T(1.0) - openvdb::math::Sqrt(distSqr) * mInvRadius; - mWeightSum += weight; - mValueSum += weight * mValues[pointIndex]; - } - - T result() const { return mWeightSum > T(0.0) ? mValueSum / mWeightSum : T(0.0); } - -private: - T const * const mValues; - const T mInvRadius; - T mWeightSum, mValueSum; -}; // struct WeightedAverageAccumulator - -} // namespace - - - -//////////////////////////////////////// - - -void -TestPointIndexGrid::testPointIndexGrid() -{ - const float voxelSize = 0.01f; - const openvdb::math::Transform::Ptr transform = - openvdb::math::Transform::createLinearTransform(voxelSize); - - // generate points - - std::vector points; - genPoints(40000, points); - - PointList pointList(points); - - - // construct data structure - typedef openvdb::tools::PointIndexGrid PointIndexGrid; - - PointIndexGrid::Ptr pointGridPtr = - openvdb::tools::createPointIndexGrid(pointList, *transform); - - openvdb::CoordBBox bbox; - pointGridPtr->tree().evalActiveVoxelBoundingBox(bbox); - - // coord bbox search - - typedef PointIndexGrid::ConstAccessor ConstAccessor; - typedef openvdb::tools::PointIndexIterator<> PointIndexIterator; - - ConstAccessor acc = pointGridPtr->getConstAccessor(); - PointIndexIterator it(bbox, acc); - - CPPUNIT_ASSERT(it.test()); - CPPUNIT_ASSERT_EQUAL(points.size(), it.size()); - - // fractional bbox search - - openvdb::BBoxd region(bbox.min().asVec3d(), bbox.max().asVec3d()); - - // points are bucketed in a cell-centered fashion, we need to pad the - // coordinate range to get the same search region in the fractional bbox. - region.expand(voxelSize * 0.5); - - it.searchAndUpdate(region, acc, pointList, *transform); - - CPPUNIT_ASSERT(it.test()); - CPPUNIT_ASSERT_EQUAL(points.size(), it.size()); - - { - std::vector vec; - vec.reserve(it.size()); - for (; it; ++it) { - vec.push_back(*it); - } - - CPPUNIT_ASSERT_EQUAL(vec.size(), it.size()); - CPPUNIT_ASSERT(!hasDuplicates(vec)); - } - - // radial search - openvdb::Vec3d center = region.getCenter(); - double radius = region.extents().x() * 0.5; - it.searchAndUpdate(center, radius, acc, pointList, *transform); - - CPPUNIT_ASSERT(it.test()); - CPPUNIT_ASSERT_EQUAL(points.size(), it.size()); - - { - std::vector vec; - vec.reserve(it.size()); - for (; it; ++it) { - vec.push_back(*it); - } - - CPPUNIT_ASSERT_EQUAL(vec.size(), it.size()); - CPPUNIT_ASSERT(!hasDuplicates(vec)); - } - - - center = region.min(); - it.searchAndUpdate(center, radius, acc, pointList, *transform); - - CPPUNIT_ASSERT(it.test()); - - { - std::vector vec; - vec.reserve(it.size()); - for (; it; ++it) { - vec.push_back(*it); - } - - CPPUNIT_ASSERT_EQUAL(vec.size(), it.size()); - CPPUNIT_ASSERT(!hasDuplicates(vec)); - - // check that no points where missed. - - std::vector indexMask(points.size(), 0); - for (size_t n = 0, N = vec.size(); n < N; ++n) { - indexMask[vec[n]] = 1; - } - - const double r2 = radius * radius; - openvdb::Vec3R v; - for (size_t n = 0, N = indexMask.size(); n < N; ++n) { - v = center - transform->worldToIndex(points[n]); - if (indexMask[n] == 0) { - CPPUNIT_ASSERT(!(v.lengthSqr() < r2)); - } else { - CPPUNIT_ASSERT(v.lengthSqr() < r2); - } - } - } - - - // Check partitioning - - CPPUNIT_ASSERT(openvdb::tools::isValidPartition(pointList, *pointGridPtr)); - - points[10000].x() += 1.5; // manually modify a few points. - points[20000].x() += 1.5; - points[30000].x() += 1.5; - - CPPUNIT_ASSERT(!openvdb::tools::isValidPartition(pointList, *pointGridPtr)); - - PointIndexGrid::Ptr pointGrid2Ptr = - openvdb::tools::getValidPointIndexGrid(pointList, pointGridPtr); - - CPPUNIT_ASSERT(openvdb::tools::isValidPartition(pointList, *pointGrid2Ptr)); -} - - -void -TestPointIndexGrid::testPointIndexFilter() -{ - // generate points - const float voxelSize = 0.01f; - const size_t pointCount = 10000; - const openvdb::math::Transform::Ptr transform = - openvdb::math::Transform::createLinearTransform(voxelSize); - - std::vector points; - genPoints(pointCount, points); - - PointList pointList(points); - - // construct data structure - typedef openvdb::tools::PointIndexGrid PointIndexGrid; - - PointIndexGrid::Ptr pointGridPtr = - openvdb::tools::createPointIndexGrid(pointList, *transform); - - - std::vector pointDensity(pointCount, 1.0); - - openvdb::tools::PointIndexFilter - filter(pointList, pointGridPtr->tree(), pointGridPtr->transform()); - - const double radius = 3.0 * voxelSize; - - WeightedAverageAccumulator - accumulator(&pointDensity.front(), radius); - - double sum = 0.0; - for (size_t n = 0, N = points.size(); n < N; ++n) { - accumulator.reset(); - filter.searchAndApply(points[n], radius, accumulator); - sum += accumulator.result(); - } - - CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, double(points.size()), 1e-6); -} - - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestPointPartitioner.cc b/openvdb_3_0_0_library/unittest/TestPointPartitioner.cc deleted file mode 100755 index c6e5702..0000000 --- a/openvdb_3_0_0_library/unittest/TestPointPartitioner.cc +++ /dev/null @@ -1,126 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include - - -class TestPointPartitioner: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestPointPartitioner); - CPPUNIT_TEST(testPartitioner); - CPPUNIT_TEST_SUITE_END(); - - void testPartitioner(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestPointPartitioner); - -//////////////////////////////////////// - -namespace { - -struct PointList { - typedef openvdb::Vec3s value_type; - - PointList(const std::vector& points) : mPoints(&points) {} - - size_t size() const { return mPoints->size(); } - - void getPos(size_t n, value_type& xyz) const { xyz = (*mPoints)[n]; } - -protected: - std::vector const * const mPoints; -}; // PointList - -} // namespace - -//////////////////////////////////////// - - -void -TestPointPartitioner::testPartitioner() -{ - const size_t pointCount = 10000; - const float voxelSize = 0.1f; - - std::vector points(pointCount, openvdb::Vec3s(0.f)); - for (size_t n = 1; n < pointCount; ++n) { - points[n].x() = points[n-1].x() + voxelSize; - } - - PointList pointList(points); - - const openvdb::math::Transform::Ptr transform = - openvdb::math::Transform::createLinearTransform(voxelSize); - - typedef openvdb::tools::UInt32PointPartitioner PointPartitioner; - - PointPartitioner::Ptr partitioner = - PointPartitioner::create(pointList, *transform); - - CPPUNIT_ASSERT(!partitioner->empty()); - - const size_t expectedPageCount = pointCount / (1u << PointPartitioner::LOG2DIM); - - CPPUNIT_ASSERT_EQUAL(expectedPageCount, partitioner->size()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(0), partitioner->origin(0)); - - PointPartitioner::IndexIterator it = partitioner->indices(0); - - CPPUNIT_ASSERT(it.test()); - CPPUNIT_ASSERT_EQUAL(it.size(), size_t(1 << PointPartitioner::LOG2DIM)); - - PointPartitioner::IndexIterator itB = partitioner->indices(0); - - CPPUNIT_ASSERT_EQUAL(++it, ++itB); - CPPUNIT_ASSERT(it != ++itB); - - std::vector indices; - - for (it.reset(); it; ++it) { - indices.push_back(*it); - } - - CPPUNIT_ASSERT_EQUAL(it.size(), indices.size()); - - size_t idx = 0; - for (itB.reset(); itB; ++itB) { - CPPUNIT_ASSERT_EQUAL(indices[idx++], *itB); - } -} - - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestPrePostAPI.cc b/openvdb_3_0_0_library/unittest/TestPrePostAPI.cc deleted file mode 100755 index 445f8ba..0000000 --- a/openvdb_3_0_0_library/unittest/TestPrePostAPI.cc +++ /dev/null @@ -1,711 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - - -class TestPrePostAPI: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestPrePostAPI); - - CPPUNIT_TEST(testMat4); - CPPUNIT_TEST(testMat4Rotate); - CPPUNIT_TEST(testMat4Scale); - CPPUNIT_TEST(testMat4Shear); - CPPUNIT_TEST(testMaps); - CPPUNIT_TEST(testLinearTransform); - CPPUNIT_TEST(testFrustumTransform); - - CPPUNIT_TEST_SUITE_END(); - - void testMat4(); - void testMat4Rotate(); - void testMat4Scale(); - void testMat4Shear(); - void testMaps(); - void testLinearTransform(); - void testFrustumTransform(); - //void testIsType(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestPrePostAPI); - - -void -TestPrePostAPI::testMat4() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - - Mat4d m = Mat4d::identity(); - Mat4d minv = Mat4d::identity(); - - // create matrix with pre-API - // Translate Shear Rotate Translate Scale matrix - m.preScale(Vec3d(1, 2, 3)); - m.preTranslate(Vec3d(2, 3, 4)); - m.preRotate(X_AXIS, 20); - m.preShear(X_AXIS, Y_AXIS, 2); - m.preTranslate(Vec3d(2, 2, 2)); - - // create inverse using the post-API - minv.postScale(Vec3d(1.f, 1.f/2.f, 1.f/3.f)); - minv.postTranslate(-Vec3d(2, 3, 4)); - minv.postRotate(X_AXIS,-20); - minv.postShear(X_AXIS, Y_AXIS, -2); - minv.postTranslate(-Vec3d(2, 2, 2)); - - Mat4d mtest = minv * m; - - // verify that the results is an identity - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][0], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][1], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][2], 1, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][3], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][2], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][3], 1, TOL); -} - - -void -TestPrePostAPI::testMat4Rotate() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - Mat4d rx, ry, rz; - const double angle1 = 20. * M_PI / 180.; - const double angle2 = 64. * M_PI / 180.; - const double angle3 = 125. *M_PI / 180.; - rx.setToRotation(Vec3d(1,0,0), angle1); - ry.setToRotation(Vec3d(0,1,0), angle2); - rz.setToRotation(Vec3d(0,0,1), angle3); - - Mat4d shear = Mat4d::identity(); - shear.setToShear(X_AXIS, Z_AXIS, 2.0); - shear.preShear(Y_AXIS, X_AXIS, 3.0); - shear.preTranslate(Vec3d(2,4,1)); - - const Mat4d preResult = rz*ry*rx*shear; - Mat4d mpre = shear; - mpre.preRotate(X_AXIS, angle1); - mpre.preRotate(Y_AXIS, angle2); - mpre.preRotate(Z_AXIS, angle3); - - CPPUNIT_ASSERT( mpre.eq(preResult, TOL) ); - - const Mat4d postResult = shear*rx*ry*rz; - Mat4d mpost = shear; - mpost.postRotate(X_AXIS, angle1); - mpost.postRotate(Y_AXIS, angle2); - mpost.postRotate(Z_AXIS, angle3); - - CPPUNIT_ASSERT( mpost.eq(postResult, TOL) ); - - CPPUNIT_ASSERT( !mpost.eq(mpre, TOL)); - -} - - -void -TestPrePostAPI::testMat4Scale() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - Mat4d mpre, mpost; - double* pre = mpre.asPointer(); - double* post = mpost.asPointer(); - for (int i = 0; i < 16; ++i) { - pre[i] = double(i); - post[i] = double(i); - } - - Mat4d scale = Mat4d::identity(); - scale.setToScale(Vec3d(2, 3, 5.5)); - Mat4d preResult = scale * mpre; - Mat4d postResult = mpost * scale; - - mpre.preScale(Vec3d(2, 3, 5.5)); - mpost.postScale(Vec3d(2, 3, 5.5)); - - CPPUNIT_ASSERT( mpre.eq(preResult, TOL) ); - CPPUNIT_ASSERT( mpost.eq(postResult, TOL) ); -} - - -void -TestPrePostAPI::testMat4Shear() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - Mat4d mpre, mpost; - double* pre = mpre.asPointer(); - double* post = mpost.asPointer(); - for (int i = 0; i < 16; ++i) { - pre[i] = double(i); - post[i] = double(i); - } - - Mat4d shear = Mat4d::identity(); - shear.setToShear(X_AXIS, Z_AXIS, 13.); - Mat4d preResult = shear * mpre; - Mat4d postResult = mpost * shear; - - mpre.preShear(X_AXIS, Z_AXIS, 13.); - mpost.postShear(X_AXIS, Z_AXIS, 13.); - - CPPUNIT_ASSERT( mpre.eq(preResult, TOL) ); - CPPUNIT_ASSERT( mpost.eq(postResult, TOL) ); -} - - -void -TestPrePostAPI::testMaps() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - - { // pre translate - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - const Vec3d trans(1,2,3); - Mat4d correct = Mat4d::identity(); - correct.preTranslate(trans); - { - MapBase::Ptr base = usm.preTranslate(trans); - Mat4d result = (base->getAffineMap())->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.preTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.preTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.preTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.preTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // post translate - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - const Vec3d trans(1,2,3); - Mat4d correct = Mat4d::identity(); - correct.postTranslate(trans); - { - const Mat4d result = usm.postTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.postTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.postTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.postTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.postTranslate(trans)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // pre scale - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - const Vec3d scale(1,2,3); - Mat4d correct = Mat4d::identity(); - correct.preScale(scale); - { - const Mat4d result = usm.preScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.preScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.preScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.preScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.preScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // post scale - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - const Vec3d scale(1,2,3); - Mat4d correct = Mat4d::identity(); - correct.postScale(scale); - { - const Mat4d result = usm.postScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.postScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.postScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.postScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.postScale(scale)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // pre shear - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - Mat4d correct = Mat4d::identity(); - correct.preShear(X_AXIS, Z_AXIS, 13.); - { - const Mat4d result = usm.preShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.preShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.preShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.preShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.preShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // post shear - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - Mat4d correct = Mat4d::identity(); - correct.postShear(X_AXIS, Z_AXIS, 13.); - { - const Mat4d result = usm.postShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.postShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.postShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.postShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.postShear(13., X_AXIS, Z_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // pre rotate - const double angle1 = 20. * M_PI / 180.; - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - Mat4d correct = Mat4d::identity(); - correct.preRotate(X_AXIS, angle1); - { - const Mat4d result = usm.preRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.preRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.preRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.preRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.preRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } - { // post rotate - const double angle1 = 20. * M_PI / 180.; - UniformScaleMap usm; - UniformScaleTranslateMap ustm; - ScaleMap sm; - ScaleTranslateMap stm; - AffineMap am; - - Mat4d correct = Mat4d::identity(); - correct.postRotate(X_AXIS, angle1); - { - const Mat4d result = usm.postRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = ustm.postRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = sm.postRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = stm.postRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - { - const Mat4d result = am.postRotate(angle1, X_AXIS)->getAffineMap()->getConstMat4(); - CPPUNIT_ASSERT( correct.eq(result, TOL)); - } - } -} - - -void -TestPrePostAPI::testLinearTransform() -{ - using namespace openvdb::math; - - double TOL = 1e-7; - { - Transform::Ptr t = Transform::createLinearTransform(1.f); - Transform::Ptr tinv = Transform::createLinearTransform(1.f); - - // create matrix with pre-API - // Translate Shear Rotate Translate Scale matrix - t->preScale(Vec3d(1, 2, 3)); - t->preTranslate(Vec3d(2, 3, 4)); - t->preRotate(20); - t->preShear(2, X_AXIS, Y_AXIS); - t->preTranslate(Vec3d(2, 2, 2)); - - // create inverse using the post-API - tinv->postScale(Vec3d(1.f, 1.f/2.f, 1.f/3.f)); - tinv->postTranslate(-Vec3d(2, 3, 4)); - tinv->postRotate(-20); - tinv->postShear(-2, X_AXIS, Y_AXIS); - tinv->postTranslate(-Vec3d(2, 2, 2)); - - - // test this by verifying that equvilent interal matrix - // represenations are inverses - Mat4d m = t->baseMap()->getAffineMap()->getMat4(); - Mat4d minv = tinv->baseMap()->getAffineMap()->getMat4(); - - Mat4d mtest = minv * m; - - // verify that the results is an identity - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][0], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][1], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][2], 1, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][3], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][2], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][3], 1, TOL); - } - - { - Transform::Ptr t = Transform::createLinearTransform(1.f); - - Mat4d m = Mat4d::identity(); - - // create matrix with pre-API - // Translate Shear Rotate Translate Scale matrix - m.preScale(Vec3d(1, 2, 3)); - m.preTranslate(Vec3d(2, 3, 4)); - m.preRotate(X_AXIS, 20); - m.preShear(X_AXIS, Y_AXIS, 2); - m.preTranslate(Vec3d(2, 2, 2)); - - t->preScale(Vec3d(1,2,3)); - t->preMult(m); - t->postMult(m); - - Mat4d minv = Mat4d::identity(); - - // create inverse using the post-API - minv.postScale(Vec3d(1.f, 1.f/2.f, 1.f/3.f)); - minv.postTranslate(-Vec3d(2, 3, 4)); - minv.postRotate(X_AXIS,-20); - minv.postShear(X_AXIS, Y_AXIS, -2); - minv.postTranslate(-Vec3d(2, 2, 2)); - - t->preMult(minv); - t->postMult(minv); - - Mat4d mtest = t->baseMap()->getAffineMap()->getMat4(); - - - // verify that the results is the scale - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][0], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][1], 2, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][2], 3, 1e-6); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][3], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][0], 0, 1e-6); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][1], 0, 1e-6); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][2], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][3], 1, TOL); - } - - -} - - -void -TestPrePostAPI::testFrustumTransform() -{ - using namespace openvdb::math; - - typedef BBox BBoxd; - - double TOL = 1e-7; - { - - BBoxd bbox(Vec3d(-5,-5,0), Vec3d(5,5,10)); - Transform::Ptr t = Transform::createFrustumTransform(bbox, /* taper*/ 1, /*depth*/10, /* voxel size */1.f); - Transform::Ptr tinv = Transform::createFrustumTransform(bbox, /* taper*/ 1, /*depth*/10, /* voxel size */1.f); - - - // create matrix with pre-API - // Translate Shear Rotate Translate Scale matrix - t->preScale(Vec3d(1, 2, 3)); - t->preTranslate(Vec3d(2, 3, 4)); - t->preRotate(20); - t->preShear(2, X_AXIS, Y_AXIS); - t->preTranslate(Vec3d(2, 2, 2)); - - // create inverse using the post-API - tinv->postScale(Vec3d(1.f, 1.f/2.f, 1.f/3.f)); - tinv->postTranslate(-Vec3d(2, 3, 4)); - tinv->postRotate(-20); - tinv->postShear(-2, X_AXIS, Y_AXIS); - tinv->postTranslate(-Vec3d(2, 2, 2)); - - - // test this by verifying that equvilent interal matrix - // represenations are inverses - NonlinearFrustumMap::Ptr frustum = boost::static_pointer_cast( t->baseMap() ); - NonlinearFrustumMap::Ptr frustuminv = boost::static_pointer_cast( tinv->baseMap() ); - - Mat4d m = frustum->secondMap().getMat4(); - Mat4d minv = frustuminv->secondMap().getMat4(); - - Mat4d mtest = minv * m; - - // verify that the results is an identity - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][0], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][1], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][2], 1, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][3], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][2], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][3], 1, TOL); - } - - { - - BBoxd bbox(Vec3d(-5,-5,0), Vec3d(5,5,10)); - Transform::Ptr t = Transform::createFrustumTransform(bbox, /* taper*/ 1, /*depth*/10, /* voxel size */1.f); - - - Mat4d m = Mat4d::identity(); - - // create matrix with pre-API - // Translate Shear Rotate Translate Scale matrix - m.preScale(Vec3d(1, 2, 3)); - m.preTranslate(Vec3d(2, 3, 4)); - m.preRotate(X_AXIS, 20); - m.preShear(X_AXIS, Y_AXIS, 2); - m.preTranslate(Vec3d(2, 2, 2)); - - t->preScale(Vec3d(1,2,3)); - t->preMult(m); - t->postMult(m); - - Mat4d minv = Mat4d::identity(); - - // create inverse using the post-API - minv.postScale(Vec3d(1.f, 1.f/2.f, 1.f/3.f)); - minv.postTranslate(-Vec3d(2, 3, 4)); - minv.postRotate(X_AXIS,-20); - minv.postShear(X_AXIS, Y_AXIS, -2); - minv.postTranslate(-Vec3d(2, 2, 2)); - - t->preMult(minv); - t->postMult(minv); - - NonlinearFrustumMap::Ptr frustum = boost::static_pointer_cast( t->baseMap() ); - Mat4d mtest = frustum->secondMap().getMat4(); - - // verify that the results is the scale - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][0], 1, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][1], 2, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][2], 3, 1e-6); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[0][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][2], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[1][3], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][0], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][1], 0, TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[2][3], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][0], 0, 1e-6); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][1], 0, 1e-6); - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][2], 0, TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(mtest[3][3], 1, TOL); - } - - -} - - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestQuadraticInterp.cc b/openvdb_3_0_0_library/unittest/TestQuadraticInterp.cc deleted file mode 100755 index 9a828ba..0000000 --- a/openvdb_3_0_0_library/unittest/TestQuadraticInterp.cc +++ /dev/null @@ -1,361 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file TestQuadraticInterp.cc - -#include -#include -#include -#include - -// CPPUNIT_TEST_SUITE() invokes CPPUNIT_TESTNAMER_DECL() to generate a suite name -// from the FixtureType. But if FixtureType is a templated type, the generated name -// can become long and messy. This macro overrides the normal naming logic, -// instead invoking FixtureType::testSuiteName(), which should be a static member -// function that returns a std::string containing the suite name for the specific -// template instantiation. -#undef CPPUNIT_TESTNAMER_DECL -#define CPPUNIT_TESTNAMER_DECL( variableName, FixtureType ) \ - CPPUNIT_NS::TestNamer variableName( FixtureType::testSuiteName() ) - - -namespace { -// Absolute tolerance for floating-point equality comparisons -const double TOLERANCE = 1.0e-5; -} - - -//////////////////////////////////////// - - -template -class TestQuadraticInterp: public CppUnit::TestCase -{ -public: - typedef typename GridType::ValueType ValueT; - typedef typename GridType::Ptr GridPtr; - struct TestVal { float x, y, z; ValueT expected; }; - - static std::string testSuiteName() - { - std::string name = openvdb::typeNameAsString(); - if (!name.empty()) name[0] = static_cast(::toupper(name[0])); - return "TestQuadraticInterp" + name; - } - - CPPUNIT_TEST_SUITE(TestQuadraticInterp); - CPPUNIT_TEST(test); - CPPUNIT_TEST(testConstantValues); - CPPUNIT_TEST(testFillValues); - CPPUNIT_TEST(testNegativeIndices); - CPPUNIT_TEST_SUITE_END(); - - void test(); - void testConstantValues(); - void testFillValues(); - void testNegativeIndices(); - -private: - void executeTest(const GridPtr&, const TestVal*, size_t numVals) const; - - /// Initialize an arbitrary ValueType from a scalar. - static inline ValueT constValue(double d) { return ValueT(d); } - - /// Compare two numeric values for equality within an absolute tolerance. - static inline bool relEq(const ValueT& v1, const ValueT& v2) - { return fabs(v1 - v2) <= TOLERANCE; } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestQuadraticInterp); -CPPUNIT_TEST_SUITE_REGISTRATION(TestQuadraticInterp); -CPPUNIT_TEST_SUITE_REGISTRATION(TestQuadraticInterp); - - -//////////////////////////////////////// - - -/// Specialization for Vec3s grids -template<> -inline openvdb::Vec3s -TestQuadraticInterp::constValue(double d) -{ - return openvdb::Vec3s(float(d), float(d), float(d)); -} - -/// Specialization for Vec3s grids -template<> -inline bool -TestQuadraticInterp::relEq( - const openvdb::Vec3s& v1, const openvdb::Vec3s& v2) -{ - return v1.eq(v2, float(TOLERANCE)); -} - - -/// Sample the given tree at various locations and assert if -/// any of the sampled values don't match the expected values. -template -void -TestQuadraticInterp::executeTest(const GridPtr& grid, - const TestVal* testVals, size_t numVals) const -{ - openvdb::tools::GridSampler interpolator(*grid); - //openvdb::tools::QuadraticInterp interpolator(*tree); - - for (size_t i = 0; i < numVals; ++i) { - const TestVal& val = testVals[i]; - const ValueT actual = interpolator.sampleVoxel(val.x, val.y, val.z); - if (!relEq(val.expected, actual)) { - std::ostringstream ostr; - ostr << std::setprecision(10) - << "sampleVoxel(" << val.x << ", " << val.y << ", " << val.z - << "): expected " << val.expected << ", got " << actual; - CPPUNIT_FAIL(ostr.str()); - } - } -} - - -template -void -TestQuadraticInterp::test() -{ - const ValueT - one = constValue(1), - two = constValue(2), - three = constValue(3), - four = constValue(4), - fillValue = constValue(256); - - GridPtr grid(new GridType(fillValue)); - typename GridType::TreeType& tree = grid->tree(); - - tree.setValue(openvdb::Coord(10, 10, 10), one); - - tree.setValue(openvdb::Coord(11, 10, 10), two); - tree.setValue(openvdb::Coord(11, 11, 10), two); - tree.setValue(openvdb::Coord(10, 11, 10), two); - tree.setValue(openvdb::Coord( 9, 11, 10), two); - tree.setValue(openvdb::Coord( 9, 10, 10), two); - tree.setValue(openvdb::Coord( 9, 9, 10), two); - tree.setValue(openvdb::Coord(10, 9, 10), two); - tree.setValue(openvdb::Coord(11, 9, 10), two); - - tree.setValue(openvdb::Coord(10, 10, 11), three); - tree.setValue(openvdb::Coord(11, 10, 11), three); - tree.setValue(openvdb::Coord(11, 11, 11), three); - tree.setValue(openvdb::Coord(10, 11, 11), three); - tree.setValue(openvdb::Coord( 9, 11, 11), three); - tree.setValue(openvdb::Coord( 9, 10, 11), three); - tree.setValue(openvdb::Coord( 9, 9, 11), three); - tree.setValue(openvdb::Coord(10, 9, 11), three); - tree.setValue(openvdb::Coord(11, 9, 11), three); - - tree.setValue(openvdb::Coord(10, 10, 9), four); - tree.setValue(openvdb::Coord(11, 10, 9), four); - tree.setValue(openvdb::Coord(11, 11, 9), four); - tree.setValue(openvdb::Coord(10, 11, 9), four); - tree.setValue(openvdb::Coord( 9, 11, 9), four); - tree.setValue(openvdb::Coord( 9, 10, 9), four); - tree.setValue(openvdb::Coord( 9, 9, 9), four); - tree.setValue(openvdb::Coord(10, 9, 9), four); - tree.setValue(openvdb::Coord(11, 9, 9), four); - - const TestVal testVals[] = { - { 10.5f, 10.5f, 10.5f, constValue(1.703125) }, - { 10.0f, 10.0f, 10.0f, one }, - { 11.0f, 10.0f, 10.0f, two }, - { 11.0f, 11.0f, 10.0f, two }, - { 11.0f, 11.0f, 11.0f, three }, - { 9.0f, 11.0f, 9.0f, four }, - { 9.0f, 10.0f, 9.0f, four }, - { 10.1f, 10.0f, 10.0f, constValue(1.01) }, - { 10.8f, 10.8f, 10.8f, constValue(2.513344) }, - { 10.1f, 10.8f, 10.5f, constValue(1.8577) }, - { 10.8f, 10.1f, 10.5f, constValue(1.8577) }, - { 10.5f, 10.1f, 10.8f, constValue(2.2927) }, - { 10.5f, 10.8f, 10.1f, constValue(1.6977) }, - }; - const size_t numVals = sizeof(testVals) / sizeof(TestVal); - - executeTest(grid, testVals, numVals); -} - - -template -void -TestQuadraticInterp::testConstantValues() -{ - const ValueT - two = constValue(2), - fillValue = constValue(256); - - GridPtr grid(new GridType(fillValue)); - typename GridType::TreeType& tree = grid->tree(); - - tree.setValue(openvdb::Coord(10, 10, 10), two); - - tree.setValue(openvdb::Coord(11, 10, 10), two); - tree.setValue(openvdb::Coord(11, 11, 10), two); - tree.setValue(openvdb::Coord(10, 11, 10), two); - tree.setValue(openvdb::Coord( 9, 11, 10), two); - tree.setValue(openvdb::Coord( 9, 10, 10), two); - tree.setValue(openvdb::Coord( 9, 9, 10), two); - tree.setValue(openvdb::Coord(10, 9, 10), two); - tree.setValue(openvdb::Coord(11, 9, 10), two); - - tree.setValue(openvdb::Coord(10, 10, 11), two); - tree.setValue(openvdb::Coord(11, 10, 11), two); - tree.setValue(openvdb::Coord(11, 11, 11), two); - tree.setValue(openvdb::Coord(10, 11, 11), two); - tree.setValue(openvdb::Coord( 9, 11, 11), two); - tree.setValue(openvdb::Coord( 9, 10, 11), two); - tree.setValue(openvdb::Coord( 9, 9, 11), two); - tree.setValue(openvdb::Coord(10, 9, 11), two); - tree.setValue(openvdb::Coord(11, 9, 11), two); - - tree.setValue(openvdb::Coord(10, 10, 9), two); - tree.setValue(openvdb::Coord(11, 10, 9), two); - tree.setValue(openvdb::Coord(11, 11, 9), two); - tree.setValue(openvdb::Coord(10, 11, 9), two); - tree.setValue(openvdb::Coord( 9, 11, 9), two); - tree.setValue(openvdb::Coord( 9, 10, 9), two); - tree.setValue(openvdb::Coord( 9, 9, 9), two); - tree.setValue(openvdb::Coord(10, 9, 9), two); - tree.setValue(openvdb::Coord(11, 9, 9), two); - - const TestVal testVals[] = { - { 10.5f, 10.5f, 10.5f, two }, - { 10.0f, 10.0f, 10.0f, two }, - { 10.1f, 10.0f, 10.0f, two }, - { 10.8f, 10.8f, 10.8f, two }, - { 10.1f, 10.8f, 10.5f, two }, - { 10.8f, 10.1f, 10.5f, two }, - { 10.5f, 10.1f, 10.8f, two }, - { 10.5f, 10.8f, 10.1f, two } - }; - const size_t numVals = sizeof(testVals) / sizeof(TestVal); - - executeTest(grid, testVals, numVals); -} - - -template -void -TestQuadraticInterp::testFillValues() -{ - const ValueT fillValue = constValue(256); - - GridPtr grid(new GridType(fillValue)); - - const TestVal testVals[] = { - { 10.5f, 10.5f, 10.5f, fillValue }, - { 10.0f, 10.0f, 10.0f, fillValue }, - { 10.1f, 10.0f, 10.0f, fillValue }, - { 10.8f, 10.8f, 10.8f, fillValue }, - { 10.1f, 10.8f, 10.5f, fillValue }, - { 10.8f, 10.1f, 10.5f, fillValue }, - { 10.5f, 10.1f, 10.8f, fillValue }, - { 10.5f, 10.8f, 10.1f, fillValue } - }; - const size_t numVals = sizeof(testVals) / sizeof(TestVal); - - executeTest(grid, testVals, numVals); -} - - -template -void -TestQuadraticInterp::testNegativeIndices() -{ - const ValueT - one = constValue(1), - two = constValue(2), - three = constValue(3), - four = constValue(4), - fillValue = constValue(256); - - GridPtr grid(new GridType(fillValue)); - typename GridType::TreeType& tree = grid->tree(); - - tree.setValue(openvdb::Coord(-10, -10, -10), one); - - tree.setValue(openvdb::Coord(-11, -10, -10), two); - tree.setValue(openvdb::Coord(-11, -11, -10), two); - tree.setValue(openvdb::Coord(-10, -11, -10), two); - tree.setValue(openvdb::Coord( -9, -11, -10), two); - tree.setValue(openvdb::Coord( -9, -10, -10), two); - tree.setValue(openvdb::Coord( -9, -9, -10), two); - tree.setValue(openvdb::Coord(-10, -9, -10), two); - tree.setValue(openvdb::Coord(-11, -9, -10), two); - - tree.setValue(openvdb::Coord(-10, -10, -11), three); - tree.setValue(openvdb::Coord(-11, -10, -11), three); - tree.setValue(openvdb::Coord(-11, -11, -11), three); - tree.setValue(openvdb::Coord(-10, -11, -11), three); - tree.setValue(openvdb::Coord( -9, -11, -11), three); - tree.setValue(openvdb::Coord( -9, -10, -11), three); - tree.setValue(openvdb::Coord( -9, -9, -11), three); - tree.setValue(openvdb::Coord(-10, -9, -11), three); - tree.setValue(openvdb::Coord(-11, -9, -11), three); - - tree.setValue(openvdb::Coord(-10, -10, -9), four); - tree.setValue(openvdb::Coord(-11, -10, -9), four); - tree.setValue(openvdb::Coord(-11, -11, -9), four); - tree.setValue(openvdb::Coord(-10, -11, -9), four); - tree.setValue(openvdb::Coord( -9, -11, -9), four); - tree.setValue(openvdb::Coord( -9, -10, -9), four); - tree.setValue(openvdb::Coord( -9, -9, -9), four); - tree.setValue(openvdb::Coord(-10, -9, -9), four); - tree.setValue(openvdb::Coord(-11, -9, -9), four); - - const TestVal testVals[] = { - { -10.5f, -10.5f, -10.5f, constValue(-104.75586) }, - { -10.0f, -10.0f, -10.0f, one }, - { -11.0f, -10.0f, -10.0f, two }, - { -11.0f, -11.0f, -10.0f, two }, - { -11.0f, -11.0f, -11.0f, three }, - { -9.0f, -11.0f, -9.0f, four }, - { -9.0f, -10.0f, -9.0f, four }, - { -10.1f, -10.0f, -10.0f, constValue(-10.28504) }, - { -10.8f, -10.8f, -10.8f, constValue(-62.84878) }, - { -10.1f, -10.8f, -10.5f, constValue(-65.68951) }, - { -10.8f, -10.1f, -10.5f, constValue(-65.68951) }, - { -10.5f, -10.1f, -10.8f, constValue(-65.40736) }, - { -10.5f, -10.8f, -10.1f, constValue(-66.30510) }, - }; - const size_t numVals = sizeof(testVals) / sizeof(TestVal); - - executeTest(grid, testVals, numVals); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestQuantizedUnitVec.cc b/openvdb_3_0_0_library/unittest/TestQuantizedUnitVec.cc deleted file mode 100755 index 65be37f..0000000 --- a/openvdb_3_0_0_library/unittest/TestQuantizedUnitVec.cc +++ /dev/null @@ -1,177 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class TestQuantizedUnitVec: public CppUnit::TestFixture -{ -public: - CPPUNIT_TEST_SUITE(TestQuantizedUnitVec); - CPPUNIT_TEST(testQuantization); - CPPUNIT_TEST_SUITE_END(); - - void testQuantization(); - -private: - // Generate a random number in the range [0, 1]. - double randNumber() { return double(rand()) / (double(RAND_MAX) + 1.0); } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestQuantizedUnitVec); - - -//////////////////////////////////////// - - -namespace { -const uint16_t - MASK_XSIGN = 0x8000, // 1000000000000000 - MASK_YSIGN = 0x4000, // 0100000000000000 - MASK_ZSIGN = 0x2000; // 0010000000000000 -} - - -//////////////////////////////////////// - - -void -TestQuantizedUnitVec::testQuantization() -{ - using namespace openvdb; - using namespace openvdb::math; - - // - // Check sign bits - // - Vec3s unitVec = Vec3s(-1.0, -1.0, -1.0); - unitVec.normalize(); - - uint16_t quantizedVec = QuantizedUnitVec::pack(unitVec); - - CPPUNIT_ASSERT((quantizedVec & MASK_XSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_YSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_ZSIGN)); - - unitVec[0] = -unitVec[0]; - unitVec[2] = -unitVec[2]; - quantizedVec = QuantizedUnitVec::pack(unitVec); - - CPPUNIT_ASSERT(!(quantizedVec & MASK_XSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_YSIGN)); - CPPUNIT_ASSERT(!(quantizedVec & MASK_ZSIGN)); - - unitVec[1] = -unitVec[1]; - quantizedVec = QuantizedUnitVec::pack(unitVec); - - CPPUNIT_ASSERT(!(quantizedVec & MASK_XSIGN)); - CPPUNIT_ASSERT(!(quantizedVec & MASK_YSIGN)); - CPPUNIT_ASSERT(!(quantizedVec & MASK_ZSIGN)); - - QuantizedUnitVec::flipSignBits(quantizedVec); - - CPPUNIT_ASSERT((quantizedVec & MASK_XSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_YSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_ZSIGN)); - - unitVec[2] = -unitVec[2]; - quantizedVec = QuantizedUnitVec::pack(unitVec); - QuantizedUnitVec::flipSignBits(quantizedVec); - - CPPUNIT_ASSERT((quantizedVec & MASK_XSIGN)); - CPPUNIT_ASSERT((quantizedVec & MASK_YSIGN)); - CPPUNIT_ASSERT(!(quantizedVec & MASK_ZSIGN)); - - // - // Check conversion error - // - const double tol = 0.05; // component error tolerance - - const int numNormals = 40000; - - - // init - srand(0); - const int n = int(std::sqrt(double(numNormals))); - const double xScale = (2.0 * M_PI) / double(n); - const double yScale = M_PI / double(n); - - double x, y, theta, phi; - Vec3s n0, n1; - - // generate random normals, by uniformly distributing points on a unit-sphere. - - // loop over a [0 to n) x [0 to n) grid. - for (int a = 0; a < n; ++a) { - for (int b = 0; b < n; ++b) { - - // jitter, move to random pos. inside the current cell - x = double(a) + randNumber(); - y = double(b) + randNumber(); - - // remap to a lat/long map - theta = y * yScale; // [0 to PI] - phi = x * xScale; // [0 to 2PI] - - // convert to cartesian coordinates on a unit sphere. - // spherical coordinate triplet (r=1, theta, phi) - n0[0] = float(std::sin(theta)*std::cos(phi)); - n0[1] = float(std::sin(theta)*std::sin(phi)); - n0[2] = float(std::cos(theta)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(n0.length(), 1.0, 1e-6); - - n1 = QuantizedUnitVec::unpack(QuantizedUnitVec::pack(n0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(n1.length(), 1.0, 1e-6); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(n0[0], n1[0], tol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(n0[1], n1[1], tol); - CPPUNIT_ASSERT_DOUBLES_EQUAL(n0[2], n1[2], tol); - - float sumDiff = std::abs(n0[0] - n1[0]) + std::abs(n0[1] - n1[1]) - + std::abs(n0[2] - n1[2]); - - CPPUNIT_ASSERT(sumDiff < (2.0 * tol)); - } - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestQuat.cc b/openvdb_3_0_0_library/unittest/TestQuat.cc deleted file mode 100755 index d532ee7..0000000 --- a/openvdb_3_0_0_library/unittest/TestQuat.cc +++ /dev/null @@ -1,313 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -using namespace openvdb::math; - -class TestQuat: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE( TestQuat ); - CPPUNIT_TEST( testConstructor ); - CPPUNIT_TEST( testAxisAngle ); - CPPUNIT_TEST( testOpPlus ); - CPPUNIT_TEST( testOpMinus ); - CPPUNIT_TEST( testOpMultiply ); - CPPUNIT_TEST( testInvert ); - CPPUNIT_TEST( testEulerAngles ); - CPPUNIT_TEST_SUITE_END(); - - void testConstructor(); - void testAxisAngle(); - void testOpPlus(); - void testOpMinus(); - void testOpMultiply(); - void testInvert(); - void testEulerAngles(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestQuat); - - -void -TestQuat::testConstructor() -{ - { - Quat qq(1.23f, 2.34f, 3.45f, 4.56f); - CPPUNIT_ASSERT( isExactlyEqual(qq.x(), 1.23f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.y(), 2.34f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.z(), 3.45f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.w(), 4.56f) ); - } - - { - float a[] = { 1.23f, 2.34f, 3.45f, 4.56f }; - Quat qq(a); - CPPUNIT_ASSERT( isExactlyEqual(qq.x(), 1.23f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.y(), 2.34f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.z(), 3.45f) ); - CPPUNIT_ASSERT( isExactlyEqual(qq.w(), 4.56f) ); - } -} - - -void -TestQuat::testAxisAngle() -{ - float TOL = 1e-6f; - - Quat q1(1.0f, 2.0f, 3.0f, 4.0f); - Quat q2(1.2f, 2.3f, 3.4f, 4.5f); - - Vec3s v(1, 2, 3); - v.normalize(); - float a = float(M_PI / 4.f); - - Quat q(v,a); - float b = q.angle(); - Vec3s vv = q.axis(); - - CPPUNIT_ASSERT( isApproxEqual(a, b, TOL) ); - CPPUNIT_ASSERT( v.eq(vv, TOL) ); - - q1.setAxisAngle(v,a); - b = q1.angle(); - vv = q1.axis(); - CPPUNIT_ASSERT( isApproxEqual(a, b, TOL) ); - CPPUNIT_ASSERT( v.eq(vv, TOL) ); -} - - -void -TestQuat::testOpPlus() -{ - Quat q1(1.0f, 2.0f, 3.0f, 4.0f); - Quat q2(1.2f, 2.3f, 3.4f, 4.5f); - - Quat q = q1 + q2; - - float - x=q1.x()+q2.x(), y=q1.y()+q2.y(), z=q1.z()+q2.z(), w=q1.w()+q2.w(); - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); - - q = q1; - q += q2; - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); - - q.add(q1,q2); - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); -} - - -void -TestQuat::testOpMinus() -{ - Quat q1(1.0f, 2.0f, 3.0f, 4.0f); - Quat q2(1.2f, 2.3f, 3.4f, 4.5f); - - Quat q = q1 - q2; - - float - x=q1.x()-q2.x(), y=q1.y()-q2.y(), z=q1.z()-q2.z(), w=q1.w()-q2.w(); - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); - - q = q1; - q -= q2; - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); - - q.sub(q1,q2); - CPPUNIT_ASSERT( isExactlyEqual(q.x(), x) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), y) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), z) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), w) ); -} - - -void -TestQuat::testOpMultiply() -{ - Quat q1(1.0f, 2.0f, 3.0f, 4.0f); - Quat q2(1.2f, 2.3f, 3.4f, 4.5f); - - Quat q = q1 * 1.5f; - - CPPUNIT_ASSERT( isExactlyEqual(q.x(), float(1.5f)*q1.x()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), float(1.5f)*q1.y()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), float(1.5f)*q1.z()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), float(1.5f)*q1.w()) ); - - q = q1; - q *= 1.5f; - CPPUNIT_ASSERT( isExactlyEqual(q.x(), float(1.5f)*q1.x()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), float(1.5f)*q1.y()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), float(1.5f)*q1.z()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), float(1.5f)*q1.w()) ); - - q.scale(1.5f, q1); - CPPUNIT_ASSERT( isExactlyEqual(q.x(), float(1.5f)*q1.x()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.y(), float(1.5f)*q1.y()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.z(), float(1.5f)*q1.z()) ); - CPPUNIT_ASSERT( isExactlyEqual(q.w(), float(1.5f)*q1.w()) ); -} - - -void -TestQuat::testInvert() -{ - float TOL = 1e-6f; - - Quat q1(1.0f, 2.0f, 3.0f, 4.0f); - Quat q2(1.2f, 2.3f, 3.4f, 4.5f); - - - q1 = q2; - q2 = q2.inverse(); - - Quat q = q1*q2; - - CPPUNIT_ASSERT( q.eq( Quat(0,0,0,1), TOL ) ); - - q1.normalize(); - q2 = q1.conjugate(); - q = q1*q2; - CPPUNIT_ASSERT( q.eq( Quat(0,0,0,1), TOL ) ); -} - - -void -TestQuat::testEulerAngles() -{ - - { - double TOL = 1e-7; - - Mat4d rx, ry, rz; - const double angle1 = 20. * M_PI / 180.; - const double angle2 = 64. * M_PI / 180.; - const double angle3 = 125. *M_PI / 180.; - rx.setToRotation(Vec3d(1,0,0), angle1); - ry.setToRotation(Vec3d(0,1,0), angle2); - rz.setToRotation(Vec3d(0,0,1), angle3); - - Mat4d r = rx * ry * rz; - - const Quat rot(r.getMat3()); - Vec3d result = rot.eulerAngles(ZYX_ROTATION); - - rx.setToRotation(Vec3d(1,0,0), result[0]); - ry.setToRotation(Vec3d(0,1,0), result[1]); - rz.setToRotation(Vec3d(0,0,1), result[2]); - - Mat4d rtest = rx * ry * rz; - - CPPUNIT_ASSERT(r.eq(rtest, TOL)); - } - - { - double TOL = 1e-7; - - Mat4d rx, ry, rz; - const double angle1 = 20. * M_PI / 180.; - const double angle2 = 64. * M_PI / 180.; - const double angle3 = 125. *M_PI / 180.; - rx.setToRotation(Vec3d(1,0,0), angle1); - ry.setToRotation(Vec3d(0,1,0), angle2); - rz.setToRotation(Vec3d(0,0,1), angle3); - - Mat4d r = rz * ry * rx; - - const Quat rot(r.getMat3()); - Vec3d result = rot.eulerAngles(XYZ_ROTATION); - - rx.setToRotation(Vec3d(1,0,0), result[0]); - ry.setToRotation(Vec3d(0,1,0), result[1]); - rz.setToRotation(Vec3d(0,0,1), result[2]); - - Mat4d rtest = rz * ry * rx; - - CPPUNIT_ASSERT(r.eq(rtest, TOL)); - } - - { - double TOL = 1e-7; - - Mat4d rx, ry, rz; - const double angle1 = 20. * M_PI / 180.; - const double angle2 = 64. * M_PI / 180.; - const double angle3 = 125. *M_PI / 180.; - rx.setToRotation(Vec3d(1,0,0), angle1); - ry.setToRotation(Vec3d(0,1,0), angle2); - rz.setToRotation(Vec3d(0,0,1), angle3); - - Mat4d r = rz * rx * ry; - - const Quat rot(r.getMat3()); - Vec3d result = rot.eulerAngles(YXZ_ROTATION); - - rx.setToRotation(Vec3d(1,0,0), result[0]); - ry.setToRotation(Vec3d(0,1,0), result[1]); - rz.setToRotation(Vec3d(0,0,1), result[2]); - - Mat4d rtest = rz * rx * ry; - - CPPUNIT_ASSERT(r.eq(rtest, TOL)); - } - - { - const Quat rot(X_AXIS, 1.0); - Vec3s result = rot.eulerAngles(XZY_ROTATION); - CPPUNIT_ASSERT_EQUAL(result, Vec3s(1,0,0)); - } - -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestRay.cc b/openvdb_3_0_0_library/unittest/TestRay.cc deleted file mode 100755 index b582c0c..0000000 --- a/openvdb_3_0_0_library/unittest/TestRay.cc +++ /dev/null @@ -1,494 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -#define ASSERT_DOUBLES_APPROX_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/1.e-6); - -class TestRay : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestRay); - CPPUNIT_TEST(testInfinity); - CPPUNIT_TEST(testRay); - CPPUNIT_TEST(testTimeSpan); - CPPUNIT_TEST(testDDA); - CPPUNIT_TEST_SUITE_END(); - - void testInfinity(); - void testRay(); - void testTimeSpan(); - void testDDA(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestRay); - -// the Ray class makes use of infinity=1/0 so we test for it -void -TestRay::testInfinity() -{ - // This code generates compiler warnings which is why it's not - // enabled by default. - /* - const double one=1, zero = 0, infinity = one / zero; - CPPUNIT_ASSERT_DOUBLES_EQUAL( infinity , infinity,0);//not a NAN - CPPUNIT_ASSERT_DOUBLES_EQUAL( infinity , infinity+1,0);//not a NAN - CPPUNIT_ASSERT_DOUBLES_EQUAL( infinity , infinity*10,0);//not a NAN - CPPUNIT_ASSERT( zero < infinity); - CPPUNIT_ASSERT( zero > -infinity); - CPPUNIT_ASSERT_DOUBLES_EQUAL( zero , one/infinity,0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( zero , -one/infinity,0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( infinity , one/zero,0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-infinity , -one/zero,0); - - std::cerr << "inf: " << infinity << "\n"; - std::cerr << "1 / inf: " << one / infinity << "\n"; - std::cerr << "1 / (-inf): " << one / (-infinity) << "\n"; - std::cerr << " inf * 0: " << infinity * 0 << "\n"; - std::cerr << "-inf * 0: " << (-infinity) * 0 << "\n"; - std::cerr << "(inf): " << (bool)(infinity) << "\n"; - std::cerr << "inf == inf: " << (infinity == infinity) << "\n"; - std::cerr << "inf > 0: " << (infinity > 0) << "\n"; - std::cerr << "-inf > 0: " << ((-infinity) > 0) << "\n"; - */ -} - -void TestRay::testRay() -{ - using namespace openvdb; - typedef double RealT; - typedef math::Ray RayT; - typedef RayT::Vec3T Vec3T; - typedef math::BBox BBoxT; - - {//default constructor - RayT ray; - CPPUNIT_ASSERT(ray.eye() == Vec3T(0,0,0)); - CPPUNIT_ASSERT(ray.dir() == Vec3T(1,0,0)); - ASSERT_DOUBLES_APPROX_EQUAL( math::Delta::value(), ray.t0()); - ASSERT_DOUBLES_APPROX_EQUAL( std::numeric_limits::max(), ray.t1()); - } - - {// simple construction - - Vec3T eye(1.5,1.5,1.5), dir(1.5,1.5,1.5); dir.normalize(); - RealT t0=0.1, t1=12589.0; - - RayT ray(eye, dir, t0, t1); - CPPUNIT_ASSERT(ray.eye()==eye); - CPPUNIT_ASSERT(ray.dir()==dir); - ASSERT_DOUBLES_APPROX_EQUAL( t0, ray.t0()); - ASSERT_DOUBLES_APPROX_EQUAL( t1, ray.t1()); - } - - {// test transformation - math::Transform::Ptr xform = math::Transform::createLinearTransform(); - - xform->preRotate(M_PI, math::Y_AXIS ); - xform->postTranslate(math::Vec3d(1, 2, 3)); - xform->preScale(Vec3R(0.1, 0.2, 0.4)); - - Vec3T eye(9,1,1), dir(1,2,0); - dir.normalize(); - RealT t0=0.1, t1=12589.0; - - RayT ray0(eye, dir, t0, t1); - CPPUNIT_ASSERT( ray0.test(t0)); - CPPUNIT_ASSERT( ray0.test(t1)); - CPPUNIT_ASSERT( ray0.test(0.5*(t0+t1))); - CPPUNIT_ASSERT(!ray0.test(t0-1)); - CPPUNIT_ASSERT(!ray0.test(t1+1)); - //std::cerr << "Ray0: " << ray0 << std::endl; - RayT ray1 = ray0.applyMap( *(xform->baseMap()) ); - //std::cerr << "Ray1: " << ray1 << std::endl; - RayT ray2 = ray1.applyInverseMap( *(xform->baseMap()) ); - //std::cerr << "Ray2: " << ray2 << std::endl; - - ASSERT_DOUBLES_APPROX_EQUAL( eye[0], ray2.eye()[0]); - ASSERT_DOUBLES_APPROX_EQUAL( eye[1], ray2.eye()[1]); - ASSERT_DOUBLES_APPROX_EQUAL( eye[2], ray2.eye()[2]); - - ASSERT_DOUBLES_APPROX_EQUAL( dir[0], ray2.dir()[0]); - ASSERT_DOUBLES_APPROX_EQUAL( dir[1], ray2.dir()[1]); - ASSERT_DOUBLES_APPROX_EQUAL( dir[2], ray2.dir()[2]); - - ASSERT_DOUBLES_APPROX_EQUAL( dir[0], 1.0/ray2.invDir()[0]); - ASSERT_DOUBLES_APPROX_EQUAL( dir[1], 1.0/ray2.invDir()[1]); - ASSERT_DOUBLES_APPROX_EQUAL( dir[2], 1.0/ray2.invDir()[2]); - - ASSERT_DOUBLES_APPROX_EQUAL( t0, ray2.t0()); - ASSERT_DOUBLES_APPROX_EQUAL( t1, ray2.t1()); - } - - {// test transformation - - // This is the index to world transform - math::Transform::Ptr xform = math::Transform::createLinearTransform(); - xform->postRotate(M_PI, math::Y_AXIS ); - xform->postTranslate(math::Vec3d(1, 2, 3)); - xform->postScale(Vec3R(0.1, 0.1, 0.1));//voxel size - - // Define a ray in world space - Vec3T eye(9,1,1), dir(1,2,0); - dir.normalize(); - RealT t0=0.1, t1=12589.0; - RayT ray0(eye, dir, t0, t1); - //std::cerr << "\nWorld Ray0: " << ray0 << std::endl; - CPPUNIT_ASSERT( ray0.test(t0)); - CPPUNIT_ASSERT( ray0.test(t1)); - CPPUNIT_ASSERT( ray0.test(0.5*(t0+t1))); - CPPUNIT_ASSERT(!ray0.test(t0-1)); - CPPUNIT_ASSERT(!ray0.test(t1+1)); - Vec3T xyz0[3] = {ray0.start(), ray0.mid(), ray0.end()}; - - // Transform the ray to index space - RayT ray1 = ray0.applyInverseMap( *(xform->baseMap()) ); - //std::cerr << "\nIndex Ray1: " << ray1 << std::endl; - Vec3T xyz1[3] = {ray1.start(), ray1.mid(), ray1.end()}; - - for (int i=0; i<3; ++i) { - Vec3T pos = xform->baseMap()->applyMap(xyz1[i]); - //std::cerr << "world0 ="< DDAType; - const RayType::Vec3T eye( 0, 0, 0); - for (int s = -1; s<=1; s+=2) { - for (int a = 0; a<3; ++a) { - const int d[3]={s*(a==0), s*(a==1), s*(a==2)}; - const RayType::Vec3T dir(d[0], d[1], d[2]); - RayType ray(eye, dir); - DDAType dda(ray); - //std::cerr << "\nray: "< -#include // for ISGradient -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - - -class TestStats: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestStats); - CPPUNIT_TEST(testExtrema); - CPPUNIT_TEST(testStats); - CPPUNIT_TEST(testHistogram); - CPPUNIT_TEST(testGridExtrema); - CPPUNIT_TEST(testGridStats); - CPPUNIT_TEST(testGridHistogram); - CPPUNIT_TEST(testGridOperatorStats); - CPPUNIT_TEST_SUITE_END(); - - void testExtrema(); - void testStats(); - void testHistogram(); - void testGridExtrema(); - void testGridStats(); - void testGridHistogram(); - void testGridOperatorStats(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestStats); - -void -TestStats::testExtrema() -{ - {// trivial test - openvdb::math::Extrema s; - s.add(0); - s.add(1); - CPPUNIT_ASSERT_EQUAL(2, int(s.size())); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, s.min(), 0.000001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, s.max(), 0.000001); - //s.print("test"); - } - {// non-trivial test - openvdb::math::Extrema s; - const int data[5]={600, 470, 170, 430, 300}; - for (int i=0; i<5; ++i) s.add(data[i]); - CPPUNIT_ASSERT_EQUAL(5, int(s.size())); - CPPUNIT_ASSERT_DOUBLES_EQUAL(data[2], s.min(), 0.000001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(data[0], s.max(), 0.000001); - //s.print("test"); - } - {// non-trivial test of Extrema::add(Extrema) - openvdb::math::Extrema s, t; - const int data[5]={600, 470, 170, 430, 300}; - for (int i=0; i<3; ++i) s.add(data[i]); - for (int i=3; i<5; ++i) t.add(data[i]); - s.add(t); - CPPUNIT_ASSERT_EQUAL(5, int(s.size())); - CPPUNIT_ASSERT_DOUBLES_EQUAL(data[2], s.min(), 0.000001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(data[0], s.max(), 0.000001); - //s.print("test"); - } - {// Trivial test of Extrema::add(value, n) - openvdb::math::Extrema s; - const double val = 3.45; - const uint64_t n = 57; - s.add(val, 57); - CPPUNIT_ASSERT_EQUAL(n, s.size()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(val, s.min(), 0.000001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(val, s.max(), 0.000001); - } - {// Test 1 of Extrema::add(value), Extrema::add(value, n) and Extrema::add(Extrema) - openvdb::math::Extrema s, t; - const double val1 = 1.0, val2 = 3.0; - const uint64_t n1 = 1, n2 =1; - s.add(val1, n1); - CPPUNIT_ASSERT_EQUAL(uint64_t(n1), s.size()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(val1, s.min(), 0.000001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(val1, s.max(), 0.000001); - for (uint64_t i=0; i= h.min(j) && data[i] < h.max(j)) bin[j]++; - } - for (int i=0; i<5; ++i) CPPUNIT_ASSERT_EQUAL(bin[i],int(h.count(i))); - //h.print("test"); - } - {//Test print of Histogram - openvdb::math::Stats s; - const int N=500000; - for (int i=0; i - void operator()(const GridT::ValueOnCIter& it, StatsT& stats) const - { - typedef openvdb::math::ISGradient GradT; - if (it.isVoxelValue()) { - stats.add(GradT::result(acc, it.getCoord()).length()); - } else { - openvdb::CoordBBox bbox = it.getBoundingBox(); - openvdb::Coord xyz; - int &x = xyz[0], &y = xyz[1], &z = xyz[2]; - for (x = bbox.min()[0]; x <= bbox.max()[0]; ++x) { - for (y = bbox.min()[1]; y <= bbox.max()[1]; ++y) { - for (z = bbox.min()[2]; z <= bbox.max()[2]; ++z) { - stats.add(GradT::result(acc, xyz).length()); - } - } - } - } - } -}; - -} // unnamed namespace - -void -TestStats::testGridExtrema() -{ - using namespace openvdb; - - const int DIM = 109; - { - const float background = 0.0; - FloatGrid grid(background); - { - // Compute active value statistics for a grid with a single active voxel. - grid.tree().setValue(Coord(0), /*value=*/42.0); - math::Extrema ex = tools::extrema(grid.cbeginValueOn()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(42.0, ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(42.0, ex.max(), /*tolerance=*/0.0); - - // Compute inactive value statistics for a grid with only background voxels. - grid.tree().setValueOff(Coord(0), background); - ex = tools::extrema(grid.cbeginValueOff()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, ex.max(), /*tolerance=*/0.0); - } - - // Compute active value statistics for a grid with two active voxel populations - // of the same size but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), /*value=*/1.0); - grid.fill(CoordBBox::createCube(Coord(-300), DIM), /*value=*/-3.0); - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Extrema ex = tools::extrema(grid.cbeginValueOn(), threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(-3.0), ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), ex.max(), /*tolerance=*/0.0); - } - - // Compute active value statistics for just the positive values. - for (int threaded = 0; threaded <= 1; ++threaded) { - struct Local { - static void addIfPositive(const FloatGrid::ValueOnCIter& it, math::Extrema& ex) - { - const float f = *it; - if (f > 0.0) { - if (it.isVoxelValue()) ex.add(f); - else ex.add(f, it.getVoxelCount()); - } - } - }; - math::Extrema ex = - tools::extrema(grid.cbeginValueOn(), &Local::addIfPositive, threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), ex.max(), /*tolerance=*/0.0); - } - - // Compute active value statistics for the first-order gradient. - for (int threaded = 0; threaded <= 1; ++threaded) { - // First, using a custom ValueOp... - math::Extrema ex = tools::extrema(grid.cbeginValueOn(), GradOp(grid), threaded); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0.0), ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - double(9.0 + 9.0 + 9.0), ex.max() * ex.max(), /*tol=*/1.0e-3); - // max gradient is (dx, dy, dz) = (-3 - 0, -3 - 0, -3 - 0) - - // ...then using tools::opStatistics(). - typedef math::ISOpMagnitude > MathOp; - ex = tools::opExtrema(grid.cbeginValueOn(), MathOp(), threaded); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0.0), ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - double(9.0 + 9.0 + 9.0), ex.max() * ex.max(), /*tolerance=*/1.0e-3); - // max gradient is (dx, dy, dz) = (-3 - 0, -3 - 0, -3 - 0) - } - } - { - const Vec3s background(0.0); - Vec3SGrid grid(background); - - // Compute active vector magnitude statistics for a vector-valued grid - // with two active voxel populations of the same size but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), Vec3s(3.0, 0.0, 4.0)); // length = 5 - grid.fill(CoordBBox::createCube(Coord(-300), DIM), Vec3s(1.0, 2.0, 2.0)); // length = 3 - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Extrema ex = tools::extrema(grid.cbeginValueOn(), threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(3.0), ex.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(5.0), ex.max(), /*tolerance=*/0.0); - } - } -} - -void -TestStats::testGridStats() -{ - using namespace openvdb; - - const int DIM = 109; - { - const float background = 0.0; - FloatGrid grid(background); - { - // Compute active value statistics for a grid with a single active voxel. - grid.tree().setValue(Coord(0), /*value=*/42.0); - math::Stats stats = tools::statistics(grid.cbeginValueOn()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(42.0, stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(42.0, stats.max(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(42.0, stats.mean(), /*tolerance=*/1.0e-8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, stats.variance(), /*tolerance=*/1.0e-8); - - // Compute inactive value statistics for a grid with only background voxels. - grid.tree().setValueOff(Coord(0), background); - stats = tools::statistics(grid.cbeginValueOff()); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, stats.max(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(background, stats.mean(), /*tolerance=*/1.0e-8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, stats.variance(), /*tolerance=*/1.0e-8); - } - - // Compute active value statistics for a grid with two active voxel populations - // of the same size but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), /*value=*/1.0); - grid.fill(CoordBBox::createCube(Coord(-300), DIM), /*value=*/-3.0); - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Stats stats = tools::statistics(grid.cbeginValueOn(), threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(-3.0), stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), stats.max(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(-1.0), stats.mean(), /*tolerance=*/1.0e-8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(4.0), stats.variance(), /*tolerance=*/1.0e-8); - } - - // Compute active value statistics for just the positive values. - for (int threaded = 0; threaded <= 1; ++threaded) { - struct Local { - static void addIfPositive(const FloatGrid::ValueOnCIter& it, math::Stats& stats) - { - const float f = *it; - if (f > 0.0) { - if (it.isVoxelValue()) stats.add(f); - else stats.add(f, it.getVoxelCount()); - } - } - }; - math::Stats stats = - tools::statistics(grid.cbeginValueOn(), &Local::addIfPositive, threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), stats.max(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), stats.mean(), /*tolerance=*/1.0e-8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0.0), stats.variance(), /*tolerance=*/1.0e-8); - } - - // Compute active value statistics for the first-order gradient. - for (int threaded = 0; threaded <= 1; ++threaded) { - // First, using a custom ValueOp... - math::Stats stats = tools::statistics(grid.cbeginValueOn(), GradOp(grid), threaded); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0.0), stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - double(9.0 + 9.0 + 9.0), stats.max() * stats.max(), /*tol=*/1.0e-3); - // max gradient is (dx, dy, dz) = (-3 - 0, -3 - 0, -3 - 0) - - // ...then using tools::opStatistics(). - typedef math::ISOpMagnitude > MathOp; - stats = tools::opStatistics(grid.cbeginValueOn(), MathOp(), threaded); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0.0), stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - double(9.0 + 9.0 + 9.0), stats.max() * stats.max(), /*tolerance=*/1.0e-3); - // max gradient is (dx, dy, dz) = (-3 - 0, -3 - 0, -3 - 0) - } - } - { - const Vec3s background(0.0); - Vec3SGrid grid(background); - - // Compute active vector magnitude statistics for a vector-valued grid - // with two active voxel populations of the same size but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), Vec3s(3.0, 0.0, 4.0)); // length = 5 - grid.fill(CoordBBox::createCube(Coord(-300), DIM), Vec3s(1.0, 2.0, 2.0)); // length = 3 - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Stats stats = tools::statistics(grid.cbeginValueOn(), threaded); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(3.0), stats.min(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(5.0), stats.max(), /*tolerance=*/0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(4.0), stats.mean(), /*tolerance=*/1.0e-8); - CPPUNIT_ASSERT_DOUBLES_EQUAL(double(1.0), stats.variance(), /*tolerance=*/1.0e-8); - } - } -} - - -namespace { - -template -inline void -doTestGridOperatorStats(const GridT& grid, const OpT& op) -{ - openvdb::math::Stats serialStats = - openvdb::tools::opStatistics(grid.cbeginValueOn(), op, /*threaded=*/false); - - openvdb::math::Stats parallelStats = - openvdb::tools::opStatistics(grid.cbeginValueOn(), op, /*threaded=*/true); - - // Verify that the results from threaded and serial runs are equivalent. - CPPUNIT_ASSERT_EQUAL(serialStats.size(), parallelStats.size()); - ASSERT_DOUBLES_EXACTLY_EQUAL(serialStats.min(), parallelStats.min()); - ASSERT_DOUBLES_EXACTLY_EQUAL(serialStats.max(), parallelStats.max()); - CPPUNIT_ASSERT_DOUBLES_EQUAL(serialStats.mean(), parallelStats.mean(), /*tolerance=*/1.0e-6); - CPPUNIT_ASSERT_DOUBLES_EQUAL(serialStats.variance(), parallelStats.variance(), 1.0e-6); -} - -} - -void -TestStats::testGridOperatorStats() -{ - using namespace openvdb; - - typedef math::UniformScaleMap MapType; - MapType map; - - const int DIM = 109; - { - // Test operations on a scalar grid. - const float background = 0.0; - FloatGrid grid(background); - grid.fill(CoordBBox::createCube(Coord(0), DIM), /*value=*/1.0); - grid.fill(CoordBBox::createCube(Coord(-300), DIM), /*value=*/-3.0); - - { // Magnitude of gradient computed via first-order differencing - typedef math::MapAdapter, MapType>, double> OpT; - doTestGridOperatorStats(grid, OpT(map)); - } - { // Magnitude of index-space gradient computed via first-order differencing - typedef math::ISOpMagnitude > OpT; - doTestGridOperatorStats(grid, OpT()); - } - { // Laplacian of index-space gradient computed via second-order central differencing - typedef math::ISLaplacian OpT; - doTestGridOperatorStats(grid, OpT()); - } - } - { - // Test operations on a vector grid. - const Vec3s background(0.0); - Vec3SGrid grid(background); - grid.fill(CoordBBox::createCube(Coord(0), DIM), Vec3s(3.0, 0.0, 4.0)); // length = 5 - grid.fill(CoordBBox::createCube(Coord(-300), DIM), Vec3s(1.0, 2.0, 2.0)); // length = 3 - - { // Divergence computed via first-order differencing - typedef math::MapAdapter, double> OpT; - doTestGridOperatorStats(grid, OpT(map)); - } - { // Magnitude of curl computed via first-order differencing - typedef math::MapAdapter, MapType>, double> OpT; - doTestGridOperatorStats(grid, OpT(map)); - } - { // Magnitude of index-space curl computed via first-order differencing - typedef math::ISOpMagnitude > OpT; - doTestGridOperatorStats(grid, OpT()); - } - } -} - - -void -TestStats::testGridHistogram() -{ - using namespace openvdb; - - const int DIM = 109; - { - const float background = 0.0; - FloatGrid grid(background); - { - const double value = 42.0; - - // Compute a histogram of the active values of a grid with a single active voxel. - grid.tree().setValue(Coord(0), value); - math::Histogram hist = tools::histogram(grid.cbeginValueOn(), - /*min=*/0.0, /*max=*/100.0); - - for (int i = 0, N = int(hist.numBins()); i < N; ++i) { - uint64_t expected = ((hist.min(i) <= value && value <= hist.max(i)) ? 1 : 0); - CPPUNIT_ASSERT_EQUAL(expected, hist.count(i)); - } - } - - // Compute a histogram of the active values of a grid with two - // active voxel populations of the same size but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), /*value=*/1.0); - grid.fill(CoordBBox::createCube(Coord(-300), DIM), /*value=*/3.0); - - CPPUNIT_ASSERT_EQUAL(uint64_t(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Histogram hist = tools::histogram(grid.cbeginValueOn(), - /*min=*/0.0, /*max=*/10.0, /*numBins=*/9, threaded); - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), hist.size()); - for (int i = 0, N = int(hist.numBins()); i < N; ++i) { - if (i == 0 || i == 2) { - CPPUNIT_ASSERT_EQUAL(uint64_t(DIM * DIM * DIM), hist.count(i)); - } else { - CPPUNIT_ASSERT_EQUAL(uint64_t(0), hist.count(i)); - } - } - } - } - { - const Vec3s background(0.0); - Vec3SGrid grid(background); - - // Compute a histogram of vector magnitudes of the active values of a - // vector-valued grid with two active voxel populations of the same size - // but two different values. - grid.fill(CoordBBox::createCube(Coord(0), DIM), Vec3s(3.0, 0.0, 4.0)); // length = 5 - grid.fill(CoordBBox::createCube(Coord(-300), DIM), Vec3s(1.0, 2.0, 2.0)); // length = 3 - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), grid.activeVoxelCount()); - - for (int threaded = 0; threaded <= 1; ++threaded) { - math::Histogram hist = tools::histogram(grid.cbeginValueOn(), - /*min=*/0.0, /*max=*/10.0, /*numBins=*/9, threaded); - - CPPUNIT_ASSERT_EQUAL(Index64(2 * DIM * DIM * DIM), hist.size()); - for (int i = 0, N = int(hist.numBins()); i < N; ++i) { - if (i == 2 || i == 4) { - CPPUNIT_ASSERT_EQUAL(uint64_t(DIM * DIM * DIM), hist.count(i)); - } else { - CPPUNIT_ASSERT_EQUAL(uint64_t(0), hist.count(i)); - } - } - } - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestStream.cc b/openvdb_3_0_0_library/unittest/TestStream.cc deleted file mode 100755 index 2081703..0000000 --- a/openvdb_3_0_0_library/unittest/TestStream.cc +++ /dev/null @@ -1,278 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for remove() -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(a, b) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((a), (b), /*tolerance=*/0.0); - - -class TestStream: public CppUnit::TestCase -{ -public: - virtual void setUp(); - virtual void tearDown(); - - CPPUNIT_TEST_SUITE(TestStream); - CPPUNIT_TEST(testWrite); - CPPUNIT_TEST(testRead); - CPPUNIT_TEST(testFileReadFromStream); - CPPUNIT_TEST_SUITE_END(); - - void testWrite(); - void testRead(); - void testFileReadFromStream(); - -private: - static openvdb::GridPtrVecPtr createTestGrids(openvdb::MetaMap::Ptr&); - static void verifyTestGrids(openvdb::GridPtrVecPtr, openvdb::MetaMap::Ptr); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestStream); - - -//////////////////////////////////////// - - -void -TestStream::setUp() -{ - openvdb::uninitialize(); - - openvdb::Int32Grid::registerGrid(); - openvdb::FloatGrid::registerGrid(); - - openvdb::StringMetadata::registerType(); - openvdb::Int32Metadata::registerType(); - openvdb::Int64Metadata::registerType(); - openvdb::Vec3IMetadata::registerType(); - - // Register maps - openvdb::math::MapRegistry::clear(); - openvdb::math::AffineMap::registerMap(); - openvdb::math::ScaleMap::registerMap(); - openvdb::math::UniformScaleMap::registerMap(); - openvdb::math::TranslationMap::registerMap(); - openvdb::math::ScaleTranslateMap::registerMap(); - openvdb::math::UniformScaleTranslateMap::registerMap(); - openvdb::math::NonlinearFrustumMap::registerMap(); -} - - -void -TestStream::tearDown() -{ - openvdb::uninitialize(); -} - - -//////////////////////////////////////// - - -openvdb::GridPtrVecPtr -TestStream::createTestGrids(openvdb::MetaMap::Ptr& metadata) -{ - using namespace openvdb; - - // Create trees - Int32Tree::Ptr tree1(new Int32Tree(1)); - FloatTree::Ptr tree2(new FloatTree(2.0)); - - // Set some values - tree1->setValue(Coord(0, 0, 0), 5); - tree1->setValue(Coord(100, 0, 0), 6); - tree2->setValue(Coord(0, 0, 0), 10); - tree2->setValue(Coord(0, 100, 0), 11); - - // Create grids - GridBase::Ptr - grid1 = createGrid(tree1), - grid2 = createGrid(tree1), // instance of grid1 - grid3 = createGrid(tree2); - grid1->setName("density"); - grid2->setName("density_copy"); - grid3->setName("temperature"); - - // Create transforms - math::Transform::Ptr trans1 = math::Transform::createLinearTransform(0.1); - math::Transform::Ptr trans2 = math::Transform::createLinearTransform(0.1); - grid1->setTransform(trans1); - grid2->setTransform(trans2); - grid3->setTransform(trans2); - - metadata.reset(new MetaMap); - metadata->insertMeta("author", StringMetadata("Einstein")); - metadata->insertMeta("year", Int32Metadata(2009)); - - GridPtrVecPtr grids(new GridPtrVec); - grids->push_back(grid1); - grids->push_back(grid2); - grids->push_back(grid3); - - return grids; -} - - -void -TestStream::verifyTestGrids(openvdb::GridPtrVecPtr grids, openvdb::MetaMap::Ptr meta) -{ - using namespace openvdb; - - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT(meta.get() != NULL); - - // Verify the metadata. - CPPUNIT_ASSERT_EQUAL(2, int(meta->metaCount())); - CPPUNIT_ASSERT_EQUAL(std::string("Einstein"), meta->metaValue("author")); - CPPUNIT_ASSERT_EQUAL(2009, meta->metaValue("year")); - - // Verify the grids. - CPPUNIT_ASSERT_EQUAL(3, int(grids->size())); - - GridBase::Ptr grid = findGridByName(*grids, "density"); - CPPUNIT_ASSERT(grid.get() != NULL); - Int32Tree::Ptr density = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(density.get() != NULL); - - grid.reset(); - grid = findGridByName(*grids, "density_copy"); - CPPUNIT_ASSERT(grid.get() != NULL); - CPPUNIT_ASSERT(gridPtrCast(grid)->treePtr().get() != NULL); - // Verify that "density_copy" is an instance of (i.e., shares a tree with) "density". - CPPUNIT_ASSERT_EQUAL(density, gridPtrCast(grid)->treePtr()); - - grid.reset(); - grid = findGridByName(*grids, "temperature"); - CPPUNIT_ASSERT(grid.get() != NULL); - FloatTree::Ptr temperature = gridPtrCast(grid)->treePtr(); - CPPUNIT_ASSERT(temperature.get() != NULL); - - ASSERT_DOUBLES_EXACTLY_EQUAL(5, density->getValue(Coord(0, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(6, density->getValue(Coord(100, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(10, temperature->getValue(Coord(0, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(11, temperature->getValue(Coord(0, 100, 0))); -} - - -//////////////////////////////////////// - - -void -TestStream::testWrite() -{ - using namespace openvdb; - - // Create test grids and stream them to a string. - MetaMap::Ptr meta; - GridPtrVecPtr grids = createTestGrids(meta); - std::ostringstream ostr(std::ios_base::binary); - io::Stream(ostr).write(*grids, *meta); - //std::ofstream file("debug.vdb2", std::ios_base::binary); - //file << ostr.str(); - - // Stream the grids back in. - std::istringstream is(ostr.str(), std::ios_base::binary); - io::Stream strm(is); - meta = strm.getMetadata(); - grids = strm.getGrids(); - - verifyTestGrids(grids, meta); -} - - -void -TestStream::testRead() -{ - using namespace openvdb; - - // Create test grids and write them to a file. - MetaMap::Ptr meta; - GridPtrVecPtr grids = createTestGrids(meta); - const char* filename = "something.vdb2"; - io::File(filename).write(*grids, *meta); - boost::shared_ptr scopedFile(filename, ::remove); - - // Stream the grids back in. - std::ifstream is(filename, std::ios_base::binary); - io::Stream strm(is); - meta = strm.getMetadata(); - grids = strm.getGrids(); - - verifyTestGrids(grids, meta); -} - - -/// Stream grids to a file using io::Stream, then read the file back using io::File. -void -TestStream::testFileReadFromStream() -{ - using namespace openvdb; - - MetaMap::Ptr meta; - GridPtrVecPtr grids; - - // Create test grids and stream them to a file (and then close the file). - const char* filename = "something.vdb2"; - boost::shared_ptr scopedFile(filename, ::remove); - { - std::ofstream os(filename, std::ios_base::binary); - grids = createTestGrids(meta); - io::Stream(os).write(*grids, *meta); - } - - // Read the grids back in. - io::File file(filename); - CPPUNIT_ASSERT(file.inputHasGridOffsets()); - CPPUNIT_ASSERT_THROW(file.getGrids(), IoError); - - file.open(); - meta = file.getMetadata(); - grids = file.getGrids(); - - CPPUNIT_ASSERT(!file.inputHasGridOffsets()); - CPPUNIT_ASSERT(meta.get() != NULL); - CPPUNIT_ASSERT(grids.get() != NULL); - CPPUNIT_ASSERT(!grids->empty()); - - verifyTestGrids(grids, meta); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestStringMetadata.cc b/openvdb_3_0_0_library/unittest/TestStringMetadata.cc deleted file mode 100755 index b9bb827..0000000 --- a/openvdb_3_0_0_library/unittest/TestStringMetadata.cc +++ /dev/null @@ -1,74 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestStringMetadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestStringMetadata); - CPPUNIT_TEST(test); - CPPUNIT_TEST_SUITE_END(); - - void test(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestStringMetadata); - -void -TestStringMetadata::test() -{ - using namespace openvdb; - - Metadata::Ptr m(new StringMetadata("testing")); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("string") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("string") == 0); - - StringMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value().compare("testing") == 0); - s->value() = "testing2"; - CPPUNIT_ASSERT(s->value().compare("testing2") == 0); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value().compare("testing2") == 0); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTools.cc b/openvdb_3_0_0_library/unittest/TestTools.cc deleted file mode 100755 index 053fd3f..0000000 --- a/openvdb_3_0_0_library/unittest/TestTools.cc +++ /dev/null @@ -1,2057 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -class TestTools: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestTools); - CPPUNIT_TEST(testDilateVoxels); - CPPUNIT_TEST(testErodeVoxels); - CPPUNIT_TEST(testActivate); - CPPUNIT_TEST(testFilter); - CPPUNIT_TEST(testFloatApply); - CPPUNIT_TEST(testLevelSetSphere); - CPPUNIT_TEST(testLevelSetAdvect); - CPPUNIT_TEST(testLevelSetMeasure); - CPPUNIT_TEST(testLevelSetMorph); - CPPUNIT_TEST(testMagnitude); - CPPUNIT_TEST(testMaskedMagnitude); - CPPUNIT_TEST(testNormalize); - CPPUNIT_TEST(testMaskedNormalize); - CPPUNIT_TEST(testPointAdvect); - CPPUNIT_TEST(testPointScatter); - CPPUNIT_TEST(testTransformValues); - CPPUNIT_TEST(testVectorApply); - CPPUNIT_TEST(testAccumulate); - CPPUNIT_TEST(testUtil); - CPPUNIT_TEST(testVectorTransformer); - CPPUNIT_TEST(testClipping); - - CPPUNIT_TEST_SUITE_END(); - - void testDilateVoxels(); - void testErodeVoxels(); - void testActivate(); - void testFilter(); - void testFloatApply(); - void testLevelSetSphere(); - void testLevelSetAdvect(); - void testLevelSetMeasure(); - void testLevelSetMorph(); - void testMagnitude(); - void testMaskedMagnitude(); - void testNormalize(); - void testMaskedNormalize(); - void testPointAdvect(); - void testPointScatter(); - void testTransformValues(); - void testVectorApply(); - void testAccumulate(); - void testUtil(); - void testVectorTransformer(); - void testClipping(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTools); - - -#if 0 -namespace { - -// Simple helper class to write out numbered vdbs -template -class FrameWriter -{ -public: - FrameWriter(int version, typename GridT::Ptr grid): - mFrame(0), mVersion(version), mGrid(grid) - {} - - void operator()(const std::string& name, float time, size_t n) - { - std::ostringstream ostr; - ostr << "/tmp/" << name << "_" << mVersion << "_" << mFrame << ".vdb"; - openvdb::io::File file(ostr.str()); - openvdb::GridPtrVec grids; - grids.push_back(mGrid); - file.write(grids); - std::cerr << "\nWrote \"" << ostr.str() << "\" with time = " - << time << " after CFL-iterations = " << n << std::endl; - ++mFrame; - } - -private: - int mFrame, mVersion; - typename GridT::Ptr mGrid; -}; - -} // unnamed namespace -#endif - - -void -TestTools::testDilateVoxels() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Index32; - using openvdb::Index64; - - typedef openvdb::tree::Tree4::Type Tree543f; - - Tree543f::Ptr tree(new Tree543f); - openvdb::tools::changeBackground(*tree, /*background=*/5.0); - CPPUNIT_ASSERT(tree->empty()); - - const openvdb::Index leafDim = Tree543f::LeafNodeType::DIM; - CPPUNIT_ASSERT_EQUAL(1 << 3, int(leafDim)); - - { - // Set and dilate a single voxel at the center of a leaf node. - tree->clear(); - tree->setValue(Coord(leafDim >> 1), 1.0); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(Index64(7), tree->activeVoxelCount()); - } - { - // Create an active, leaf node-sized tile. - tree->clear(); - tree->fill(CoordBBox(Coord(0), Coord(leafDim - 1)), 1.0); - CPPUNIT_ASSERT_EQUAL(Index32(0), tree->leafCount()); - CPPUNIT_ASSERT_EQUAL(Index64(leafDim * leafDim * leafDim), tree->activeVoxelCount()); - - tree->setValue(Coord(leafDim, leafDim - 1, leafDim - 1), 1.0); - CPPUNIT_ASSERT_EQUAL(Index64(leafDim * leafDim * leafDim + 1), - tree->activeVoxelCount()); - - openvdb::tools::dilateVoxels(*tree); - - CPPUNIT_ASSERT_EQUAL(Index64(leafDim * leafDim * leafDim + 1 + 5), - tree->activeVoxelCount()); - } - { - // Set and dilate a single voxel at each of the eight corners of a leaf node. - for (int i = 0; i < 8; ++i) { - tree->clear(); - - openvdb::Coord xyz( - i & 1 ? leafDim - 1 : 0, - i & 2 ? leafDim - 1 : 0, - i & 4 ? leafDim - 1 : 0); - tree->setValue(xyz, 1.0); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(Index64(7), tree->activeVoxelCount()); - } - } - { - tree->clear(); - tree->setValue(Coord(0), 1.0); - tree->setValue(Coord( 1, 0, 0), 1.0); - tree->setValue(Coord(-1, 0, 0), 1.0); - CPPUNIT_ASSERT_EQUAL(Index64(3), tree->activeVoxelCount()); - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(Index64(17), tree->activeVoxelCount()); - } - { - struct Info { int activeVoxelCount, leafCount, nonLeafCount; }; - Info iterInfo[11] = { - { 1, 1, 3 }, - { 7, 1, 3 }, - { 25, 1, 3 }, - { 63, 1, 3 }, - { 129, 4, 3 }, - { 231, 7, 9 }, - { 377, 7, 9 }, - { 575, 7, 9 }, - { 833, 10, 9 }, - { 1159, 16, 9 }, - { 1561, 19, 15 }, - }; - - // Perform repeated dilations, starting with a single voxel. - tree->clear(); - tree->setValue(Coord(leafDim >> 1), 1.0); - for (int i = 0; i < 11; ++i) { - CPPUNIT_ASSERT_EQUAL(iterInfo[i].activeVoxelCount, int(tree->activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(iterInfo[i].leafCount, int(tree->leafCount())); - CPPUNIT_ASSERT_EQUAL(iterInfo[i].nonLeafCount, int(tree->nonLeafCount())); - - openvdb::tools::dilateVoxels(*tree); - } - } - - {// dialte a narrow band of a sphere - typedef openvdb::Grid GridType; - GridType grid(tree->background()); - unittest_util::makeSphere(/*dim=*/openvdb::Coord(64, 64, 64), - /*center=*/openvdb::Vec3f(0, 0, 0), - /*radius=*/20, grid, /*dx=*/1.0f, - unittest_util::SPHERE_DENSE_NARROW_BAND); - const openvdb::Index64 count = grid.tree().activeVoxelCount(); - openvdb::tools::dilateVoxels(grid.tree()); - CPPUNIT_ASSERT(grid.tree().activeVoxelCount() > count); - } - - {// dilate a fog volume of a sphere - typedef openvdb::Grid GridType; - GridType grid(tree->background()); - unittest_util::makeSphere(/*dim=*/openvdb::Coord(64, 64, 64), - /*center=*/openvdb::Vec3f(0, 0, 0), - /*radius=*/20, grid, /*dx=*/1.0f, - unittest_util::SPHERE_DENSE_NARROW_BAND); - openvdb::tools::sdfToFogVolume(grid); - const openvdb::Index64 count = grid.tree().activeVoxelCount(); - //std::cerr << "\nBefore: active voxel count = " << count << std::endl; - //grid.print(std::cerr,5); - openvdb::tools::dilateVoxels(grid.tree()); - CPPUNIT_ASSERT(grid.tree().activeVoxelCount() > count); - //std::cerr << "\nAfter: active voxel count = " - // << grid.tree().activeVoxelCount() << std::endl; - } -// {// Test a grid from a file that has proven to be challenging -// openvdb::initialize(); -// openvdb::io::File file("/usr/home/kmuseth/Data/vdb/dilation.vdb"); -// file.open(); -// openvdb::GridBase::Ptr baseGrid = file.readGrid(file.beginName().gridName()); -// file.close(); -// openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast(baseGrid); -// const openvdb::Index64 count = grid->tree().activeVoxelCount(); -// //std::cerr << "\nBefore: active voxel count = " << count << std::endl; -// //grid->print(std::cerr,5); -// openvdb::tools::dilateVoxels(grid->tree()); -// CPPUNIT_ASSERT(grid->tree().activeVoxelCount() > count); -// //std::cerr << "\nAfter: active voxel count = " -// // << grid->tree().activeVoxelCount() << std::endl; -// } - - {// test dilateVoxels6 - for (int x=0; x<8; ++x) { - for (int y=0; y<8; ++y) { - for (int z=0; z<8; ++z) { - const openvdb::Coord ijk(x,y,z); - Tree543f tree1(0.0f); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree1.activeVoxelCount()); - tree1.setValue(ijk, 1.0f); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree1.isValueOn(ijk)); - openvdb::tools::Morphology m(tree1); - m.dilateVoxels6(); - for (int i=-1; i<=1; ++i) { - for (int j=-1; j<=1; ++j) { - for (int k=-1; k<=1; ++k) { - const openvdb::Coord xyz = ijk.offsetBy(i,j,k), d=ijk-xyz; - const int n= openvdb::math::Abs(d[0]) - + openvdb::math::Abs(d[1]) - + openvdb::math::Abs(d[2]); - if (n<=1) { - CPPUNIT_ASSERT( tree1.isValueOn(xyz)); - } else { - CPPUNIT_ASSERT(!tree1.isValueOn(xyz)); - } - } - } - } - CPPUNIT_ASSERT_EQUAL(Index64(1 + 6), tree1.activeVoxelCount()); - } - } - } - } - {// test dilateVoxels18 - for (int x=0; x<8; ++x) { - for (int y=0; y<8; ++y) { - for (int z=0; z<8; ++z) { - const openvdb::Coord ijk(x,y,z); - Tree543f tree1(0.0f); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree1.activeVoxelCount()); - tree1.setValue(ijk, 1.0f); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree1.isValueOn(ijk)); - openvdb::tools::Morphology m(tree1); - m.dilateVoxels18(); - for (int i=-1; i<=1; ++i) { - for (int j=-1; j<=1; ++j) { - for (int k=-1; k<=1; ++k) { - const openvdb::Coord xyz = ijk.offsetBy(i,j,k), d=ijk-xyz; - const int n= openvdb::math::Abs(d[0]) - + openvdb::math::Abs(d[1]) - + openvdb::math::Abs(d[2]); - if (n<=2) { - CPPUNIT_ASSERT( tree1.isValueOn(xyz)); - } else { - CPPUNIT_ASSERT(!tree1.isValueOn(xyz)); - } - } - } - } - CPPUNIT_ASSERT_EQUAL(Index64(1 + 6 + 12), tree1.activeVoxelCount()); - } - } - } - } - {// test dilateVoxels26 - for (int x=0; x<8; ++x) { - for (int y=0; y<8; ++y) { - for (int z=0; z<8; ++z) { - const openvdb::Coord ijk(x,y,z); - Tree543f tree1(0.0f); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree1.activeVoxelCount()); - tree1.setValue(ijk, 1.0f); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree1.isValueOn(ijk)); - openvdb::tools::Morphology m(tree1); - m.dilateVoxels26(); - for (int i=-1; i<=1; ++i) { - for (int j=-1; j<=1; ++j) { - for (int k=-1; k<=1; ++k) { - const openvdb::Coord xyz = ijk.offsetBy(i,j,k), d=ijk-xyz; - const int n = openvdb::math::Abs(d[0]) - + openvdb::math::Abs(d[1]) - + openvdb::math::Abs(d[2]); - if (n<=3) { - CPPUNIT_ASSERT( tree1.isValueOn(xyz)); - } else { - CPPUNIT_ASSERT(!tree1.isValueOn(xyz)); - } - } - } - } - CPPUNIT_ASSERT_EQUAL(Index64(1 + 6 + 12 + 8), tree1.activeVoxelCount()); - } - } - } - } - /* - // Performance test - {// dialte a narrow band of a sphere - const float radius = 335.3f; - const openvdb::Vec3f center(15.8f, 13.2f, 16.7f); - const float voxelSize = 1.5f, width = 3.25f; - openvdb::FloatGrid::Ptr grid = - openvdb::tools::createLevelSetSphere( - radius, center, voxelSize, width); - //grid->print(std::cerr, 3); - const openvdb::Index64 count = grid->tree().activeVoxelCount(); - openvdb::util::CpuTimer t; - t.start("sphere dilateVoxels6"); - openvdb::tools::dilateVoxels(grid->tree()); - t.stop(); - CPPUNIT_ASSERT(grid->tree().activeVoxelCount() > count); - // grid->print(std::cerr, 3); - } - {// dialte a narrow band of a sphere - const float radius = 335.3f; - const openvdb::Vec3f center(15.8f, 13.2f, 16.7f); - const float voxelSize = 1.5f, width = 3.25f; - openvdb::FloatGrid::Ptr grid = - openvdb::tools::createLevelSetSphere( - radius, center, voxelSize, width); - //grid->print(std::cerr, 3); - const openvdb::Index64 count = grid->tree().activeVoxelCount(); - openvdb::util::CpuTimer t; - t.start("sphere dilateVoxels18"); - openvdb::tools::dilateVoxels(grid->tree(), 1, openvdb::tools::NN_FACE_EDGE); - t.stop(); - CPPUNIT_ASSERT(grid->tree().activeVoxelCount() > count); - //grid->print(std::cerr, 3); - } - {// dialte a narrow band of a sphere - const float radius = 335.3f; - const openvdb::Vec3f center(15.8f, 13.2f, 16.7f); - const float voxelSize = 1.5f, width = 3.25f; - openvdb::FloatGrid::Ptr grid = - openvdb::tools::createLevelSetSphere( - radius, center, voxelSize, width); - //grid->print(std::cerr, 3); - const openvdb::Index64 count = grid->tree().activeVoxelCount(); - openvdb::util::CpuTimer t; - t.start("sphere dilateVoxels26"); - openvdb::tools::dilateVoxels(grid->tree(), 1, openvdb::tools::NN_FACE_EDGE_VERTEX); - t.stop(); - CPPUNIT_ASSERT(grid->tree().activeVoxelCount() > count); - //grid->print(std::cerr, 3); - } - */ -} - -void -TestTools::testErodeVoxels() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Index32; - using openvdb::Index64; - - typedef openvdb::tree::Tree4::Type TreeType; - - TreeType::Ptr tree(new TreeType); - openvdb::tools::changeBackground(*tree, /*background=*/5.0); - CPPUNIT_ASSERT(tree->empty()); - - const int leafDim = TreeType::LeafNodeType::DIM; - CPPUNIT_ASSERT_EQUAL(1 << 3, leafDim); - - { - // Set, dilate and erode a single voxel at the center of a leaf node. - tree->clear(); - CPPUNIT_ASSERT_EQUAL(0, int(tree->activeVoxelCount())); - - tree->setValue(Coord(leafDim >> 1), 1.0); - CPPUNIT_ASSERT_EQUAL(1, int(tree->activeVoxelCount())); - - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(7, int(tree->activeVoxelCount())); - - openvdb::tools::erodeVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(1, int(tree->activeVoxelCount())); - - openvdb::tools::erodeVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(0, int(tree->activeVoxelCount())); - } - { - // Create an active, leaf node-sized tile. - tree->clear(); - tree->fill(CoordBBox(Coord(0), Coord(leafDim - 1)), 1.0); - CPPUNIT_ASSERT_EQUAL(0, int(tree->leafCount())); - CPPUNIT_ASSERT_EQUAL(leafDim * leafDim * leafDim, int(tree->activeVoxelCount())); - - tree->setValue(Coord(leafDim, leafDim - 1, leafDim - 1), 1.0); - CPPUNIT_ASSERT_EQUAL(1, int(tree->leafCount())); - CPPUNIT_ASSERT_EQUAL(leafDim * leafDim * leafDim + 1,int(tree->activeVoxelCount())); - - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(3, int(tree->leafCount())); - CPPUNIT_ASSERT_EQUAL(leafDim * leafDim * leafDim + 1 + 5,int(tree->activeVoxelCount())); - - openvdb::tools::erodeVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(1, int(tree->leafCount())); - CPPUNIT_ASSERT_EQUAL(leafDim * leafDim * leafDim + 1, int(tree->activeVoxelCount())); - } - { - // Set and dilate a single voxel at each of the eight corners of a leaf node. - for (int i = 0; i < 8; ++i) { - tree->clear(); - - openvdb::Coord xyz( - i & 1 ? leafDim - 1 : 0, - i & 2 ? leafDim - 1 : 0, - i & 4 ? leafDim - 1 : 0); - tree->setValue(xyz, 1.0); - CPPUNIT_ASSERT_EQUAL(1, int(tree->activeVoxelCount())); - - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(7, int(tree->activeVoxelCount())); - - openvdb::tools::erodeVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(1, int(tree->activeVoxelCount())); - } - } - { - // Set three active voxels and dilate and erode - tree->clear(); - tree->setValue(Coord(0), 1.0); - tree->setValue(Coord( 1, 0, 0), 1.0); - tree->setValue(Coord(-1, 0, 0), 1.0); - CPPUNIT_ASSERT_EQUAL(3, int(tree->activeVoxelCount())); - - openvdb::tools::dilateVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(17, int(tree->activeVoxelCount())); - - openvdb::tools::erodeVoxels(*tree); - CPPUNIT_ASSERT_EQUAL(3, int(tree->activeVoxelCount())); - } - { - struct Info { - void test(TreeType::Ptr aTree) { - CPPUNIT_ASSERT_EQUAL(activeVoxelCount, int(aTree->activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(leafCount, int(aTree->leafCount())); - CPPUNIT_ASSERT_EQUAL(nonLeafCount, int(aTree->nonLeafCount())); - } - int activeVoxelCount, leafCount, nonLeafCount; - }; - Info iterInfo[12] = { - { 0, 0, 1 },//an empty tree only contains a root node - { 1, 1, 3 }, - { 7, 1, 3 }, - { 25, 1, 3 }, - { 63, 1, 3 }, - { 129, 4, 3 }, - { 231, 7, 9 }, - { 377, 7, 9 }, - { 575, 7, 9 }, - { 833, 10, 9 }, - { 1159, 16, 9 }, - { 1561, 19, 15 }, - }; - - // Perform repeated dilations, starting with a single voxel. - tree->clear(); - iterInfo[0].test(tree); - - tree->setValue(Coord(leafDim >> 1), 1.0); - iterInfo[1].test(tree); - - for (int i = 2; i < 12; ++i) { - openvdb::tools::dilateVoxels(*tree); - iterInfo[i].test(tree); - } - for (int i = 10; i >= 0; --i) { - openvdb::tools::erodeVoxels(*tree); - iterInfo[i].test(tree); - } - - // Now try it using the resursive calls - for (int i = 2; i < 12; ++i) { - tree->clear(); - tree->setValue(Coord(leafDim >> 1), 1.0); - openvdb::tools::dilateVoxels(*tree, i-1); - iterInfo[i].test(tree); - } - for (int i = 10; i >= 0; --i) { - tree->clear(); - tree->setValue(Coord(leafDim >> 1), 1.0); - openvdb::tools::dilateVoxels(*tree, 10); - openvdb::tools::erodeVoxels(*tree, 11-i); - iterInfo[i].test(tree); - } - } - - {// erode a narrow band of a sphere - typedef openvdb::Grid GridType; - GridType grid(tree->background()); - unittest_util::makeSphere(/*dim=*/openvdb::Coord(64, 64, 64), - /*center=*/openvdb::Vec3f(0, 0, 0), - /*radius=*/20, grid, /*dx=*/1.0f, - unittest_util::SPHERE_DENSE_NARROW_BAND); - const openvdb::Index64 count = grid.tree().activeVoxelCount(); - openvdb::tools::erodeVoxels(grid.tree()); - CPPUNIT_ASSERT(grid.tree().activeVoxelCount() < count); - } - - {// erode a fog volume of a sphere - typedef openvdb::Grid GridType; - GridType grid(tree->background()); - unittest_util::makeSphere(/*dim=*/openvdb::Coord(64, 64, 64), - /*center=*/openvdb::Vec3f(0, 0, 0), - /*radius=*/20, grid, /*dx=*/1.0f, - unittest_util::SPHERE_DENSE_NARROW_BAND); - openvdb::tools::sdfToFogVolume(grid); - const openvdb::Index64 count = grid.tree().activeVoxelCount(); - openvdb::tools::erodeVoxels(grid.tree()); - CPPUNIT_ASSERT(grid.tree().activeVoxelCount() < count); - } - - {//erode6 - for (int x=0; x<8; ++x) { - for (int y=0; y<8; ++y) { - for (int z=0; z<8; ++z) { - tree->clear(); - const openvdb::Coord ijk(x,y,z); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree->activeVoxelCount()); - tree->setValue(ijk, 1.0f); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - CPPUNIT_ASSERT(tree->isValueOn(ijk)); - openvdb::tools::dilateVoxels(*tree, 1, openvdb::tools::NN_FACE); - CPPUNIT_ASSERT_EQUAL(Index64(1 + 6), tree->activeVoxelCount()); - openvdb::tools::erodeVoxels( *tree, 1, openvdb::tools::NN_FACE); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - CPPUNIT_ASSERT(tree->isValueOn(ijk)); - } - } - } - } - /* Not completed yet - {//erode18 - //for (int x=0; x<8; ++x) { - //for (int y=0; y<8; ++y) { - //for (int z=0; z<8; ++z) { - int x=3, y=3, z=3; - const openvdb::Coord ijk(x,y,z); - std::cerr << ijk; - tree->clear(); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree->activeVoxelCount()); - tree->setValue(ijk, 1.0f); - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - CPPUNIT_ASSERT(tree->isValueOn(ijk)); - openvdb::tools::dilateVoxels(*tree, 1, openvdb::tools::NN_FACE_EDGE); - std::cerr << " dilated to " << tree->activeVoxelCount(); - CPPUNIT_ASSERT_EQUAL(Index64(1 + 6 + 12), tree->activeVoxelCount()); - openvdb::tools::erodeVoxels( *tree, 1, openvdb::tools::NN_FACE_EDGE); - std::cerr << ", eroded to " << tree->activeVoxelCount() << std::endl; - CPPUNIT_ASSERT_EQUAL(Index64(1), tree->activeVoxelCount()); - CPPUNIT_ASSERT(tree->isValueOn(ijk)); - // } - //} - //} - } - - {//erode26 - tree->clear(); - tree->setValue(openvdb::Coord(3,4,5), 1.0f); - openvdb::tools::dilateVoxels(*tree, 12, openvdb::tools::NN_FACE_EDGE_VERTEX); - openvdb::tools::erodeVoxels( *tree, 12, openvdb::tools::NN_FACE_EDGE_VERTEX); - CPPUNIT_ASSERT_EQUAL(1, int(tree->activeVoxelCount())); - CPPUNIT_ASSERT(tree->isValueOn(openvdb::Coord(3,4,5))); - } - */ -} - - -void -TestTools::testActivate() -{ - using namespace openvdb; - - const Vec3s background(0.0, -1.0, 1.0), foreground(42.0); - - Vec3STree tree(background); - - const CoordBBox bbox1(Coord(-200), Coord(-181)), bbox2(Coord(51), Coord(373)); - - // Set some non-background active voxels. - tree.fill(bbox1, Vec3s(0.0), /*active=*/true); - - // Mark some background voxels as active. - tree.fill(bbox2, background, /*active=*/true); - CPPUNIT_ASSERT_EQUAL(bbox2.volume() + bbox1.volume(), tree.activeVoxelCount()); - - // Deactivate all voxels with the background value. - tools::deactivate(tree, background, /*tolerance=*/Vec3s(1.0e-6f)); - // Verify that there are no longer any active voxels with the background value. - CPPUNIT_ASSERT_EQUAL(bbox1.volume(), tree.activeVoxelCount()); - - // Set some voxels to the foreground value but leave them inactive. - tree.fill(bbox2, foreground, /*active=*/false); - // Verify that there are no active voxels with the background value. - CPPUNIT_ASSERT_EQUAL(bbox1.volume(), tree.activeVoxelCount()); - - // Activate all voxels with the foreground value. - tools::activate(tree, foreground); - // Verify that the expected number of voxels are active. - CPPUNIT_ASSERT_EQUAL(bbox1.volume() + bbox2.volume(), tree.activeVoxelCount()); -} - - -void -TestTools::testFilter() -{ - openvdb::FloatGrid::Ptr referenceGrid = openvdb::FloatGrid::create(/*background=*/5.0); - - const openvdb::Coord dim(40); - const openvdb::Vec3f center(25.0f, 20.0f, 20.0f); - const float radius = 10.0f; - unittest_util::makeSphere( - dim, center, radius, *referenceGrid, unittest_util::SPHERE_DENSE); - const openvdb::FloatTree& sphere = referenceGrid->tree(); - - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(sphere.activeVoxelCount())); - openvdb::Coord xyz; - - {// test Filter::offsetFilter - openvdb::FloatGrid::Ptr grid = referenceGrid->deepCopy(); - openvdb::FloatTree& tree = grid->tree(); - openvdb::tools::Filter filter(*grid); - const float offset = 2.34f; - filter.setGrainSize(0);//i.e. disable threading - filter.offset(offset); - for (int x=0; x0.0001f) std::cerr << " failed at " << xyz << std::endl; - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0f, delta, /*tolerance=*/0.0001); - } - } - } - filter.setGrainSize(1);//i.e. enable threading - filter.offset(-offset);//default is multi-threaded - for (int x=0; x0.0001f) std::cerr << " failed at " << xyz << std::endl; - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0f, delta, /*tolerance=*/0.0001); - } - } - } - //std::cerr << "Successfully completed TestTools::testFilter offset test" << std::endl; - } - {// test Filter::median - openvdb::FloatGrid::Ptr filteredGrid = referenceGrid->deepCopy(); - openvdb::FloatTree& filteredTree = filteredGrid->tree(); - const int width = 2; - openvdb::math::DenseStencil stencil(*referenceGrid, width); - openvdb::tools::Filter filter(*filteredGrid); - filter.median(width, /*interations=*/1); - std::vector tmp; - for (int x=0; xdeepCopy(); - openvdb::FloatTree& filteredTree = filteredGrid->tree(); - const int width = 2; - openvdb::math::DenseStencil stencil(*referenceGrid, width); - openvdb::tools::Filter filter(*filteredGrid); - filter.mean(width, /*interations=*/1); - for (int x=0; x(radius, center, voxelSize, width); - - /// Also test ultra slow makeSphere in unittest/util.h - openvdb::FloatGrid::Ptr grid2 = openvdb::createLevelSet(voxelSize, width); - unittest_util::makeSphere( - openvdb::Coord(dim), center, radius, *grid2, unittest_util::SPHERE_SPARSE_NARROW_BAND); - - const float outside = grid1->background(), inside = -outside; - for (int i=0; itree().getValue(openvdb::Coord(i,j,k)); - const float val2 = grid2->tree().getValue(openvdb::Coord(i,j,k)); - if (dist > outside) { - CPPUNIT_ASSERT_DOUBLES_EQUAL( outside, val1, 0.0001); - CPPUNIT_ASSERT_DOUBLES_EQUAL( outside, val2, 0.0001); - } else if (dist < inside) { - CPPUNIT_ASSERT_DOUBLES_EQUAL( inside, val1, 0.0001); - CPPUNIT_ASSERT_DOUBLES_EQUAL( inside, val2, 0.0001); - } else { - CPPUNIT_ASSERT_DOUBLES_EQUAL( dist, val1, 0.0001); - CPPUNIT_ASSERT_DOUBLES_EQUAL( dist, val2, 0.0001); - } - } - } - } - - CPPUNIT_ASSERT_EQUAL(grid1->activeVoxelCount(), grid2->activeVoxelCount()); -} - -void -TestTools::testLevelSetAdvect() -{ - // Uncomment sections below to run this (time-consuming) test - /* - const int dim = 64;//256 - const openvdb::Vec3f center(0.35f, 0.35f, 0.35f); - const float radius = 0.15f, voxelSize = 1.0f/(dim-1); - - typedef openvdb::FloatGrid GridT; - typedef openvdb::Vec3fGrid VectT; - - */ - /* - {//test tracker - GridT::Ptr grid = openvdb::tools::createLevelSetSphere(radius, center, voxelSize); - typedef openvdb::tools::LevelSetTracker TrackerT; - TrackerT tracker(*grid); - tracker.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - tracker.setTemporalScheme(openvdb::math::TVD_RK1); - - FrameWriter fw(dim, grid); fw("Tracker",0, 0); - //for (float t = 0, dt = 0.005f; !grid->empty() && t < 3.0f; t += dt) { - // fw("Enright", t + dt, advect.advect(t, t + dt)); - //} - for (float t = 0, dt = 0.5f; !grid->empty() && t < 1.0f; t += dt) { - tracker.track(); - fw("Tracker", 0, 0); - } - } - */ - /* - {//test EnrightField - GridT::Ptr grid = openvdb::tools::createLevelSetSphere(radius, center, voxelSize); - typedef openvdb::tools::EnrightField FieldT; - FieldT field; - - typedef openvdb::tools::LevelSetAdvection AdvectT; - AdvectT advect(*grid, field); - advect.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - advect.setTemporalScheme(openvdb::math::TVD_RK2); - advect.setTrackerSpatialScheme(openvdb::math::HJWENO5_BIAS); - advect.setTrackerTemporalScheme(openvdb::math::TVD_RK1); - - FrameWriter fw(dim, grid); fw("Enright",0, 0); - //for (float t = 0, dt = 0.005f; !grid->empty() && t < 3.0f; t += dt) { - // fw("Enright", t + dt, advect.advect(t, t + dt)); - //} - for (float t = 0, dt = 0.5f; !grid->empty() && t < 1.0f; t += dt) { - fw("Enright", t + dt, advect.advect(t, t + dt)); - } - } - */ - /* - {// test DiscreteGrid - Aligned - GridT::Ptr grid = openvdb::tools::createLevelSetSphere(radius, center, voxelSize); - VectT vect(openvdb::Vec3f(1,0,0)); - typedef openvdb::tools::DiscreteField FieldT; - FieldT field(vect); - typedef openvdb::tools::LevelSetAdvection AdvectT; - AdvectT advect(*grid, field); - advect.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - advect.setTemporalScheme(openvdb::math::TVD_RK2); - - FrameWriter fw(dim, grid); fw("Aligned",0, 0); - //for (float t = 0, dt = 0.005f; !grid->empty() && t < 3.0f; t += dt) { - // fw("Aligned", t + dt, advect.advect(t, t + dt)); - //} - for (float t = 0, dt = 0.5f; !grid->empty() && t < 1.0f; t += dt) { - fw("Aligned", t + dt, advect.advect(t, t + dt)); - } - } - */ - /* - {// test DiscreteGrid - Transformed - GridT::Ptr grid = openvdb::tools::createLevelSetSphere(radius, center, voxelSize); - VectT vect(openvdb::Vec3f(0,0,0)); - VectT::Accessor acc = vect.getAccessor(); - for (openvdb::Coord ijk(0); ijk[0] FieldT; - FieldT field(vect); - typedef openvdb::tools::LevelSetAdvection AdvectT; - AdvectT advect(*grid, field); - advect.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - advect.setTemporalScheme(openvdb::math::TVD_RK2); - - FrameWriter fw(dim, grid); fw("Xformed",0, 0); - //for (float t = 0, dt = 0.005f; !grid->empty() && t < 3.0f; t += dt) { - // fw("Xformed", t + dt, advect.advect(t, t + dt)); - //} - for (float t = 0, dt = 0.5f; !grid->empty() && t < 1.0f; t += dt) { - fw("Xformed", t + dt, advect.advect(t, t + dt)); - } - } - */ -}//testLevelSetAdvect - - -//////////////////////////////////////// - -void -TestTools::testLevelSetMorph() -{ - typedef openvdb::FloatGrid GridT; - {//test morphing overlapping but aligned spheres - const int dim = 64; - const openvdb::Vec3f C1(0.35f, 0.35f, 0.35f), C2(0.4f, 0.4f, 0.4f); - const float radius = 0.15f, voxelSize = 1.0f/(dim-1); - - GridT::Ptr source = openvdb::tools::createLevelSetSphere(radius, C1, voxelSize); - GridT::Ptr target = openvdb::tools::createLevelSetSphere(radius, C2, voxelSize); - - typedef openvdb::tools::LevelSetMorphing MorphT; - MorphT morph(*source, *target); - morph.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTemporalScheme(openvdb::math::TVD_RK3); - morph.setTrackerSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTrackerTemporalScheme(openvdb::math::TVD_RK2); - - const std::string name("SphereToSphere"); - //FrameWriter fw(dim, source); - //fw(name, 0.0f, 0); - //util::CpuTimer timer; - const float tMax = 0.05f/voxelSize; - //std::cerr << "\nt-max = " << tMax << std::endl; - //timer.start("\nMorphing"); - for (float t = 0, dt = 0.1f; !source->empty() && t < tMax; t += dt) { - morph.advect(t, t + dt); - //fw(name, t + dt, morph.advect(t, t + dt)); - } - // timer.stop(); - - const float invDx = 1.0f/voxelSize; - openvdb::math::Stats s; - for (GridT::ValueOnCIter it = source->tree().cbeginValueOn(); it; ++it) { - s.add( invDx*(*it - target->tree().getValue(it.getCoord())) ); - } - for (GridT::ValueOnCIter it = target->tree().cbeginValueOn(); it; ++it) { - s.add( invDx*(*it - target->tree().getValue(it.getCoord())) ); - } - //s.print("Morph"); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, s.min(), 0.50); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, s.max(), 0.50); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, s.avg(), 0.02); - /* - openvdb::math::Histogram h(s, 30); - for (GridT::ValueOnCIter it = source->tree().cbeginValueOn(); it; ++it) { - h.add( invDx*(*it - target->tree().getValue(it.getCoord())) ); - } - for (GridT::ValueOnCIter it = target->tree().cbeginValueOn(); it; ++it) { - h.add( invDx*(*it - target->tree().getValue(it.getCoord())) ); - } - h.print("Morph"); - */ - } - /* - // Uncomment sections below to run this (very time-consuming) test - {//test morphing between the bunny and the buddha models loaded from files - util::CpuTimer timer; - openvdb::initialize();//required whenever I/O of OpenVDB files is performed! - openvdb::io::File sourceFile("/usr/pic1/Data/OpenVDB/LevelSetModels/bunny.vdb"); - sourceFile.open(); - GridT::Ptr source = openvdb::gridPtrCast(sourceFile.getGrids()->at(0)); - - openvdb::io::File targetFile("/usr/pic1/Data/OpenVDB/LevelSetModels/buddha.vdb"); - targetFile.open(); - GridT::Ptr target = openvdb::gridPtrCast(targetFile.getGrids()->at(0)); - - typedef openvdb::tools::LevelSetMorphing MorphT; - MorphT morph(*source, *target); - morph.setSpatialScheme(openvdb::math::FIRST_BIAS); - //morph.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTemporalScheme(openvdb::math::TVD_RK2); - morph.setTrackerSpatialScheme(openvdb::math::FIRST_BIAS); - //morph.setTrackerSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTrackerTemporalScheme(openvdb::math::TVD_RK2); - - const std::string name("Bunny2Buddha"); - FrameWriter fw(1, source); - fw(name, 0.0f, 0); - for (float t = 0, dt = 1.0f; !source->empty() && t < 300.0f; t += dt) { - timer.start("Morphing"); - const int cflCount = morph.advect(t, t + dt); - timer.stop(); - fw(name, t + dt, cflCount); - } - } - */ - /* - // Uncomment sections below to run this (very time-consuming) test - {//test morphing between the dragon and the teapot models loaded from files - util::CpuTimer timer; - openvdb::initialize();//required whenever I/O of OpenVDB files is performed! - openvdb::io::File sourceFile("/usr/pic1/Data/OpenVDB/LevelSetModels/dragon.vdb"); - sourceFile.open(); - GridT::Ptr source = openvdb::gridPtrCast(sourceFile.getGrids()->at(0)); - - openvdb::io::File targetFile("/usr/pic1/Data/OpenVDB/LevelSetModels/utahteapot.vdb"); - targetFile.open(); - GridT::Ptr target = openvdb::gridPtrCast(targetFile.getGrids()->at(0)); - - typedef openvdb::tools::LevelSetMorphing MorphT; - MorphT morph(*source, *target); - morph.setSpatialScheme(openvdb::math::FIRST_BIAS); - //morph.setSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTemporalScheme(openvdb::math::TVD_RK2); - //morph.setTrackerSpatialScheme(openvdb::math::HJWENO5_BIAS); - morph.setTrackerSpatialScheme(openvdb::math::FIRST_BIAS); - morph.setTrackerTemporalScheme(openvdb::math::TVD_RK2); - - const std::string name("Dragon2Teapot"); - FrameWriter fw(5, source); - fw(name, 0.0f, 0); - for (float t = 0, dt = 0.4f; !source->empty() && t < 110.0f; t += dt) { - timer.start("Morphing"); - const int cflCount = morph.advect(t, t + dt); - timer.stop(); - fw(name, t + dt, cflCount); - } - } - - */ -}//testLevelSetMorph - -//////////////////////////////////////// - -void -TestTools::testLevelSetMeasure() -{ - const double percentage = 0.1/100.0;//i.e. 0.1% - typedef openvdb::FloatGrid GridT; - const int dim = 256; - openvdb::Real a, v, c, area, volume, curv; - - // First sphere - openvdb::Vec3f C(0.35f, 0.35f, 0.35f); - openvdb::Real r = 0.15, voxelSize = 1.0/(dim-1); - const openvdb::Real Pi = boost::math::constants::pi(); - GridT::Ptr sphere = openvdb::tools::createLevelSetSphere( - float(r), C, float(voxelSize)); - - typedef openvdb::tools::LevelSetMeasure MeasureT; - MeasureT m(*sphere); - - /// Test area and volume of sphere in world units - m.measure(a, v); - area = 4*Pi*r*r; - volume = 4.0/3.0*Pi*r*r*r; - //std::cerr << "\nArea of sphere = " << area << " " << a << std::endl; - //std::cerr << "\nVolume of sphere = " << volume << " " << v << std::endl; - // Test accuracy of computed measures to within 0.1% of the exact measure. - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, a, percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume, v, percentage*volume); - - // Test all measures of sphere in world units - m.measure(a, v, c); - area = 4*Pi*r*r; - volume = 4.0/3.0*Pi*r*r*r; - curv = 1.0/r; - //std::cerr << "\nArea of sphere = " << area << " " << a << std::endl; - //std::cerr << "Volume of sphere = " << volume << " " << v << std::endl; - //std::cerr << "Avg mean curvature of sphere = " << curv << " " << c << std::endl; - // Test accuracy of computed measures to within 0.1% of the exact measure. - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, a, percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume, v, percentage*volume); - CPPUNIT_ASSERT_DOUBLES_EQUAL(curv, c, percentage*curv); - - // Test all measures of sphere in index units - m.measure(a, v, c, false); - r /= voxelSize; - area = 4*Pi*r*r; - volume = 4.0/3.0*Pi*r*r*r; - curv = 1.0/r; - //std::cerr << "\nArea of sphere = " << area << " " << a << std::endl; - //std::cerr << "Volume of sphere = " << volume << " " << v << std::endl; - //std::cerr << "Avg mean curvature of sphere = " << curv << " " << c << std::endl; - // Test accuracy of computed measures to within 0.1% of the exact measure. - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, a, percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume, v, percentage*volume); - CPPUNIT_ASSERT_DOUBLES_EQUAL(curv, c, percentage*curv); - - // Second sphere - C = openvdb::Vec3f(5.4f, 6.4f, 8.4f); - r = 0.57f; - sphere = openvdb::tools::createLevelSetSphere(float(r), C, float(voxelSize)); - m.reinit(*sphere); - - // Test all measures of sphere in world units - m.measure(a, v, c); - area = 4*Pi*r*r; - volume = 4.0/3.0*Pi*r*r*r; - curv = 1.0/r; - //std::cerr << "\nArea of sphere = " << area << " " << a << std::endl; - //std::cerr << "Volume of sphere = " << volume << " " << v << std::endl; - //std::cerr << "Avg mean curvature of sphere = " << curv << " " << c << std::endl; - // Test accuracy of computed measures to within 0.1% of the exact measure. - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, a, percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume, v, percentage*volume); - CPPUNIT_ASSERT_DOUBLES_EQUAL(curv, c, percentage*curv); - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, openvdb::tools::levelSetArea(*sphere), percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume,openvdb::tools::levelSetVolume(*sphere),percentage*volume); - - // Test all measures of sphere in index units - m.measure(a, v, c, false); - r /= voxelSize; - area = 4*Pi*r*r; - volume = 4.0/3.0*Pi*r*r*r; - curv = 1.0/r; - //std::cerr << "\nArea of sphere = " << area << " " << a << std::endl; - //std::cerr << "Volume of sphere = " << volume << " " << v << std::endl; - //std::cerr << "Avg mean curvature of sphere = " << curv << " " << c << std::endl; - // Test accuracy of computed measures to within 0.1% of the exact measure. - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, a, percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume, v, percentage*volume); - CPPUNIT_ASSERT_DOUBLES_EQUAL(curv, c, percentage*curv); - CPPUNIT_ASSERT_DOUBLES_EQUAL(area, openvdb::tools::levelSetArea(*sphere,false), - percentage*area); - CPPUNIT_ASSERT_DOUBLES_EQUAL(volume,openvdb::tools::levelSetVolume(*sphere,false), - percentage*volume); - - // Read level set from file - /* - util::CpuTimer timer; - openvdb::initialize();//required whenever I/O of OpenVDB files is performed! - openvdb::io::File sourceFile("/usr/pic1/Data/OpenVDB/LevelSetModels/venusstatue.vdb"); - sourceFile.open(); - GridT::Ptr model = openvdb::gridPtrCast(sourceFile.getGrids()->at(0)); - m.reinit(*model); - - //m.setGrainSize(1); - timer.start("\nParallel measure of area and volume"); - m.measure(a, v, false); - timer.stop(); - std::cerr << "Model: area = " << a << ", volume = " << v << std::endl; - - timer.start("\nParallel measure of area, volume and curvature"); - m.measure(a, v, c, false); - timer.stop(); - std::cerr << "Model: area = " << a << ", volume = " << v - << ", average curvature = " << c << std::endl; - - m.setGrainSize(0); - timer.start("\nSerial measure of area and volume"); - m.measure(a, v, false); - timer.stop(); - std::cerr << "Model: area = " << a << ", volume = " << v << std::endl; - - timer.start("\nSerial measure of area, volume and curvature"); - m.measure(a, v, c, false); - timer.stop(); - std::cerr << "Model: area = " << a << ", volume = " << v - << ", average curvature = " << c << std::endl; - */ -}//testLevelSetMeasure - -void -TestTools::testMagnitude() -{ - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(/*background=*/5.0); - openvdb::FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim,center,radius,*grid, - unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - openvdb::VectorGrid::Ptr gradGrid = openvdb::tools::gradient(*grid); - CPPUNIT_ASSERT_EQUAL(int(tree.activeVoxelCount()), int(gradGrid->activeVoxelCount())); - - openvdb::FloatGrid::Ptr mag = openvdb::tools::magnitude(*gradGrid); - CPPUNIT_ASSERT_EQUAL(int(tree.activeVoxelCount()), int(mag->activeVoxelCount())); - - openvdb::FloatGrid::ConstAccessor accessor = mag->getConstAccessor(); - - openvdb::Coord xyz(35,30,30); - float v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, v, 0.01); - - xyz.reset(35,10,40); - v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, v, 0.01); -} - - -void -TestTools::testMaskedMagnitude() -{ - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(/*background=*/5.0); - openvdb::FloatTree& tree = grid->tree(); - CPPUNIT_ASSERT(tree.empty()); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=0.0f; - unittest_util::makeSphere(dim,center,radius,*grid, - unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT(!tree.empty()); - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - - openvdb::VectorGrid::Ptr gradGrid = openvdb::tools::gradient(*grid); - CPPUNIT_ASSERT_EQUAL(int(tree.activeVoxelCount()), int(gradGrid->activeVoxelCount())); - - - // create a masking grid - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - openvdb::BoolGrid::Ptr maskGrid = openvdb::BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - // compute the magnitude in masked region - openvdb::FloatGrid::Ptr mag = openvdb::tools::magnitude(*gradGrid, *maskGrid); - - openvdb::FloatGrid::ConstAccessor accessor = mag->getConstAccessor(); - - // test in the masked region - openvdb::Coord xyz(35,30,30); - CPPUNIT_ASSERT(maskbbox.isInside(xyz)); - float v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, v, 0.01); - - // test outside the masked region - xyz.reset(35,10,40); - CPPUNIT_ASSERT(!maskbbox.isInside(xyz)); - v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, v, 0.01); -} - - -void -TestTools::testNormalize() -{ - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(5.0); - openvdb::FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=10.0f; - unittest_util::makeSphere( - dim,center,radius,*grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - openvdb::Coord xyz(10, 20, 30); - - openvdb::VectorGrid::Ptr grad = openvdb::tools::gradient(*grid); - - typedef openvdb::VectorGrid::ValueType Vec3Type; - - typedef openvdb::VectorGrid::ValueOnIter ValueIter; - - struct Local { - static inline Vec3Type op(const Vec3Type &x) { return x * 2.0f; } - static inline void visit(const ValueIter& it) { it.setValue(op(*it)); } - }; - - openvdb::tools::foreach(grad->beginValueOn(), Local::visit, true); - - openvdb::VectorGrid::ConstAccessor accessor = grad->getConstAccessor(); - - xyz = openvdb::Coord(35,10,40); - Vec3Type v = accessor.getValue(xyz); - //std::cerr << "\nPassed testNormalize(" << xyz << ")=" << v.length() << std::endl; - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0,v.length(),0.001); - openvdb::VectorGrid::Ptr norm = openvdb::tools::normalize(*grad); - - accessor = norm->getConstAccessor(); - v = accessor.getValue(xyz); - //std::cerr << "\nPassed testNormalize(" << xyz << ")=" << v.length() << std::endl; - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, v.length(), 0.0001); -} - - -void -TestTools::testMaskedNormalize() -{ - openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(5.0); - openvdb::FloatTree& tree = grid->tree(); - - const openvdb::Coord dim(64,64,64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius=10.0f; - unittest_util::makeSphere( - dim,center,radius,*grid, unittest_util::SPHERE_DENSE); - - CPPUNIT_ASSERT_EQUAL(dim[0]*dim[1]*dim[2], int(tree.activeVoxelCount())); - openvdb::Coord xyz(10, 20, 30); - - openvdb::VectorGrid::Ptr grad = openvdb::tools::gradient(*grid); - - typedef openvdb::VectorGrid::ValueType Vec3Type; - - typedef openvdb::VectorGrid::ValueOnIter ValueIter; - - struct Local { - static inline Vec3Type op(const Vec3Type &x) { return x * 2.0f; } - static inline void visit(const ValueIter& it) { it.setValue(op(*it)); } - }; - - openvdb::tools::foreach(grad->beginValueOn(), Local::visit, true); - - openvdb::VectorGrid::ConstAccessor accessor = grad->getConstAccessor(); - - xyz = openvdb::Coord(35,10,40); - Vec3Type v = accessor.getValue(xyz); - - // create a masking grid - - const openvdb::CoordBBox maskbbox(openvdb::Coord(35, 30, 30), openvdb::Coord(41, 41, 41)); - openvdb::BoolGrid::Ptr maskGrid = openvdb::BoolGrid::create(false); - maskGrid->fill(maskbbox, true/*value*/, true/*activate*/); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0,v.length(),0.001); - - // compute the normalized valued in the masked region - openvdb::VectorGrid::Ptr norm = openvdb::tools::normalize(*grad, *maskGrid); - - accessor = norm->getConstAccessor(); - { // outside the masked region - CPPUNIT_ASSERT(!maskbbox.isInside(xyz)); - v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, v.length(), 0.0001); - } - { // inside the masked region - xyz.reset(35, 30, 30); - v = accessor.getValue(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, v.length(), 0.0001); - } -} - -//////////////////////////////////////// - - -void -TestTools::testPointAdvect() -{ - { - // Setup: Advect a number of points in a uniform velocity field (1,1,1). - // over a time dt=1 with each of the 4 different advection schemes. - // Points initialized at latice points. - // - // Uses: FloatTree (velocity), collocated sampling, advection - // - // Expected: All advection schemes will have the same result. Each point will - // be advanced to a new latice point. The i-th point will be at (i+1,i+1,i+1) - // - - const size_t numPoints = 2000000; - - // create a uniform velocity field in SINGLE PRECISION - const openvdb::Vec3f velocityBackground(1, 1, 1); - openvdb::Vec3fGrid::Ptr velocityGrid = openvdb::Vec3fGrid::create(velocityBackground); - - // using all the default template arguments - openvdb::tools::PointAdvect<> advectionTool(*velocityGrid); - - // create points - std::vector pointList(numPoints); /// larger than the tbb chunk size - for (size_t i = 0; i < numPoints; i++) { - pointList[i] = openvdb::Vec3f(float(i), float(i), float(i)); - } - - for (unsigned int order = 1; order < 5; ++order) { - // check all four time integrations schemes - // construct an advection tool. By default the number of cpt iterations is zero - advectionTool.setIntegrationOrder(order); - advectionTool.advect(pointList, /*dt=*/1.0, /*iterations=*/1); - - // check locations - for (size_t i = 0; i < numPoints; i++) { - openvdb::Vec3f expected(float(i + 1), float(i + 1), float(i + 1)); - CPPUNIT_ASSERT_EQUAL(expected, pointList[i]); - } - // reset values - for (size_t i = 0; i < numPoints; i++) { - pointList[i] = openvdb::Vec3f(float(i), float(i), float(i)); - } - } - - } - - { - // Setup: Advect a number of points in a uniform velocity field (1,1,1). - // over a time dt=1 with each of the 4 different advection schemes. - // And then project the point location onto the x-y plane - // Points initialized at latice points. - // - // Uses: DoubleTree (velocity), staggered sampling, constraint projection, advection - // - // Expected: All advection schemes will have the same result. Modes 1-4: Each point will - // be advanced to a new latice point and projected to x-y plane. - // The i-th point will be at (i+1,i+1,0). For mode 0 (no advection), i-th point - // will be found at (i, i, 0) - - const size_t numPoints = 4; - - // create a uniform velocity field in DOUBLE PRECISION - const openvdb::Vec3d velocityBackground(1, 1, 1); - openvdb::Vec3dGrid::Ptr velocityGrid = openvdb::Vec3dGrid::create(velocityBackground); - - // create a simple (horizontal) constraint field valid for a - // (-10,10)x(-10,10)x(-10,10) - const openvdb::Vec3d cptBackground(0, 0, 0); - openvdb::Vec3dGrid::Ptr cptGrid = openvdb::Vec3dGrid::create(cptBackground); - openvdb::Vec3dTree& cptTree = cptGrid->tree(); - - // create points - std::vector pointList(numPoints); - for (unsigned int i = 0; i < numPoints; i++) pointList[i] = openvdb::Vec3d(i, i, i); - - // Initialize the constraint field in a [-10,10]x[-10,10]x[-10,10] box - // this test will only work if the points remain in the box - openvdb::Coord ijk(0, 0, 0); - for (int i = -10; i < 11; i++) { - ijk.setX(i); - for (int j = -10; j < 11; j++) { - ijk.setY(j); - for (int k = -10; k < 11; k++) { - ijk.setZ(k); - // set the value as projection onto the x-y plane - cptTree.setValue(ijk, openvdb::Vec3d(i, j, 0)); - } - } - } - - // construct an advection tool. By default the number of cpt iterations is zero - openvdb::tools::ConstrainedPointAdvect, true> constrainedAdvectionTool(*velocityGrid, *cptGrid, 0); - constrainedAdvectionTool.setThreaded(false); - - // change the number of constraint interation from default 0 to 5 - constrainedAdvectionTool.setConstraintIterations(5); - - // test the pure-projection mode (order = 0) - constrainedAdvectionTool.setIntegrationOrder(0); - - // change the number of constraint interation (from 0 to 5) - constrainedAdvectionTool.setConstraintIterations(5); - - constrainedAdvectionTool.advect(pointList, /*dt=*/1.0, /*iterations=*/1); - - // check locations - for (unsigned int i = 0; i < numPoints; i++) { - openvdb::Vec3d expected(i, i, 0); // location (i, i, i) projected on to x-y plane - for (int n=0; n<3; ++n) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected[n], pointList[i][n], /*tolerance=*/1e-6); - } - } - - // reset values - for (unsigned int i = 0; i < numPoints; i++) pointList[i] = openvdb::Vec3d(i, i, i); - - // test all four time integrations schemes - for (unsigned int order = 1; order < 5; ++order) { - - constrainedAdvectionTool.setIntegrationOrder(order); - - constrainedAdvectionTool.advect(pointList, /*dt=*/1.0, /*iterations=*/1); - - // check locations - for (unsigned int i = 0; i < numPoints; i++) { - openvdb::Vec3d expected(i+1, i+1, 0); // location (i,i,i) projected onto x-y plane - for (int n=0; n<3; ++n) { - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected[n], pointList[i][n], /*tolerance=*/1e-6); - } - } - // reset values - for (unsigned int i = 0; i < numPoints; i++) pointList[i] = openvdb::Vec3d(i, i, i); - } - } -} - - -//////////////////////////////////////// - - -namespace { - - struct PointList - { - struct Point { double x,y,z; }; - std::vector list; - openvdb::Index64 size() const { return openvdb::Index64(list.size()); } - void add(const openvdb::Vec3d &p) { Point q={p[0],p[1],p[2]}; list.push_back(q); } - }; -} - - -void -TestTools::testPointScatter() -{ - typedef openvdb::FloatGrid GridType; - const openvdb::Coord dim(64, 64, 64); - const openvdb::Vec3f center(35.0f, 30.0f, 40.0f); - const float radius = 20.0; - typedef boost::mt11213b RandGen; - RandGen mtRand; - - GridType::Ptr grid = GridType::create(/*background=*/2.0); - unittest_util::makeSphere(dim, center, radius, *grid, - unittest_util::SPHERE_DENSE_NARROW_BAND); - - {// test fixed point count scattering - const openvdb::Index64 pointCount = 1000; - PointList points; - openvdb::tools::UniformPointScatter scatter(points, pointCount, mtRand); - scatter.operator()(*grid); - CPPUNIT_ASSERT_EQUAL( pointCount, scatter.getPointCount() ); - CPPUNIT_ASSERT_EQUAL( pointCount, points.size() ); - } - {// test uniform density scattering - const float density = 1.0f;//per volume = per voxel since voxel size = 1 - PointList points; - openvdb::tools::UniformPointScatter scatter(points, density, mtRand); - scatter.operator()(*grid); - CPPUNIT_ASSERT_EQUAL( scatter.getVoxelCount(), scatter.getPointCount() ); - CPPUNIT_ASSERT_EQUAL( scatter.getVoxelCount(), points.size() ); - } - {// test non-uniform density scattering - const float density = 1.0f;//per volume = per voxel since voxel size = 1 - PointList points; - openvdb::tools::NonUniformPointScatter scatter(points, density, mtRand); - scatter.operator()(*grid); - CPPUNIT_ASSERT( scatter.getVoxelCount() < scatter.getPointCount() ); - CPPUNIT_ASSERT_EQUAL( scatter.getPointCount(), points.size() ); - } - {// test dense uniform scattering - const size_t pointsPerVoxel = 8; - PointList points; - openvdb::tools::DenseUniformPointScatter - scatter(points, pointsPerVoxel, mtRand); - scatter.operator()(*grid); - CPPUNIT_ASSERT_EQUAL( scatter.getVoxelCount()*pointsPerVoxel, scatter.getPointCount() ); - CPPUNIT_ASSERT_EQUAL( scatter.getPointCount(), points.size() ); - } -} - - -//////////////////////////////////////// - - -void -TestTools::testFloatApply() -{ - typedef openvdb::FloatTree::ValueOnIter ValueIter; - - struct Local { - static inline float op(float x) { return x * 2.f; } - static inline void visit(const ValueIter& it) { it.setValue(op(*it)); } - }; - - const float background = 1.0; - openvdb::FloatTree tree(background); - - const int MIN = -1000, MAX = 1000, STEP = 50; - openvdb::Coord xyz; - for (int z = MIN; z < MAX; z += STEP) { - xyz.setZ(z); - for (int y = MIN; y < MAX; y += STEP) { - xyz.setY(y); - for (int x = MIN; x < MAX; x += STEP) { - xyz.setX(x); - tree.setValue(xyz, float(x + y + z)); - } - } - } - /// @todo set some tile values - - openvdb::tools::foreach(tree.begin(), Local::visit, /*threaded=*/true); - - float expected = Local::op(background); - //CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, tree.background(), /*tolerance=*/0.0); - //expected = Local::op(-background); - //CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, -tree.background(), /*tolerance=*/0.0); - - for (openvdb::FloatTree::ValueOnCIter it = tree.cbeginValueOn(); it; ++it) { - xyz = it.getCoord(); - expected = Local::op(float(xyz[0] + xyz[1] + xyz[2])); - CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, it.getValue(), /*tolerance=*/0.0); - } -} - - -//////////////////////////////////////// - - -namespace { - -template -struct MatMul { - openvdb::math::Mat3s mat; - MatMul(const openvdb::math::Mat3s& _mat): mat(_mat) {} - openvdb::Vec3s xform(const openvdb::Vec3s& v) const { return mat.transform(v); } - void operator()(const IterT& it) const { it.setValue(xform(*it)); } -}; - -} - - -void -TestTools::testVectorApply() -{ - typedef openvdb::VectorTree::ValueOnIter ValueIter; - - const openvdb::Vec3s background(1, 1, 1); - openvdb::VectorTree tree(background); - - const int MIN = -1000, MAX = 1000, STEP = 80; - openvdb::Coord xyz; - for (int z = MIN; z < MAX; z += STEP) { - xyz.setZ(z); - for (int y = MIN; y < MAX; y += STEP) { - xyz.setY(y); - for (int x = MIN; x < MAX; x += STEP) { - xyz.setX(x); - tree.setValue(xyz, openvdb::Vec3s(float(x), float(y), float(z))); - } - } - } - /// @todo set some tile values - - MatMul op(openvdb::math::Mat3s(1, 2, 3, -1, -2, -3, 3, 2, 1)); - openvdb::tools::foreach(tree.beginValueOn(), op, /*threaded=*/true); - - openvdb::Vec3s expected; - for (openvdb::VectorTree::ValueOnCIter it = tree.cbeginValueOn(); it; ++it) { - xyz = it.getCoord(); - expected = op.xform(openvdb::Vec3s(float(xyz[0]), float(xyz[1]), float(xyz[2]))); - CPPUNIT_ASSERT_EQUAL(expected, it.getValue()); - } -} - - -//////////////////////////////////////// - - -namespace { - -struct AccumSum { - int64_t sum; int joins; - AccumSum(): sum(0), joins(0) {} - void operator()(const openvdb::Int32Tree::ValueOnCIter& it) - { - if (it.isVoxelValue()) sum += *it; - else sum += (*it) * it.getVoxelCount(); - } - void join(AccumSum& other) { sum += other.sum; joins += 1 + other.joins; } -}; - - -struct AccumLeafVoxelCount { - typedef openvdb::tree::LeafManager::LeafRange LeafRange; - openvdb::Index64 count; - AccumLeafVoxelCount(): count(0) {} - void operator()(const LeafRange::Iterator& it) { count += it->onVoxelCount(); } - void join(AccumLeafVoxelCount& other) { count += other.count; } -}; - -} - - -void -TestTools::testAccumulate() -{ - using namespace openvdb; - - const int value = 2; - Int32Tree tree(/*background=*/0); - tree.fill(CoordBBox::createCube(Coord(0), 198), value, /*active=*/true); - - const int64_t expected = tree.activeVoxelCount() * value; - { - AccumSum op; - tools::accumulate(tree.cbeginValueOn(), op, /*threaded=*/false); - CPPUNIT_ASSERT_EQUAL(expected, op.sum); - CPPUNIT_ASSERT_EQUAL(0, op.joins); - } - { - AccumSum op; - tools::accumulate(tree.cbeginValueOn(), op, /*threaded=*/true); - CPPUNIT_ASSERT_EQUAL(expected, op.sum); - } - { - AccumLeafVoxelCount op; - tree::LeafManager mgr(tree); - tools::accumulate(mgr.leafRange().begin(), op, /*threaded=*/true); - CPPUNIT_ASSERT_EQUAL(tree.activeLeafVoxelCount(), op.count); - } -} - - -//////////////////////////////////////// - - -namespace { - -template -struct FloatToVec -{ - typedef typename InIterT::ValueT ValueT; - typedef typename openvdb::tree::ValueAccessor Accessor; - - // Transform a scalar value into a vector value. - static openvdb::Vec3s toVec(const ValueT& v) { return openvdb::Vec3s(v, v*2, v*3); } - - FloatToVec() { numTiles = 0; } - - void operator()(const InIterT& it, Accessor& acc) - { - if (it.isVoxelValue()) { // set a single voxel - acc.setValue(it.getCoord(), toVec(*it)); - } else { // fill an entire tile - numTiles.fetch_and_increment(); - openvdb::CoordBBox bbox; - it.getBoundingBox(bbox); - acc.tree().fill(bbox, toVec(*it)); - } - } - - tbb::atomic numTiles; -}; - -} - - -void -TestTools::testTransformValues() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Vec3s; - - typedef openvdb::tree::Tree4::Type Tree323f; - typedef openvdb::tree::Tree4::Type Tree323v; - - const float background = 1.0; - Tree323f ftree(background); - - const int MIN = -1000, MAX = 1000, STEP = 80; - Coord xyz; - for (int z = MIN; z < MAX; z += STEP) { - xyz.setZ(z); - for (int y = MIN; y < MAX; y += STEP) { - xyz.setY(y); - for (int x = MIN; x < MAX; x += STEP) { - xyz.setX(x); - ftree.setValue(xyz, float(x + y + z)); - } - } - } - // Set some tile values. - ftree.fill(CoordBBox(Coord(1024), Coord(1024 + 8 - 1)), 3 * 1024); // level-1 tile - ftree.fill(CoordBBox(Coord(2048), Coord(2048 + 32 - 1)), 3 * 2048); // level-2 tile - ftree.fill(CoordBBox(Coord(3072), Coord(3072 + 256 - 1)), 3 * 3072); // level-3 tile - - for (int shareOp = 0; shareOp <= 1; ++shareOp) { - FloatToVec op; - Tree323v vtree; - openvdb::tools::transformValues(ftree.cbeginValueOn(), vtree, op, - /*threaded=*/true, shareOp); - - // The tile count is accurate only if the functor is shared. Otherwise, - // it is initialized to zero in the main thread and never changed. - CPPUNIT_ASSERT_EQUAL(shareOp ? 3 : 0, int(op.numTiles)); - - Vec3s expected; - for (Tree323v::ValueOnCIter it = vtree.cbeginValueOn(); it; ++it) { - xyz = it.getCoord(); - expected = op.toVec(float(xyz[0] + xyz[1] + xyz[2])); - CPPUNIT_ASSERT_EQUAL(expected, it.getValue()); - } - // Check values inside the tiles. - CPPUNIT_ASSERT_EQUAL(op.toVec(3 * 1024), vtree.getValue(Coord(1024 + 4))); - CPPUNIT_ASSERT_EQUAL(op.toVec(3 * 2048), vtree.getValue(Coord(2048 + 16))); - CPPUNIT_ASSERT_EQUAL(op.toVec(3 * 3072), vtree.getValue(Coord(3072 + 128))); - } -} - - -//////////////////////////////////////// - - -void -TestTools::testUtil() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Vec3s; - - typedef openvdb::tree::Tree4::Type CharTree; - - // Test boolean operators - CharTree treeA(false), treeB(false); - - treeA.fill(CoordBBox(Coord(-10), Coord(10)), true); - treeA.voxelizeActiveTiles(); - - treeB.fill(CoordBBox(Coord(-10), Coord(10)), true); - treeB.voxelizeActiveTiles(); - - const size_t voxelCountA = treeA.activeVoxelCount(); - const size_t voxelCountB = treeB.activeVoxelCount(); - - CPPUNIT_ASSERT_EQUAL(voxelCountA, voxelCountB); - - CharTree::Ptr tree = openvdb::util::leafTopologyDifference(treeA, treeB); - CPPUNIT_ASSERT(tree->activeVoxelCount() == 0); - - tree = openvdb::util::leafTopologyIntersection(treeA, treeB); - CPPUNIT_ASSERT(tree->activeVoxelCount() == voxelCountA); - - treeA.fill(CoordBBox(Coord(-10), Coord(22)), true); - treeA.voxelizeActiveTiles(); - - const size_t voxelCount = treeA.activeVoxelCount(); - - tree = openvdb::util::leafTopologyDifference(treeA, treeB); - CPPUNIT_ASSERT(tree->activeVoxelCount() == (voxelCount - voxelCountA)); - - tree = openvdb::util::leafTopologyIntersection(treeA, treeB); - CPPUNIT_ASSERT(tree->activeVoxelCount() == voxelCountA); -} - - -//////////////////////////////////////// - - -void -TestTools::testVectorTransformer() -{ - using namespace openvdb; - - Mat4d xform = Mat4d::identity(); - xform.preTranslate(Vec3d(0.1, -2.5, 3)); - xform.preScale(Vec3d(0.5, 1.1, 2)); - xform.preRotate(math::X_AXIS, 30.0 * M_PI / 180.0); - xform.preRotate(math::Y_AXIS, 300.0 * M_PI / 180.0); - - Mat4d invXform = xform.inverse(); - invXform = invXform.transpose(); - - { - // Set some vector values in a grid, then verify that tools::transformVectors() - // transforms them as expected for each VecType. - - const Vec3s refVec0(0, 0, 0), refVec1(1, 0, 0), refVec2(0, 1, 0), refVec3(0, 0, 1); - - Vec3SGrid grid; - Vec3SGrid::Accessor acc = grid.getAccessor(); - -#define resetGrid() \ - { \ - grid.clear(); \ - acc.setValue(Coord(0), refVec0); \ - acc.setValue(Coord(1), refVec1); \ - acc.setValue(Coord(2), refVec2); \ - acc.setValue(Coord(3), refVec3); \ - } - - // Verify that grid values are in world space by default. - CPPUNIT_ASSERT(grid.isInWorldSpace()); - - resetGrid(); - grid.setVectorType(VEC_INVARIANT); - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT(acc.getValue(Coord(0)).eq(refVec0)); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(refVec1)); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(refVec2)); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(refVec3)); - - resetGrid(); - grid.setVectorType(VEC_COVARIANT); - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT(acc.getValue(Coord(0)).eq(invXform.transform3x3(refVec0))); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(invXform.transform3x3(refVec1))); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(invXform.transform3x3(refVec2))); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(invXform.transform3x3(refVec3))); - - resetGrid(); - grid.setVectorType(VEC_COVARIANT_NORMALIZE); - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT_EQUAL(refVec0, acc.getValue(Coord(0))); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(invXform.transform3x3(refVec1).unit())); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(invXform.transform3x3(refVec2).unit())); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(invXform.transform3x3(refVec3).unit())); - - resetGrid(); - grid.setVectorType(VEC_CONTRAVARIANT_RELATIVE); - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT(acc.getValue(Coord(0)).eq(xform.transform3x3(refVec0))); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(xform.transform3x3(refVec1))); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(xform.transform3x3(refVec2))); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(xform.transform3x3(refVec3))); - - resetGrid(); - grid.setVectorType(VEC_CONTRAVARIANT_ABSOLUTE); - /// @todo This doesn't really test the behavior w.r.t. homogeneous coords. - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT(acc.getValue(Coord(0)).eq(xform.transformH(refVec0))); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(xform.transformH(refVec1))); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(xform.transformH(refVec2))); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(xform.transformH(refVec3))); - - // Verify that transformVectors() has no effect on local-space grids. - resetGrid(); - grid.setVectorType(VEC_CONTRAVARIANT_RELATIVE); - grid.setIsInWorldSpace(false); - tools::transformVectors(grid, xform); - CPPUNIT_ASSERT(acc.getValue(Coord(0)).eq(refVec0)); - CPPUNIT_ASSERT(acc.getValue(Coord(1)).eq(refVec1)); - CPPUNIT_ASSERT(acc.getValue(Coord(2)).eq(refVec2)); - CPPUNIT_ASSERT(acc.getValue(Coord(3)).eq(refVec3)); - -#undef resetGrid - } - { - // Verify that transformVectors() operates only on vector-valued grids. - FloatGrid scalarGrid; - CPPUNIT_ASSERT_THROW(tools::transformVectors(scalarGrid, xform), TypeError); - } -} - - -//////////////////////////////////////// - - -// See also TestGrid::testClipping() -void -TestTools::testClipping() -{ - using namespace openvdb; - - FloatGrid cube(0.f); - cube.fill(CoordBBox(Coord(-10), Coord(10)), /*value=*/5.f, /*active=*/true); - - struct Local { - static void validate(const FloatGrid& clipped) - { - const CoordBBox bbox = clipped.evalActiveVoxelBoundingBox(); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.min().y()); - CPPUNIT_ASSERT_EQUAL(-6, bbox.min().z()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().x()); - CPPUNIT_ASSERT_EQUAL(4, bbox.max().y()); - CPPUNIT_ASSERT_EQUAL(6, bbox.max().z()); - CPPUNIT_ASSERT_EQUAL(6 + 6 + 1, int(clipped.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(2, int(clipped.constTree().leafCount())); - - FloatGrid::ConstAccessor acc = clipped.getConstAccessor(); - const float bg = clipped.background(); - Coord xyz; - int &x = xyz[0], &y = xyz[1], &z = xyz[2]; - for (x = -10; x <= 10; ++x) { - for (y = -10; y <= 10; ++y) { - for (z = -10; z <= 10; ++z) { - if (x == 4 && y == 4 && z >= -6 && z <= 6) { - CPPUNIT_ASSERT_EQUAL(5.f, acc.getValue(Coord(4, 4, z))); - } else { - CPPUNIT_ASSERT_EQUAL(bg, acc.getValue(Coord(x, y, z))); - } - } - } - } - } - }; - - { - // Test clipping against a bounding box. - BBoxd clipBox(Vec3d(4.0, 4.0, -6.0), Vec3d(4.9, 4.9, 6.0)); - FloatGrid::Ptr clipped = tools::clip(cube, clipBox); - Local::validate(*clipped); - } - { - // Test clipping against a boolean mask grid. - BoolGrid mask(false); - mask.fill(CoordBBox(Coord(4, 4, -6), Coord(4, 4, 6)), true, true); - FloatGrid::Ptr clipped = tools::clip(cube, mask); - Local::validate(*clipped); - } - { - // Test clipping against a non-boolean mask grid. - Int32Grid mask(0); - mask.fill(CoordBBox(Coord(4, 4, -6), Coord(4, 4, 6)), -5, true); - FloatGrid::Ptr clipped = tools::clip(cube, mask); - Local::validate(*clipped); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTransform.cc b/openvdb_3_0_0_library/unittest/TestTransform.cc deleted file mode 100755 index 96f8407..0000000 --- a/openvdb_3_0_0_library/unittest/TestTransform.cc +++ /dev/null @@ -1,566 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include - - -class TestTransform: public CppUnit::TestCase -{ -public: - virtual void setUp(); - virtual void tearDown(); - - CPPUNIT_TEST_SUITE(TestTransform); - CPPUNIT_TEST(testLinearTransform); - CPPUNIT_TEST(testTransformEquality); - CPPUNIT_TEST(testBackwardCompatibility); - CPPUNIT_TEST(testIsIdentity); - CPPUNIT_TEST(testBoundingBoxes); - CPPUNIT_TEST_SUITE_END(); - - void testLinearTransform(); - void testTransformEquality(); - void testBackwardCompatibility(); - void testIsIdentity(); - void testBoundingBoxes(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTransform); - - -//////////////////////////////////////// - - -void -TestTransform::setUp() -{ - openvdb::math::MapRegistry::clear(); - openvdb::math::AffineMap::registerMap(); - openvdb::math::ScaleMap::registerMap(); - openvdb::math::UniformScaleMap::registerMap(); - openvdb::math::TranslationMap::registerMap(); - openvdb::math::ScaleTranslateMap::registerMap(); - openvdb::math::UniformScaleTranslateMap::registerMap(); -} - - -void -TestTransform::tearDown() -{ - openvdb::math::MapRegistry::clear(); -} - - -////openvdb:://////////////////////////////////// - - -void -TestTransform::testLinearTransform() -{ - using namespace openvdb; - double TOL = 1e-7; - - // Test: Scaling - math::Transform::Ptr t = math::Transform::createLinearTransform(0.5); - - Vec3R voxelSize = t->voxelSize(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[2], TOL); - - CPPUNIT_ASSERT(t->hasUniformScale()); - - // world to index space - Vec3R xyz(-1.0, 2.0, 4.0); - xyz = t->worldToIndex(xyz); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-2.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 4.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 8.0, xyz[2], TOL); - - xyz = Vec3R(-0.7, 2.4, 4.7); - - // cell centered conversion - Coord ijk = t->worldToIndexCellCentered(xyz); - CPPUNIT_ASSERT_EQUAL(Coord(-1, 5, 9), ijk); - - // node centrered conversion - ijk = t->worldToIndexNodeCentered(xyz); - CPPUNIT_ASSERT_EQUAL(Coord(-2, 4, 9), ijk); - - // index to world space - ijk = Coord(4, 2, -8); - xyz = t->indexToWorld(ijk); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 2.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-4.0, xyz[2], TOL); - - // I/O test - { - std::stringstream - ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - t->write(ss); - - t = math::Transform::createLinearTransform(); - - // Since we wrote only a fragment of a VDB file (in particular, we didn't - // write the header), set the file format version number explicitly. - io::setCurrentVersion(ss); - - t->read(ss); - } - - // check map type - CPPUNIT_ASSERT_EQUAL(math::UniformScaleMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[2], TOL); - - ////////// - - // Test: Scale, translation & rotation - t = math::Transform::createLinearTransform(2.0); - - // rotate, 180 deg, (produces a diagonal matrix that can be simplified into a scale map) - // with diagonal -2, 2, -2 - const double PI = std::atan(1.0)*4; - t->preRotate(PI, math::Y_AXIS); - - // this is just a rotation so it will have uniform scale - CPPUNIT_ASSERT(t->hasUniformScale()); - - CPPUNIT_ASSERT_EQUAL(math::ScaleMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - xyz = t->worldToIndex(Vec3R(-2.0, -2.0, -2.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[2], TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[2], TOL); - - // translate - t->postTranslate(Vec3d(1.0, 0.0, 1.0)); - - CPPUNIT_ASSERT_EQUAL(math::ScaleTranslateMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - xyz = t->worldToIndex(Vec3R(-2.0, -2.0, -2.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[2], TOL); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.5, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.5, xyz[2], TOL); - - - // I/O test - { - std::stringstream - ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - t->write(ss); - - t = math::Transform::createLinearTransform(); - - // Since we wrote only a fragment of a VDB file (in particular, we didn't - // write the header), set the file format version number explicitly. - io::setCurrentVersion(ss); - - t->read(ss); - } - - // check map type - CPPUNIT_ASSERT_EQUAL(math::ScaleTranslateMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[2], TOL); - - xyz = t->worldToIndex(Vec3R(-2.0, -2.0, -2.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.5, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.5, xyz[2], TOL); - - // new transform - t = math::Transform::createLinearTransform(1.0); - - // rotate 90 deg - t->preRotate( std::atan(1.0) * 2 , math::Y_AXIS); - - // check map type - CPPUNIT_ASSERT_EQUAL(math::AffineMap::mapType(), t->baseMap()->type()); - - xyz = t->worldToIndex(Vec3R(1.0, 1.0, 1.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[2], TOL); - - // I/O test - { - std::stringstream - ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - t->write(ss); - - t = math::Transform::createLinearTransform(); - - CPPUNIT_ASSERT_EQUAL(math::UniformScaleMap::mapType(), t->baseMap()->type()); - - xyz = t->worldToIndex(Vec3R(1.0, 1.0, 1.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, xyz[2], TOL); - - // Since we wrote only a fragment of a VDB file (in particular, we didn't - // write the header), set the file format version number explicitly. - io::setCurrentVersion(ss); - - t->read(ss); - } - - // check map type - CPPUNIT_ASSERT_EQUAL(math::AffineMap::mapType(), t->baseMap()->type()); - - xyz = t->worldToIndex(Vec3R(1.0, 1.0, 1.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[2], TOL); -} - - -//////////////////////////////////////// - -void -TestTransform::testTransformEquality() -{ - using namespace openvdb; - - // maps created in different ways may be equivalent - math::Transform::Ptr t1 = math::Transform::createLinearTransform(0.5); - math::Mat4d mat = math::Mat4d::identity(); - mat.preScale(math::Vec3d(0.5, 0.5, 0.5)); - math::Transform::Ptr t2 = math::Transform::createLinearTransform(mat); - - CPPUNIT_ASSERT( *t1 == *t2); - - // test that the auto-convert to the simplest form worked - CPPUNIT_ASSERT( t1->mapType() == t2->mapType()); - - - mat.preScale(math::Vec3d(1., 1., .4)); - math::Transform::Ptr t3 = math::Transform::createLinearTransform(mat); - - CPPUNIT_ASSERT( *t1 != *t3); - - // test equality between different but equivalent maps - math::UniformScaleTranslateMap::Ptr ustmap( - new math::UniformScaleTranslateMap(1.0, math::Vec3d(0,0,0))); - math::Transform::Ptr t4( new math::Transform( ustmap) ); - CPPUNIT_ASSERT( t4->baseMap()->isType() ); - math::Transform::Ptr t5( new math::Transform); // constructs with a scale map - CPPUNIT_ASSERT( t5->baseMap()->isType() ); - - CPPUNIT_ASSERT( *t5 == *t4); - - CPPUNIT_ASSERT( t5->mapType() != t4->mapType() ); - - // test inequatlity of two maps of the same type - math::UniformScaleTranslateMap::Ptr ustmap2( - new math::UniformScaleTranslateMap(1.0, math::Vec3d(1,0,0))); - math::Transform::Ptr t6( new math::Transform( ustmap2) ); - CPPUNIT_ASSERT( t6->baseMap()->isType() ); - CPPUNIT_ASSERT( *t6 != *t4); - - // test comparison of linear to nonlinear map - openvdb::BBoxd bbox(math::Vec3d(0), math::Vec3d(100)); - math::Transform::Ptr frustum = math::Transform::createFrustumTransform(bbox, 0.25, 10); - - CPPUNIT_ASSERT( *frustum != *t1 ); - - -} -//////////////////////////////////////// - -void -TestTransform::testBackwardCompatibility() -{ - using namespace openvdb; - double TOL = 1e-7; - - // Register maps - math::MapRegistry::clear(); - math::AffineMap::registerMap(); - math::ScaleMap::registerMap(); - math::TranslationMap::registerMap(); - math::ScaleTranslateMap::registerMap(); - - std::stringstream - ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - - ////////// - - // Construct and write out an old transform that gets converted - // into a ScaleMap on read. - - // First write the old transform type name - writeString(ss, Name("LinearTransform")); - - // Second write the old transform's base class membes. - Coord tmpMin(0), tmpMax(1); - ss.write(reinterpret_cast(&tmpMin), sizeof(Coord::ValueType) * 3); - ss.write(reinterpret_cast(&tmpMax), sizeof(Coord::ValueType) * 3); - - // Last write out the old linear transform's members - math::Mat4d tmpLocalToWorld = math::Mat4d::identity(), - tmpWorldToLocal = math::Mat4d::identity(), - tmpVoxelToLocal = math::Mat4d::identity(), - tmpLocalToVoxel = math::Mat4d::identity(); - - tmpVoxelToLocal.preScale(math::Vec3d(0.5, 0.5, 0.5)); - - tmpLocalToWorld.write(ss); - tmpWorldToLocal.write(ss); - tmpVoxelToLocal.write(ss); - tmpLocalToVoxel.write(ss); - - // Read in the old transform and converting it to the new map based implementation. - - math::Transform::Ptr t = math::Transform::createLinearTransform(1.0); - - t->read(ss); - - // check map type - CPPUNIT_ASSERT_EQUAL(math::UniformScaleMap::mapType(), t->baseMap()->type()); - - Vec3d voxelSize = t->voxelSize(); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, voxelSize[2], TOL); - - Vec3d xyz = t->worldToIndex(Vec3d(-1.0, 2.0, 4.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(-2.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 4.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 8.0, xyz[2], TOL); - - - ////////// - - // Construct and write out an old transform that gets converted - // into a ScaleTranslateMap on read. - - ss.clear(); - writeString(ss, Name("LinearTransform")); - ss.write((char*)&tmpMin, sizeof(Coord::ValueType) * 3); - ss.write((char*)&tmpMax, sizeof(Coord::ValueType) * 3); - tmpLocalToWorld = math::Mat4d::identity(), - tmpWorldToLocal = math::Mat4d::identity(), - tmpVoxelToLocal = math::Mat4d::identity(), - tmpLocalToVoxel = math::Mat4d::identity(); - - tmpVoxelToLocal.preScale(math::Vec3d(2.0, 2.0, 2.0)); - tmpLocalToWorld.setTranslation(math::Vec3d(1.0, 0.0, 1.0)); - - tmpLocalToWorld.write(ss); - tmpWorldToLocal.write(ss); - tmpVoxelToLocal.write(ss); - tmpLocalToVoxel.write(ss); - - // Read in the old transform and converting it to the new map based implementation. - - t = math::Transform::createLinearTransform(); // rest transform - t->read(ss); - - CPPUNIT_ASSERT_EQUAL(math::UniformScaleTranslateMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.0, voxelSize[2], TOL); - - xyz = t->worldToIndex(Vec3d(1.0, 1.0, 1.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, xyz[2], TOL); - - - ////////// - - // Construct and write out an old transform that gets converted - // into a AffineMap on read. - - ss.clear(); - writeString(ss, Name("LinearTransform")); - ss.write((char*)&tmpMin, sizeof(Coord::ValueType) * 3); - ss.write((char*)&tmpMax, sizeof(Coord::ValueType) * 3); - tmpLocalToWorld = math::Mat4d::identity(), - tmpWorldToLocal = math::Mat4d::identity(), - tmpVoxelToLocal = math::Mat4d::identity(), - tmpLocalToVoxel = math::Mat4d::identity(); - - tmpVoxelToLocal.preScale(math::Vec3d(1.0, 1.0, 1.0)); - tmpLocalToWorld.preRotate( math::Y_AXIS, std::atan(1.0) * 2); - - tmpLocalToWorld.write(ss); - tmpWorldToLocal.write(ss); - tmpVoxelToLocal.write(ss); - tmpLocalToVoxel.write(ss); - - // Read in the old transform and converting it to the new map based implementation. - - t = math::Transform::createLinearTransform(); // rest transform - t->read(ss); - - CPPUNIT_ASSERT_EQUAL(math::AffineMap::mapType(), t->baseMap()->type()); - - voxelSize = t->voxelSize(); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, voxelSize[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, voxelSize[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, voxelSize[2], TOL); - - xyz = t->worldToIndex(Vec3d(1.0, 1.0, 1.0)); - - CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, xyz[0], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[1], TOL); - CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, xyz[2], TOL); -} - - -void -TestTransform::testIsIdentity() -{ - using namespace openvdb; - math::Transform::Ptr t = math::Transform::createLinearTransform(1.0); - - CPPUNIT_ASSERT(t->isIdentity()); - - t->preScale(Vec3d(2,2,2)); - - CPPUNIT_ASSERT(!t->isIdentity()); - - t->preScale(Vec3d(0.5,0.5,0.5)); - CPPUNIT_ASSERT(t->isIdentity()); - - BBoxd bbox(math::Vec3d(-5,-5,0), Vec3d(5,5,10)); - math::Transform::Ptr f = math::Transform::createFrustumTransform(bbox, - /*taper*/ 1, - /*depth*/ 1, - /*voxel size*/ 1); - f->preScale(Vec3d(10,10,10)); - - CPPUNIT_ASSERT(f->isIdentity()); - - // rotate by PI/2 - f->postRotate(std::atan(1.0)*2, math::Y_AXIS); - CPPUNIT_ASSERT(!f->isIdentity()); - - f->postRotate(std::atan(1.0)*6, math::Y_AXIS); - CPPUNIT_ASSERT(f->isIdentity()); -} - - -void -TestTransform::testBoundingBoxes() -{ - using namespace openvdb; - - { - math::Transform::ConstPtr t = math::Transform::createLinearTransform(0.5); - - const BBoxd bbox(Vec3d(-8.0), Vec3d(16.0)); - - BBoxd xBBox = t->indexToWorld(bbox); - CPPUNIT_ASSERT_EQUAL(Vec3d(-4.0), xBBox.min()); - CPPUNIT_ASSERT_EQUAL(Vec3d(8.0), xBBox.max()); - - xBBox = t->worldToIndex(xBBox); - CPPUNIT_ASSERT_EQUAL(bbox.min(), xBBox.min()); - CPPUNIT_ASSERT_EQUAL(bbox.max(), xBBox.max()); - } - { - const double PI = std::atan(1.0) * 4.0, SQRT2 = std::sqrt(2.0); - - math::Transform::Ptr t = math::Transform::createLinearTransform(1.0); - t->preRotate(PI / 4.0, math::Z_AXIS); - - const BBoxd bbox(Vec3d(-10.0), Vec3d(10.0)); - - BBoxd xBBox = t->indexToWorld(bbox); // expand in x and y by sqrt(2) - CPPUNIT_ASSERT(Vec3d(-10.0 * SQRT2, -10.0 * SQRT2, -10.0).eq(xBBox.min())); - CPPUNIT_ASSERT(Vec3d(10.0 * SQRT2, 10.0 * SQRT2, 10.0).eq(xBBox.max())); - - xBBox = t->worldToIndex(xBBox); // expand again in x and y by sqrt(2) - CPPUNIT_ASSERT(Vec3d(-20.0, -20.0, -10.0).eq(xBBox.min())); - CPPUNIT_ASSERT(Vec3d(20.0, 20.0, 10.0).eq(xBBox.max())); - } - - /// @todo frustum transform -} - - -//////////////////////////////////////// - - -/// @todo Test the new frustum transform. -/* -void -TestTransform::testNonlinearTransform() -{ - using namespace openvdb; - double TOL = 1e-7; -} -*/ - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTree.cc b/openvdb_3_0_0_library/unittest/TestTree.cc deleted file mode 100755 index d14f0b4..0000000 --- a/openvdb_3_0_0_library/unittest/TestTree.cc +++ /dev/null @@ -1,2800 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include // for remove() -#include -#include -#include -#include -#include -#include -#include // for tools::setValueOnMin(), et al. -#include -#include -#include -#include // for io::RealToHalf -#include // for Abs() -#include -#include -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - - -typedef float ValueType; -typedef openvdb::tree::LeafNode LeafNodeType; -typedef openvdb::tree::InternalNode InternalNodeType1; -typedef openvdb::tree::InternalNode InternalNodeType2; -typedef openvdb::tree::RootNode RootNodeType; - - -class TestTree: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestTree); - CPPUNIT_TEST(testChangeBackground); - CPPUNIT_TEST(testHalf); - CPPUNIT_TEST(testValues); - CPPUNIT_TEST(testSetValue); - CPPUNIT_TEST(testSetValueOnly); - CPPUNIT_TEST(testEvalMinMax); - CPPUNIT_TEST(testResize); - CPPUNIT_TEST(testHasSameTopology); - CPPUNIT_TEST(testTopologyCopy); - CPPUNIT_TEST(testIterators); - CPPUNIT_TEST(testIO); - CPPUNIT_TEST(testNegativeIndexing); - CPPUNIT_TEST(testDeepCopy); - CPPUNIT_TEST(testMerge); - CPPUNIT_TEST(testVoxelizeActiveTiles); - CPPUNIT_TEST(testTopologyUnion); - CPPUNIT_TEST(testTopologyIntersection); - CPPUNIT_TEST(testTopologyDifference); - CPPUNIT_TEST(testSignedFloodFill); - CPPUNIT_TEST(testPruneInactive); - CPPUNIT_TEST(testPruneLevelSet); - CPPUNIT_TEST(testTouchLeaf); - CPPUNIT_TEST(testProbeLeaf); - CPPUNIT_TEST(testAddLeaf); - CPPUNIT_TEST(testAddTile); - CPPUNIT_TEST(testGetNodes); - CPPUNIT_TEST(testLeafManager); - CPPUNIT_TEST(testNodeManager); - CPPUNIT_TEST(testProcessBBox); - CPPUNIT_TEST(testStealNode); - CPPUNIT_TEST_SUITE_END(); - - void testChangeBackground(); - void testHalf(); - void testValues(); - void testSetValue(); - void testSetValueOnly(); - void testEvalMinMax(); - void testResize(); - void testHasSameTopology(); - void testTopologyCopy(); - void testIterators(); - void testIO(); - void testNegativeIndexing(); - void testDeepCopy(); - void testMerge(); - void testVoxelizeActiveTiles(); - void testTopologyUnion(); - void testTopologyIntersection(); - void testTopologyDifference(); - void testSignedFloodFill(); - void testPruneLevelSet(); - void testPruneInactive(); - void testTouchLeaf(); - void testProbeLeaf(); - void testAddLeaf(); - void testAddTile(); - void testGetNodes(); - void testLeafManager(); - void testNodeManager(); - void testProcessBBox(); - void testStealNode(); - -private: - template void testWriteHalf(); - template void doTestMerge(openvdb::MergePolicy); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTree); - -void -TestTree::testChangeBackground() -{ - const int dim = 128; - const openvdb::Vec3f center(0.35f, 0.35f, 0.35f); - const float - radius = 0.15f, - voxelSize = 1.0f / (dim-1), - halfWidth = 4, - gamma = halfWidth * voxelSize; - typedef openvdb::FloatGrid GridT; - const openvdb::Coord inside(int(center[0]*dim), int(center[1]*dim), int(center[2]*dim)); - const openvdb::Coord outside(dim); - - {//changeBackground - GridT::Ptr grid = openvdb::tools::createLevelSetSphere( - radius, center, voxelSize, halfWidth); - openvdb::FloatTree& tree = grid->tree(); - - CPPUNIT_ASSERT(grid->tree().isValueOff(outside)); - ASSERT_DOUBLES_EXACTLY_EQUAL( gamma, tree.getValue(outside)); - - CPPUNIT_ASSERT(tree.isValueOff(inside)); - ASSERT_DOUBLES_EXACTLY_EQUAL(-gamma, tree.getValue(inside)); - - const float background = gamma*3.43f; - openvdb::tools::changeBackground(tree, background); - - CPPUNIT_ASSERT(grid->tree().isValueOff(outside)); - ASSERT_DOUBLES_EXACTLY_EQUAL( background, tree.getValue(outside)); - - CPPUNIT_ASSERT(tree.isValueOff(inside)); - ASSERT_DOUBLES_EXACTLY_EQUAL(-background, tree.getValue(inside)); - } - - {//changeLevelSetBackground - GridT::Ptr grid = openvdb::tools::createLevelSetSphere( - radius, center, voxelSize, halfWidth); - openvdb::FloatTree& tree = grid->tree(); - - CPPUNIT_ASSERT(grid->tree().isValueOff(outside)); - ASSERT_DOUBLES_EXACTLY_EQUAL( gamma, tree.getValue(outside)); - - CPPUNIT_ASSERT(tree.isValueOff(inside)); - ASSERT_DOUBLES_EXACTLY_EQUAL(-gamma, tree.getValue(inside)); - - const float v1 = gamma*3.43f, v2 = -gamma*6.457f; - openvdb::tools::changeAsymmetricLevelSetBackground(tree, v1, v2); - - CPPUNIT_ASSERT(grid->tree().isValueOff(outside)); - ASSERT_DOUBLES_EXACTLY_EQUAL( v1, tree.getValue(outside)); - - CPPUNIT_ASSERT(tree.isValueOff(inside)); - ASSERT_DOUBLES_EXACTLY_EQUAL( v2, tree.getValue(inside)); - } -} - - -void -TestTree::testHalf() -{ - testWriteHalf(); - testWriteHalf(); - testWriteHalf(); - testWriteHalf(); - testWriteHalf(); - testWriteHalf(); - - // Verify that non-floating-point grids are saved correctly. - testWriteHalf(); - testWriteHalf(); - testWriteHalf(); -} - - -template -void -TestTree::testWriteHalf() -{ - typedef openvdb::Grid GridType; - typedef typename TreeType::ValueType ValueT; - ValueT background(5); - GridType grid(background); - - unittest_util::makeSphere(openvdb::Coord(64, 64, 64), - openvdb::Vec3f(35, 30, 40), - /*radius=*/10, grid, - /*dx=*/1.0f, unittest_util::SPHERE_DENSE); - CPPUNIT_ASSERT(!grid.tree().empty()); - - // Write grid blocks in both float and half formats. - std::ostringstream outFull(std::ios_base::binary); - grid.setSaveFloatAsHalf(false); - grid.writeBuffers(outFull); - outFull.flush(); - const size_t fullBytes = outFull.str().size(); - CPPUNIT_ASSERT_MESSAGE("wrote empty full float buffers", fullBytes > 0); - - std::ostringstream outHalf(std::ios_base::binary); - grid.setSaveFloatAsHalf(true); - grid.writeBuffers(outHalf); - outHalf.flush(); - const size_t halfBytes = outHalf.str().size(); - CPPUNIT_ASSERT_MESSAGE("wrote empty half float buffers", halfBytes > 0); - - if (openvdb::io::RealToHalf::isReal) { - // Verify that the half float file is "significantly smaller" than the full float file. - std::ostringstream ostr; - ostr << "half float buffers not significantly smaller than full float (" - << halfBytes << " vs. " << fullBytes << " bytes)"; - CPPUNIT_ASSERT_MESSAGE(ostr.str(), halfBytes < size_t(0.75 * fullBytes)); - } else { - // For non-real data types, "half float" and "full float" file sizes should be the same. - CPPUNIT_ASSERT_MESSAGE("full float and half float file sizes differ for data of type " - + std::string(openvdb::typeNameAsString()), halfBytes == fullBytes); - } - - // Read back the half float data (converting back to full float in the process), - // then write it out again in half float format. Verify that the resulting file - // is identical to the original half float file. - { - openvdb::Grid gridCopy(grid); - gridCopy.setSaveFloatAsHalf(true); - std::istringstream is(outHalf.str(), std::ios_base::binary); - - // Since the input stream doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(is); - - gridCopy.readBuffers(is); - - std::ostringstream outDiff(std::ios_base::binary); - gridCopy.writeBuffers(outDiff); - outDiff.flush(); - - CPPUNIT_ASSERT_MESSAGE("half-from-full and half-from-half buffers differ", - outHalf.str() == outDiff.str()); - } -} - - -void -TestTree::testValues() -{ - ValueType background=5.0f; - - { - const openvdb::Coord c0(5,10,20), c1(50000,20000,30000); - RootNodeType root_node(background); - const float v0=0.234f, v1=4.5678f; - CPPUNIT_ASSERT(root_node.empty()); - ASSERT_DOUBLES_EXACTLY_EQUAL(root_node.getValue(c0), background); - ASSERT_DOUBLES_EXACTLY_EQUAL(root_node.getValue(c1), background); - root_node.setValueOn(c0, v0); - root_node.setValueOn(c1, v1); - ASSERT_DOUBLES_EXACTLY_EQUAL(v0,root_node.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(v1,root_node.getValue(c1)); - int count=0; - for (int i =0; i<256; ++i) { - for (int j=0; j<256; ++j) { - for (int k=0; k<256; ++k) { - if (root_node.getValue(openvdb::Coord(i,j,k))<1.0f) ++count; - } - } - } - CPPUNIT_ASSERT(count == 1); - } - - { - const openvdb::Coord min(-30,-25,-60), max(60,80,100); - const openvdb::Coord c0(-5,-10,-20), c1(50,20,90), c2(59,67,89); - const float v0=0.234f, v1=4.5678f, v2=-5.673f; - RootNodeType root_node(background); - CPPUNIT_ASSERT(root_node.empty()); - ASSERT_DOUBLES_EXACTLY_EQUAL(background,root_node.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background,root_node.getValue(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background,root_node.getValue(c2)); - root_node.setValueOn(c0, v0); - root_node.setValueOn(c1, v1); - root_node.setValueOn(c2, v2); - ASSERT_DOUBLES_EXACTLY_EQUAL(v0,root_node.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(v1,root_node.getValue(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(v2,root_node.getValue(c2)); - int count=0; - for (int i =min[0]; i -void -evalMinMaxTest() -{ - typedef typename TreeT::ValueType ValueT; - - struct Local { - static bool isEqual(const ValueT& a, const ValueT& b) { - using namespace openvdb; // for operator>() - return !(math::Abs(a - b) > zeroVal()); - } - }; - - const ValueT - zero = openvdb::zeroVal(), - minusTwo = zero + (-2), - plusTwo = zero + 2, - five = zero + 5; - - TreeT tree(/*background=*/five); - - // No set voxels (defaults to min = max = zero) - ValueT minVal = five, maxVal = five; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT(Local::isEqual(minVal, zero)); - CPPUNIT_ASSERT(Local::isEqual(maxVal, zero)); - - // Only one set voxel - tree.setValue(openvdb::Coord(0, 0, 0), minusTwo); - minVal = maxVal = five; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT(Local::isEqual(minVal, minusTwo)); - CPPUNIT_ASSERT(Local::isEqual(maxVal, minusTwo)); - - // Multiple set voxels, single value - tree.setValue(openvdb::Coord(10, 10, 10), minusTwo); - minVal = maxVal = five; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT(Local::isEqual(minVal, minusTwo)); - CPPUNIT_ASSERT(Local::isEqual(maxVal, minusTwo)); - - // Multiple set voxels, multiple values - tree.setValue(openvdb::Coord(10, 10, 10), plusTwo); - tree.setValue(openvdb::Coord(-10, -10, -10), zero); - minVal = maxVal = five; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT(Local::isEqual(minVal, minusTwo)); - CPPUNIT_ASSERT(Local::isEqual(maxVal, plusTwo)); -} - -/// Specialization for boolean trees -template<> -void -evalMinMaxTest() -{ - openvdb::BoolTree tree(/*background=*/false); - - // No set voxels (defaults to min = max = zero) - bool minVal = true, maxVal = false; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(false, minVal); - CPPUNIT_ASSERT_EQUAL(false, maxVal); - - // Only one set voxel - tree.setValue(openvdb::Coord(0, 0, 0), true); - minVal = maxVal = false; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(true, minVal); - CPPUNIT_ASSERT_EQUAL(true, maxVal); - - // Multiple set voxels, single value - tree.setValue(openvdb::Coord(-10, -10, -10), true); - minVal = maxVal = false; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(true, minVal); - CPPUNIT_ASSERT_EQUAL(true, maxVal); - - // Multiple set voxels, multiple values - tree.setValue(openvdb::Coord(10, 10, 10), false); - minVal = true; maxVal = false; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(false, minVal); - CPPUNIT_ASSERT_EQUAL(true, maxVal); -} - -/// Specialization for string trees -template<> -void -evalMinMaxTest() -{ - const std::string - echidna("echidna"), loris("loris"), pangolin("pangolin"); - - openvdb::StringTree tree(/*background=*/loris); - - // No set voxels (defaults to min = max = zero) - std::string minVal, maxVal; - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(std::string(), minVal); - CPPUNIT_ASSERT_EQUAL(std::string(), maxVal); - - // Only one set voxel - tree.setValue(openvdb::Coord(0, 0, 0), pangolin); - minVal.clear(); maxVal.clear(); - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(pangolin, minVal); - CPPUNIT_ASSERT_EQUAL(pangolin, maxVal); - - // Multiple set voxels, single value - tree.setValue(openvdb::Coord(-10, -10, -10), pangolin); - minVal.clear(); maxVal.clear(); - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(pangolin, minVal); - CPPUNIT_ASSERT_EQUAL(pangolin, maxVal); - - // Multiple set voxels, multiple values - tree.setValue(openvdb::Coord(10, 10, 10), echidna); - minVal.clear(); maxVal.clear(); - tree.evalMinMax(minVal, maxVal); - CPPUNIT_ASSERT_EQUAL(echidna, minVal); - CPPUNIT_ASSERT_EQUAL(pangolin, maxVal); -} - -} // unnamed namespace - -void -TestTree::testEvalMinMax() -{ - evalMinMaxTest(); - evalMinMaxTest(); - evalMinMaxTest(); - evalMinMaxTest(); - evalMinMaxTest(); - evalMinMaxTest(); -} - - -void -TestTree::testResize() -{ - ValueType background=5.0f; - //use this when resize is implemented - RootNodeType root_node(background); - CPPUNIT_ASSERT(root_node.getLevel()==3); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, root_node.getValue(openvdb::Coord(5,10,20))); - //fprintf(stdout,"Root grid dim=(%i,%i,%i)\n", - // root_node.getGridDim(0), root_node.getGridDim(1), root_node.getGridDim(2)); - root_node.setValueOn(openvdb::Coord(5,10,20),0.234f); - ASSERT_DOUBLES_EXACTLY_EQUAL(root_node.getValue(openvdb::Coord(5,10,20)) , 0.234f); - root_node.setValueOn(openvdb::Coord(500,200,300),4.5678f); - ASSERT_DOUBLES_EXACTLY_EQUAL(root_node.getValue(openvdb::Coord(500,200,300)) , 4.5678f); - { - ValueType sum=0.0f; - for (RootNodeType::ChildOnIter root_iter = root_node.beginChildOn(); - root_iter.test(); ++root_iter) - { - for (InternalNodeType2::ChildOnIter internal_iter2 = root_iter->beginChildOn(); - internal_iter2.test(); ++internal_iter2) - { - for (InternalNodeType1::ChildOnIter internal_iter1 = - internal_iter2->beginChildOn(); internal_iter1.test(); ++internal_iter1) - { - for (LeafNodeType::ValueOnIter block_iter = - internal_iter1->beginValueOn(); block_iter.test(); ++block_iter) - { - sum += *block_iter; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL(sum, (0.234f + 4.5678f)); - } - - CPPUNIT_ASSERT(root_node.getLevel()==3); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, root_node.getValue(openvdb::Coord(5,11,20))); - { - ValueType sum=0.0f; - for (RootNodeType::ChildOnIter root_iter = root_node.beginChildOn(); - root_iter.test(); ++root_iter) - { - for (InternalNodeType2::ChildOnIter internal_iter2 = root_iter->beginChildOn(); - internal_iter2.test(); ++internal_iter2) - { - for (InternalNodeType1::ChildOnIter internal_iter1 = - internal_iter2->beginChildOn(); internal_iter1.test(); ++internal_iter1) - { - for (LeafNodeType::ValueOnIter block_iter = - internal_iter1->beginValueOn(); block_iter.test(); ++block_iter) - { - sum += *block_iter; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL(sum, (0.234f + 4.5678f)); - } - -} - - -void -TestTree::testHasSameTopology() -{ - // Test using trees of the same type. - { - const float background1=5.0f; - openvdb::FloatTree tree1(background1); - - const float background2=6.0f; - openvdb::FloatTree tree2(background2); - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - tree1.setValue(openvdb::Coord(-10,40,845),3.456f); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(-10,40,845),-3.456f); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - tree1.setValue(openvdb::Coord(1,-500,-8), 1.0f); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(1,-500,-8),1.0f); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - } - // Test using trees of different types. - { - const float background1=5.0f; - openvdb::FloatTree tree1(background1); - - const openvdb::Vec3f background2(1.0f,3.4f,6.0f); - openvdb::Vec3fTree tree2(background2); - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - tree1.setValue(openvdb::Coord(-10,40,845),3.456f); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(-10,40,845),openvdb::Vec3f(1.0f,2.0f,-3.0f)); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - tree1.setValue(openvdb::Coord(1,-500,-8), 1.0f); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(1,-500,-8),openvdb::Vec3f(1.0f,2.0f,-3.0f)); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - } -} - - -void -TestTree::testTopologyCopy() -{ - // Test using trees of the same type. - { - const float background1=5.0f; - openvdb::FloatTree tree1(background1); - tree1.setValue(openvdb::Coord(-10,40,845),3.456f); - tree1.setValue(openvdb::Coord(1,-50,-8), 1.0f); - - const float background2=6.0f, setValue2=3.0f; - openvdb::FloatTree tree2(tree1,background2,setValue2,openvdb::TopologyCopy()); - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - ASSERT_DOUBLES_EXACTLY_EQUAL(background2, tree2.getValue(openvdb::Coord(1,2,3))); - ASSERT_DOUBLES_EXACTLY_EQUAL(setValue2, tree2.getValue(openvdb::Coord(-10,40,845))); - ASSERT_DOUBLES_EXACTLY_EQUAL(setValue2, tree2.getValue(openvdb::Coord(1,-50,-8))); - - tree1.setValue(openvdb::Coord(1,-500,-8), 1.0f); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(1,-500,-8),1.0f); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - } - // Test using trees of different types. - { - const openvdb::Vec3f background1(1.0f,3.4f,6.0f); - openvdb::Vec3fTree tree1(background1); - tree1.setValue(openvdb::Coord(-10,40,845),openvdb::Vec3f(3.456f,-2.3f,5.6f)); - tree1.setValue(openvdb::Coord(1,-50,-8), openvdb::Vec3f(1.0f,3.0f,4.5f)); - - const float background2=6.0f, setValue2=3.0f; - openvdb::FloatTree tree2(tree1,background2,setValue2,openvdb::TopologyCopy()); - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - - ASSERT_DOUBLES_EXACTLY_EQUAL(background2, tree2.getValue(openvdb::Coord(1,2,3))); - ASSERT_DOUBLES_EXACTLY_EQUAL(setValue2, tree2.getValue(openvdb::Coord(-10,40,845))); - ASSERT_DOUBLES_EXACTLY_EQUAL(setValue2, tree2.getValue(openvdb::Coord(1,-50,-8))); - - tree1.setValue(openvdb::Coord(1,-500,-8), openvdb::Vec3f(1.0f,0.0f,-3.0f)); - CPPUNIT_ASSERT(!tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(!tree2.hasSameTopology(tree1)); - - tree2.setValue(openvdb::Coord(1,-500,-8), 1.0f); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree2)); - CPPUNIT_ASSERT(tree2.hasSameTopology(tree1)); - } -} - - -void -TestTree::testIterators() -{ - ValueType background=5.0f; - RootNodeType root_node(background); - root_node.setValueOn(openvdb::Coord(5,10,20),0.234f); - root_node.setValueOn(openvdb::Coord(50000,20000,30000),4.5678f); - { - ValueType sum=0.0f; - for (RootNodeType::ChildOnIter root_iter = root_node.beginChildOn(); - root_iter.test(); ++root_iter) - { - for (InternalNodeType2::ChildOnIter internal_iter2 = root_iter->beginChildOn(); - internal_iter2.test(); ++internal_iter2) - { - for (InternalNodeType1::ChildOnIter internal_iter1 = - internal_iter2->beginChildOn(); internal_iter1.test(); ++internal_iter1) - { - for (LeafNodeType::ValueOnIter block_iter = - internal_iter1->beginValueOn(); block_iter.test(); ++block_iter) - { - sum += *block_iter; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL((0.234f + 4.5678f), sum); - } - { - // As above, but using dense iterators. - ValueType sum = 0.0f, val = 0.0f; - for (RootNodeType::ChildAllIter rootIter = root_node.beginChildAll(); - rootIter.test(); ++rootIter) - { - if (!rootIter.isChildNode()) continue; - - for (InternalNodeType2::ChildAllIter internalIter2 = - rootIter.probeChild(val)->beginChildAll(); internalIter2; ++internalIter2) - { - if (!internalIter2.isChildNode()) continue; - - for (InternalNodeType1::ChildAllIter internalIter1 = - internalIter2.probeChild(val)->beginChildAll(); internalIter1; ++internalIter1) - { - if (!internalIter1.isChildNode()) continue; - - for (LeafNodeType::ValueOnIter leafIter = - internalIter1.probeChild(val)->beginValueOn(); leafIter; ++leafIter) - { - sum += *leafIter; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL((0.234f + 4.5678f), sum); - } - { - ValueType v_sum=0.0f; - openvdb::Coord xyz0, xyz1, xyz2, xyz3, xyzSum(0, 0, 0); - for (RootNodeType::ChildOnIter root_iter = root_node.beginChildOn(); - root_iter.test(); ++root_iter) - { - root_iter.getCoord(xyz3); - for (InternalNodeType2::ChildOnIter internal_iter2 = root_iter->beginChildOn(); - internal_iter2.test(); ++internal_iter2) - { - internal_iter2.getCoord(xyz2); - xyz2 = xyz2 - internal_iter2.parent().origin(); - for (InternalNodeType1::ChildOnIter internal_iter1 = - internal_iter2->beginChildOn(); internal_iter1.test(); ++internal_iter1) - { - internal_iter1.getCoord(xyz1); - xyz1 = xyz1 - internal_iter1.parent().origin(); - for (LeafNodeType::ValueOnIter block_iter = - internal_iter1->beginValueOn(); block_iter.test(); ++block_iter) - { - block_iter.getCoord(xyz0); - xyz0 = xyz0 - block_iter.parent().origin(); - v_sum += *block_iter; - xyzSum = xyzSum + xyz0 + xyz1 + xyz2 + xyz3; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL((0.234f + 4.5678f), v_sum); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(5 + 50000, 10 + 20000, 20 + 30000), xyzSum); - } -} - - -void -TestTree::testIO() -{ - const char* filename = "/tmp/test.dbg"; - boost::shared_ptr scopedFile(filename, ::remove); - { - ValueType background=5.0f; - RootNodeType root_node(background); - root_node.setValueOn(openvdb::Coord(5,10,20),0.234f); - root_node.setValueOn(openvdb::Coord(50000,20000,30000),4.5678f); - - std::ofstream os(filename, std::ios_base::binary); - root_node.writeTopology(os); - root_node.writeBuffers(os); - CPPUNIT_ASSERT(!os.fail()); - } - { - ValueType background=2.0f; - RootNodeType root_node(background); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, root_node.getValue(openvdb::Coord(5,10,20))); - { - std::ifstream is(filename, std::ios_base::binary); - // Since the test file doesn't include a VDB header with file format version info, - // tag the input stream explicitly with the current version number. - openvdb::io::setCurrentVersion(is); - root_node.readTopology(is); - root_node.readBuffers(is); - CPPUNIT_ASSERT(!is.fail()); - } - - ASSERT_DOUBLES_EXACTLY_EQUAL(0.234f, root_node.getValue(openvdb::Coord(5,10,20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(5.0f, root_node.getValue(openvdb::Coord(5,11,20))); - ValueType sum=0.0f; - for (RootNodeType::ChildOnIter root_iter = root_node.beginChildOn(); - root_iter.test(); ++root_iter) - { - for (InternalNodeType2::ChildOnIter internal_iter2 = root_iter->beginChildOn(); - internal_iter2.test(); ++internal_iter2) - { - for (InternalNodeType1::ChildOnIter internal_iter1 = - internal_iter2->beginChildOn(); internal_iter1.test(); ++internal_iter1) - { - for (LeafNodeType::ValueOnIter block_iter = - internal_iter1->beginValueOn(); block_iter.test(); ++block_iter) - { - sum += *block_iter; - } - } - } - } - ASSERT_DOUBLES_EXACTLY_EQUAL(sum, (0.234f + 4.5678f)); - } -} - - -void -TestTree::testNegativeIndexing() -{ - ValueType background=5.0f; - openvdb::FloatTree tree(background); - CPPUNIT_ASSERT(tree.empty()); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree.getValue(openvdb::Coord(5,-10,20)), background); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree.getValue(openvdb::Coord(-5000,2000,3000)), background); - tree.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree.setValue(openvdb::Coord( 5, 10,-20),0.3f); - tree.setValue(openvdb::Coord(-5,-10, 20),0.4f); - tree.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree.setValue(openvdb::Coord(-5,-10,-20),0.7f); - tree.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.0f, tree.getValue(openvdb::Coord( 5, 10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.1f, tree.getValue(openvdb::Coord(-5, 10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.2f, tree.getValue(openvdb::Coord( 5,-10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.3f, tree.getValue(openvdb::Coord( 5, 10,-20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.4f, tree.getValue(openvdb::Coord(-5,-10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.5f, tree.getValue(openvdb::Coord(-5, 10,-20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.6f, tree.getValue(openvdb::Coord( 5,-10,-20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.7f, tree.getValue(openvdb::Coord(-5,-10,-20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord(-5000, 2000,-3000))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord( 5000,-2000,-3000))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord(-5000,-2000, 3000))); - int count=0; - for (int i =-25; i<25; ++i) { - for (int j=-25; j<25; ++j) { - for (int k=-25; k<25; ++k) { - if (tree.getValue(openvdb::Coord(i,j,k))<1.0f) { - //fprintf(stderr,"(%i,%i,%i)=%f\n",i,j,k,tree.getValue(openvdb::Coord(i,j,k))); - ++count; - } - } - } - } - CPPUNIT_ASSERT(count == 8); - int count2 = 0; - openvdb::Coord xyz; - for (openvdb::FloatTree::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - ++count2; - xyz = iter.getCoord(); - //std::cerr << xyz << " = " << *iter << "\n"; - } - CPPUNIT_ASSERT(count2 == 11); - CPPUNIT_ASSERT(tree.activeVoxelCount() == 11); - { - count2 = 0; - for (openvdb::FloatTree::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - ++count2; - xyz = iter.getCoord(); - //std::cerr << xyz << " = " << *iter << "\n"; - } - CPPUNIT_ASSERT(count2 == 11); - CPPUNIT_ASSERT(tree.activeVoxelCount() == 11); - } -} - - -void -TestTree::testDeepCopy() -{ - // set up a tree - const float fillValue1=5.0f; - openvdb::FloatTree tree1(fillValue1); - tree1.setValue(openvdb::Coord(-10,40,845), 3.456f); - tree1.setValue(openvdb::Coord(1,-50,-8), 1.0f); - - // make a deep copy of the tree - openvdb::TreeBase::Ptr newTree = tree1.copy(); - - // cast down to the concrete type to query values - openvdb::FloatTree *pTree2 = dynamic_cast(newTree.get()); - - // compare topology - CPPUNIT_ASSERT(tree1.hasSameTopology(*pTree2)); - CPPUNIT_ASSERT(pTree2->hasSameTopology(tree1)); - - // trees should be equal - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue1, pTree2->getValue(openvdb::Coord(1,2,3))); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.456f, pTree2->getValue(openvdb::Coord(-10,40,845))); - ASSERT_DOUBLES_EXACTLY_EQUAL(1.0f, pTree2->getValue(openvdb::Coord(1,-50,-8))); - - // change 1 value in tree2 - openvdb::Coord changeCoord(1, -500, -8); - pTree2->setValue(changeCoord, 1.0f); - - // topology should no longer match - CPPUNIT_ASSERT(!tree1.hasSameTopology(*pTree2)); - CPPUNIT_ASSERT(!pTree2->hasSameTopology(tree1)); - - // query changed value and make sure it's different between trees - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue1, tree1.getValue(changeCoord)); - ASSERT_DOUBLES_EXACTLY_EQUAL(1.0f, pTree2->getValue(changeCoord)); -} - - -void -TestTree::testMerge() -{ - ValueType background=5.0f; - openvdb::FloatTree tree0(background), tree1(background), tree2(background); - CPPUNIT_ASSERT(tree2.empty()); - tree0.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree0.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree0.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree0.setValue(openvdb::Coord( 5, 10,-20),0.3f); - tree1.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree1.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree1.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree1.setValue(openvdb::Coord( 5, 10,-20),0.3f); - - tree0.setValue(openvdb::Coord(-5,-10, 20),0.4f); - tree0.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree0.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree0.setValue(openvdb::Coord(-5,-10,-20),0.7f); - tree0.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree0.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree0.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - tree2.setValue(openvdb::Coord(-5,-10, 20),0.4f); - tree2.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree2.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree2.setValue(openvdb::Coord(-5,-10,-20),0.7f); - tree2.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - - CPPUNIT_ASSERT(tree0.leafCount()!=tree1.leafCount()); - CPPUNIT_ASSERT(tree0.leafCount()!=tree2.leafCount()); - - CPPUNIT_ASSERT(!tree2.empty()); - tree1.merge(tree2, openvdb::MERGE_ACTIVE_STATES); - CPPUNIT_ASSERT(tree2.empty()); - CPPUNIT_ASSERT(tree0.leafCount()==tree1.leafCount()); - CPPUNIT_ASSERT(tree0.nonLeafCount()==tree1.nonLeafCount()); - CPPUNIT_ASSERT(tree0.activeLeafVoxelCount()==tree1.activeLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveLeafVoxelCount()==tree1.inactiveLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.activeVoxelCount()==tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveVoxelCount()==tree1.inactiveVoxelCount()); - - for (openvdb::FloatTree::ValueOnCIter iter0 = tree0.cbeginValueOn(); iter0; ++iter0) { - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter0,tree1.getValue(iter0.getCoord())); - } - - // Test active tile support. - { - using namespace openvdb; - FloatTree treeA(/*background*/0.0), treeB(/*background*/0.0); - - treeA.fill(CoordBBox(Coord(16,16,16), Coord(31,31,31)), /*value*/1.0); - treeB.fill(CoordBBox(Coord(0,0,0), Coord(15,15,15)), /*value*/1.0); - - CPPUNIT_ASSERT_EQUAL(4096, int(treeA.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(4096, int(treeB.activeVoxelCount())); - - treeA.merge(treeB, MERGE_ACTIVE_STATES); - - CPPUNIT_ASSERT_EQUAL(8192, int(treeA.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(0, int(treeB.activeVoxelCount())); - } - - doTestMerge(openvdb::MERGE_NODES); - doTestMerge(openvdb::MERGE_ACTIVE_STATES); - doTestMerge(openvdb::MERGE_ACTIVE_STATES_AND_NODES); - - doTestMerge(openvdb::MERGE_NODES); - doTestMerge(openvdb::MERGE_ACTIVE_STATES); - doTestMerge(openvdb::MERGE_ACTIVE_STATES_AND_NODES); -} - - -template -void -TestTree::doTestMerge(openvdb::MergePolicy policy) -{ - using namespace openvdb; - - TreeType treeA, treeB; - - typedef typename TreeType::RootNodeType RootT; - typedef typename TreeType::LeafNodeType LeafT; - - const typename TreeType::ValueType val(1); - const int - depth = static_cast(treeA.treeDepth()), - leafDim = static_cast(LeafT::dim()), - leafSize = static_cast(LeafT::size()); - // Coords that are in a different top-level branch than (0, 0, 0) - const Coord pos(static_cast(RootT::getChildDim())); - - treeA.setValueOff(pos, val); - treeA.setValueOff(-pos, val); - - treeB.setValueOff(Coord(0), val); - treeB.fill(CoordBBox(pos, pos.offsetBy(leafDim - 1)), val, /*active=*/true); - treeB.setValueOn(-pos, val); - - // treeA treeB . - // . - // R R . - // / \ /|\ . - // I I I I I . - // / \ / | \ . - // I I I I I . - // / \ / | on x SIZE . - // L L L L . - // off off on off . - - CPPUNIT_ASSERT_EQUAL(0, int(treeA.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(leafSize + 1, int(treeB.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(2, int(treeA.leafCount())); - CPPUNIT_ASSERT_EQUAL(2, int(treeB.leafCount())); - CPPUNIT_ASSERT_EQUAL(2*(depth-2)+1, int(treeA.nonLeafCount())); // 2 branches (II+II+R) - CPPUNIT_ASSERT_EQUAL(3*(depth-2)+1, int(treeB.nonLeafCount())); // 3 branches (II+II+II+R) - - treeA.merge(treeB, policy); - - // MERGE_NODES MERGE_ACTIVE_STATES MERGE_ACTIVE_STATES_AND_NODES . - // . - // R R R . - // /|\ /|\ /|\ . - // I I I I I I I I I . - // / | \ / | \ / | \ . - // I I I I I I I I I . - // / | \ / | on x SIZE / | \ . - // L L L L L L L L . - // off off off on off on off on x SIZE . - - switch (policy) { - case MERGE_NODES: - CPPUNIT_ASSERT_EQUAL(0, int(treeA.activeVoxelCount())); - CPPUNIT_ASSERT_EQUAL(2 + 1, int(treeA.leafCount())); // 1 leaf node stolen from B - CPPUNIT_ASSERT_EQUAL(3*(depth-2)+1, int(treeA.nonLeafCount())); // 3 branches (II+II+II+R) - break; - case MERGE_ACTIVE_STATES: - CPPUNIT_ASSERT_EQUAL(2, int(treeA.leafCount())); // 1 leaf stolen, 1 replaced with tile - CPPUNIT_ASSERT_EQUAL(3*(depth-2)+1, int(treeA.nonLeafCount())); // 3 branches (II+II+II+R) - CPPUNIT_ASSERT_EQUAL(leafSize + 1, int(treeA.activeVoxelCount())); - break; - case MERGE_ACTIVE_STATES_AND_NODES: - CPPUNIT_ASSERT_EQUAL(2 + 1, int(treeA.leafCount())); // 1 leaf node stolen from B - CPPUNIT_ASSERT_EQUAL(3*(depth-2)+1, int(treeA.nonLeafCount())); // 3 branches (II+II+II+R) - CPPUNIT_ASSERT_EQUAL(leafSize + 1, int(treeA.activeVoxelCount())); - break; - } - CPPUNIT_ASSERT(treeB.empty()); -} - - -void -TestTree::testVoxelizeActiveTiles() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - // Use a small custom tree so we don't run out of memory when - // tiles are converted to dense leafs :) - typedef openvdb::tree::Tree4::Type MyTree; - float background=5.0f; - const Coord xyz[] = {Coord(-1,-2,-3),Coord( 1, 2, 3)}; - //check two leaf nodes and two tiles at each level 1, 2 and 3 - const int tile_size[4]={0, 1<<2, 1<<(2*2), 1<<(3*2)}; - for (int level=0; level<=3; ++level) { - - MyTree tree(background); - CPPUNIT_ASSERT_EQUAL(-1,tree.getValueDepth(xyz[0])); - CPPUNIT_ASSERT_EQUAL(-1,tree.getValueDepth(xyz[1])); - - if (level==0) { - tree.setValue(xyz[0], 1.0f); - tree.setValue(xyz[1], 1.0f); - } else { - const int n = tile_size[level]; - tree.fill(CoordBBox::createCube(Coord(-n,-n,-n), n), 1.0f, true); - tree.fill(CoordBBox::createCube(Coord( 0, 0, 0), n), 1.0f, true); - } - - CPPUNIT_ASSERT_EQUAL(3-level,tree.getValueDepth(xyz[0])); - CPPUNIT_ASSERT_EQUAL(3-level,tree.getValueDepth(xyz[1])); - - tree.voxelizeActiveTiles(); - - CPPUNIT_ASSERT_EQUAL(3 ,tree.getValueDepth(xyz[0])); - CPPUNIT_ASSERT_EQUAL(3 ,tree.getValueDepth(xyz[1])); - } -} - - -void -TestTree::testTopologyUnion() -{ - {//super simple test with only two active values - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - tree1.setValue(openvdb::Coord( 8, 11, 11), 2.0f); - openvdb::FloatTree tree2(tree1); - - tree1.topologyUnion(tree0); - - for (openvdb::FloatTree::ValueOnCIter iter = tree0.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT(tree1.isValueOn(iter.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree2.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT(tree1.isValueOn(iter.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree2.getValue(iter.getCoord())); - } - } - {// test using setValue - ValueType background=5.0f; - openvdb::FloatTree tree0(background), tree1(background), tree2(background); - CPPUNIT_ASSERT(tree2.empty()); - // tree0 = tree1.topologyUnion(tree2) - tree0.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree0.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree0.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree0.setValue(openvdb::Coord( 5, 10,-20),0.3f); - tree1.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree1.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree1.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree1.setValue(openvdb::Coord( 5, 10,-20),0.3f); - - tree0.setValue(openvdb::Coord(-5,-10, 20),background); - tree0.setValue(openvdb::Coord(-5, 10,-20),background); - tree0.setValue(openvdb::Coord( 5,-10,-20),background); - tree0.setValue(openvdb::Coord(-5,-10,-20),background); - tree0.setValue(openvdb::Coord(-5000, 2000,-3000),background); - tree0.setValue(openvdb::Coord( 5000,-2000,-3000),background); - tree0.setValue(openvdb::Coord(-5000,-2000, 3000),background); - tree2.setValue(openvdb::Coord(-5,-10, 20),0.4f); - tree2.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree2.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree2.setValue(openvdb::Coord(-5,-10,-20),0.7f); - tree2.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - - // tree3 has the same topology as tree2 but a different value type - const openvdb::Vec3f background2(1.0f,3.4f,6.0f), vec_val(3.1f,5.3f,-9.5f); - openvdb::Vec3fTree tree3(background2); - for (openvdb::FloatTree::ValueOnCIter iter2 = tree2.cbeginValueOn(); iter2; ++iter2) { - tree3.setValue(iter2.getCoord(), vec_val); - } - - CPPUNIT_ASSERT(tree0.leafCount()!=tree1.leafCount()); - CPPUNIT_ASSERT(tree0.leafCount()!=tree2.leafCount()); - CPPUNIT_ASSERT(tree0.leafCount()!=tree3.leafCount()); - - CPPUNIT_ASSERT(!tree2.empty()); - CPPUNIT_ASSERT(!tree3.empty()); - openvdb::FloatTree tree1_copy(tree1); - - //tree1.topologyUnion(tree2);//should make tree1 = tree0 - tree1.topologyUnion(tree3);//should make tree1 = tree0 - - CPPUNIT_ASSERT(tree0.leafCount()==tree1.leafCount()); - CPPUNIT_ASSERT(tree0.nonLeafCount()==tree1.nonLeafCount()); - CPPUNIT_ASSERT(tree0.activeLeafVoxelCount()==tree1.activeLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveLeafVoxelCount()==tree1.inactiveLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.activeVoxelCount()==tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveVoxelCount()==tree1.inactiveVoxelCount()); - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree0)); - CPPUNIT_ASSERT(tree0.hasSameTopology(tree1)); - - for (openvdb::FloatTree::ValueOnCIter iter2 = tree2.cbeginValueOn(); iter2; ++iter2) { - CPPUNIT_ASSERT(tree1.isValueOn(iter2.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter1 = tree1.cbeginValueOn(); iter1; ++iter1) { - CPPUNIT_ASSERT(tree0.isValueOn(iter1.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter0 = tree0.cbeginValueOn(); iter0; ++iter0) { - CPPUNIT_ASSERT(tree1.isValueOn(iter0.getCoord())); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter0,tree1.getValue(iter0.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1_copy.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT(tree1.isValueOn(iter.getCoord())); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree1.getValue(iter.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree3.isValueOn(p) || tree1_copy.isValueOn(p)); - } - } - { - ValueType background=5.0f; - openvdb::FloatTree tree0(background), tree1(background), tree2(background); - CPPUNIT_ASSERT(tree2.empty()); - // tree0 = tree1.topologyUnion(tree2) - tree0.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree0.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree0.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree0.setValue(openvdb::Coord( 5, 10,-20),0.3f); - tree1.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree1.setValue(openvdb::Coord(-5, 10, 20),0.1f); - tree1.setValue(openvdb::Coord( 5,-10, 20),0.2f); - tree1.setValue(openvdb::Coord( 5, 10,-20),0.3f); - - tree0.setValue(openvdb::Coord(-5,-10, 20),background); - tree0.setValue(openvdb::Coord(-5, 10,-20),background); - tree0.setValue(openvdb::Coord( 5,-10,-20),background); - tree0.setValue(openvdb::Coord(-5,-10,-20),background); - tree0.setValue(openvdb::Coord(-5000, 2000,-3000),background); - tree0.setValue(openvdb::Coord( 5000,-2000,-3000),background); - tree0.setValue(openvdb::Coord(-5000,-2000, 3000),background); - tree2.setValue(openvdb::Coord(-5,-10, 20),0.4f); - tree2.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree2.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree2.setValue(openvdb::Coord(-5,-10,-20),0.7f); - tree2.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - - // tree3 has the same topology as tree2 but a different value type - const openvdb::Vec3f background2(1.0f,3.4f,6.0f), vec_val(3.1f,5.3f,-9.5f); - openvdb::Vec3fTree tree3(background2); - - for (openvdb::FloatTree::ValueOnCIter iter2 = tree2.cbeginValueOn(); iter2; ++iter2) { - tree3.setValue(iter2.getCoord(), vec_val); - } - - openvdb::FloatTree tree4(tree1);//tree4 = tree1 - openvdb::FloatTree tree5(tree1);//tree5 = tree1 - - tree1.topologyUnion(tree3);//should make tree1 = tree0 - - CPPUNIT_ASSERT(tree1.hasSameTopology(tree0)); - - for (openvdb::Vec3fTree::ValueOnCIter iter3 = tree3.cbeginValueOn(); iter3; ++iter3) { - tree4.setValueOn(iter3.getCoord()); - const openvdb::Coord p = iter3.getCoord(); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree1.getValue(p),tree5.getValue(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree4.getValue(p),tree5.getValue(p)); - } - - CPPUNIT_ASSERT(tree4.hasSameTopology(tree0)); - - for (openvdb::FloatTree::ValueOnCIter iter4 = tree4.cbeginValueOn(); iter4; ++iter4) { - const openvdb::Coord p = iter4.getCoord(); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree0.getValue(p),tree5.getValue(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree1.getValue(p),tree5.getValue(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree4.getValue(p),tree5.getValue(p)); - } - - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree3.isValueOn(p) || tree4.isValueOn(p)); - } - } - {// test overlapping spheres - const float background=5.0f, R0=10.0f, R1=5.6f; - const openvdb::Vec3f C0(35.0f, 30.0f, 40.0f), C1(22.3f, 30.5f, 31.0f); - const openvdb::Coord dim(32, 32, 32); - openvdb::FloatGrid grid0(background); - openvdb::FloatGrid grid1(background); - unittest_util::makeSphere(dim, C0, R0, grid0, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - unittest_util::makeSphere(dim, C1, R1, grid1, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - openvdb::FloatTree& tree0 = grid0.tree(); - openvdb::FloatTree& tree1 = grid1.tree(); - openvdb::FloatTree tree0_copy(tree0); - - tree0.topologyUnion(tree1); - - const openvdb::Index64 n0 = tree0_copy.activeVoxelCount(); - const openvdb::Index64 n = tree0.activeVoxelCount(); - const openvdb::Index64 n1 = tree1.activeVoxelCount(); - - //fprintf(stderr,"Union of spheres: n=%i, n0=%i n1=%i n0+n1=%i\n",n,n0,n1, n0+n1); - - CPPUNIT_ASSERT( n > n0 ); - CPPUNIT_ASSERT( n > n1 ); - CPPUNIT_ASSERT( n < n0 + n1 ); - - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree0.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree0.getValue(p), tree0_copy.getValue(p)); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree0_copy.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree0.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(tree0.getValue(p), *iter); - } - } - -}// testTopologyUnion - -void -TestTree::testTopologyIntersection() -{ - {//no overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - tree1.setValue(openvdb::Coord( 8, 11, 11), 2.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree1.activeVoxelCount()); - - tree1.topologyIntersection(tree0); - - CPPUNIT_ASSERT_EQUAL(tree1.activeVoxelCount(), openvdb::Index64(0)); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(tree1.empty()); - } - {//two overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - - tree1.setValue(openvdb::Coord( 8, 11, 11), 2.0f); - tree1.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree0.activeVoxelCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(2), tree1.activeVoxelCount() ); - - tree1.topologyIntersection(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - } - {//4 overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - tree0.setValue(openvdb::Coord( 400, 30, 20), 2.0f); - tree0.setValue(openvdb::Coord( 8, 11, 11), 3.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree0.leafCount() ); - - tree1.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree1.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree1.setValue(openvdb::Coord( 8, 11, 11), 6.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree1.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree1.leafCount() ); - - tree1.topologyIntersection(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(3), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(2), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(2), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(2), tree1.activeVoxelCount() ); - } - {//passive tile - const ValueType background=0.0f; - const openvdb::Index64 dim = openvdb::FloatTree::RootNodeType::ChildNodeType::DIM; - openvdb::FloatTree tree0(background), tree1(background); - tree0.fill(openvdb::CoordBBox(openvdb::Coord(0),openvdb::Coord(dim-1)),2.0f, false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(0), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree0.leafCount() ); - - tree1.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree1.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree1.setValue(openvdb::Coord( dim, 11, 11), 6.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree1.activeVoxelCount()); - - tree1.topologyIntersection(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(0), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(0), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(tree1.empty()); - } - {//active tile - const ValueType background=0.0f; - const openvdb::Index64 dim = openvdb::FloatTree::RootNodeType::ChildNodeType::DIM; - openvdb::FloatTree tree0(background), tree1(background); - tree1.fill(openvdb::CoordBBox(openvdb::Coord(0),openvdb::Coord(dim-1)),2.0f, true); - CPPUNIT_ASSERT_EQUAL(dim*dim*dim, tree1.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree1.leafCount() ); - - tree0.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree0.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree0.setValue(openvdb::Coord( dim, 11, 11), 6.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree0.leafCount() ); - - tree1.topologyIntersection(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(2), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(2), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - } - {// use tree with different voxel type - ValueType background=5.0f; - openvdb::FloatTree tree0(background), tree1(background), tree2(background); - CPPUNIT_ASSERT(tree2.empty()); - // tree0 = tree1.topologyIntersection(tree2) - tree0.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree0.setValue(openvdb::Coord(-5, 10,-20),0.1f); - tree0.setValue(openvdb::Coord( 5,-10,-20),0.2f); - tree0.setValue(openvdb::Coord(-5,-10,-20),0.3f); - - tree1.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree1.setValue(openvdb::Coord(-5, 10,-20),0.1f); - tree1.setValue(openvdb::Coord( 5,-10,-20),0.2f); - tree1.setValue(openvdb::Coord(-5,-10,-20),0.3f); - - tree2.setValue(openvdb::Coord( 5, 10, 20),0.4f); - tree2.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree2.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree2.setValue(openvdb::Coord(-5,-10,-20),0.7f); - - tree2.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - - openvdb::FloatTree tree1_copy(tree1); - - // tree3 has the same topology as tree2 but a different value type - const openvdb::Vec3f background2(1.0f,3.4f,6.0f), vec_val(3.1f,5.3f,-9.5f); - openvdb::Vec3fTree tree3(background2); - for (openvdb::FloatTree::ValueOnCIter iter = tree2.cbeginValueOn(); iter; ++iter) { - tree3.setValue(iter.getCoord(), vec_val); - } - - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(4), tree0.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(4), tree1.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree2.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree3.leafCount()); - - - //tree1.topologyInterection(tree2);//should make tree1 = tree0 - tree1.topologyIntersection(tree3);//should make tree1 = tree0 - - CPPUNIT_ASSERT(tree0.leafCount()==tree1.leafCount()); - CPPUNIT_ASSERT(tree0.nonLeafCount()==tree1.nonLeafCount()); - CPPUNIT_ASSERT(tree0.activeLeafVoxelCount()==tree1.activeLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveLeafVoxelCount()==tree1.inactiveLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.activeVoxelCount()==tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveVoxelCount()==tree1.inactiveVoxelCount()); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree0)); - CPPUNIT_ASSERT(tree0.hasSameTopology(tree1)); - - for (openvdb::FloatTree::ValueOnCIter iter = tree0.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree1.isValueOn(p)); - CPPUNIT_ASSERT(tree2.isValueOn(p)); - CPPUNIT_ASSERT(tree3.isValueOn(p)); - CPPUNIT_ASSERT(tree1_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree1.getValue(p)); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1_copy.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT(tree1.isValueOn(iter.getCoord())); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree1.getValue(iter.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree0.isValueOn(p)); - CPPUNIT_ASSERT(tree2.isValueOn(p)); - CPPUNIT_ASSERT(tree3.isValueOn(p)); - CPPUNIT_ASSERT(tree1_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree0.getValue(p)); - } - } - - {// test overlapping spheres - const float background=5.0f, R0=10.0f, R1=5.6f; - const openvdb::Vec3f C0(35.0f, 30.0f, 40.0f), C1(22.3f, 30.5f, 31.0f); - const openvdb::Coord dim(32, 32, 32); - openvdb::FloatGrid grid0(background); - openvdb::FloatGrid grid1(background); - unittest_util::makeSphere(dim, C0, R0, grid0, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - unittest_util::makeSphere(dim, C1, R1, grid1, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - openvdb::FloatTree& tree0 = grid0.tree(); - openvdb::FloatTree& tree1 = grid1.tree(); - openvdb::FloatTree tree0_copy(tree0); - - tree0.topologyIntersection(tree1); - - const openvdb::Index64 n0 = tree0_copy.activeVoxelCount(); - const openvdb::Index64 n = tree0.activeVoxelCount(); - const openvdb::Index64 n1 = tree1.activeVoxelCount(); - - //fprintf(stderr,"Intersection of spheres: n=%i, n0=%i n1=%i n0+n1=%i\n",n,n0,n1, n0+n1); - - CPPUNIT_ASSERT( n < n0 ); - CPPUNIT_ASSERT( n < n1 ); - - for (openvdb::FloatTree::ValueOnCIter iter = tree0.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree1.isValueOn(p)); - CPPUNIT_ASSERT(tree0_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter, tree0_copy.getValue(p)); - } - } - - {// Test based on boolean grids - openvdb::CoordBBox big( openvdb::Coord(-9), openvdb::Coord(10)); - openvdb::CoordBBox small(openvdb::Coord( 1), openvdb::Coord(10)); - - openvdb::BoolGrid::Ptr gridBig = openvdb::BoolGrid::create(false); - gridBig->fill(big, true/*value*/, true /*make active*/); - CPPUNIT_ASSERT_EQUAL(8, int(gridBig->tree().activeTileCount())); - CPPUNIT_ASSERT_EQUAL((20 * 20 * 20), int(gridBig->activeVoxelCount())); - - openvdb::BoolGrid::Ptr gridSmall = openvdb::BoolGrid::create(false); - gridSmall->fill(small, true/*value*/, true /*make active*/); - CPPUNIT_ASSERT_EQUAL(0, int(gridSmall->tree().activeTileCount())); - CPPUNIT_ASSERT_EQUAL((10 * 10 * 10), int(gridSmall->activeVoxelCount())); - - // change the topology of gridBig by intersecting with gridSmall - gridBig->topologyIntersection(*gridSmall); - - // Should be unchanged - CPPUNIT_ASSERT_EQUAL(0, int(gridSmall->tree().activeTileCount())); - CPPUNIT_ASSERT_EQUAL((10 * 10 * 10), int(gridSmall->activeVoxelCount())); - - // In this case the interesection should be exactly "small" - CPPUNIT_ASSERT_EQUAL(0, int(gridBig->tree().activeTileCount())); - CPPUNIT_ASSERT_EQUAL((10 * 10 * 10), int(gridBig->activeVoxelCount())); - - } - -}// testTopologyIntersection - -void -TestTree::testTopologyDifference() -{ - {//no overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - tree1.setValue(openvdb::Coord( 8, 11, 11), 2.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree1.activeVoxelCount()); - - tree1.topologyDifference(tree0); - - CPPUNIT_ASSERT_EQUAL(tree1.activeVoxelCount(), openvdb::Index64(1)); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - } - {//two overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - - tree1.setValue(openvdb::Coord( 8, 11, 11), 2.0f); - tree1.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree0.activeVoxelCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(2), tree1.activeVoxelCount() ); - - CPPUNIT_ASSERT( tree0.isValueOn(openvdb::Coord( 500, 300, 200))); - CPPUNIT_ASSERT( tree1.isValueOn(openvdb::Coord( 500, 300, 200))); - CPPUNIT_ASSERT( tree1.isValueOn(openvdb::Coord( 8, 11, 11))); - - tree1.topologyDifference(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT( tree0.isValueOn(openvdb::Coord( 500, 300, 200))); - CPPUNIT_ASSERT(!tree1.isValueOn(openvdb::Coord( 500, 300, 200))); - CPPUNIT_ASSERT( tree1.isValueOn(openvdb::Coord( 8, 11, 11))); - - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - } - {//4 overlapping voxels - const ValueType background=0.0f; - openvdb::FloatTree tree0(background), tree1(background); - tree0.setValue(openvdb::Coord( 500, 300, 200), 1.0f); - tree0.setValue(openvdb::Coord( 400, 30, 20), 2.0f); - tree0.setValue(openvdb::Coord( 8, 11, 11), 3.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree0.leafCount() ); - - tree1.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree1.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree1.setValue(openvdb::Coord( 8, 11, 11), 6.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree1.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree1.leafCount() ); - - tree1.topologyDifference(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(3), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT(!tree1.empty()); - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(1), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree1.activeVoxelCount() ); - } - {//passive tile - const ValueType background=0.0f; - const openvdb::Index64 dim = openvdb::FloatTree::RootNodeType::ChildNodeType::DIM; - openvdb::FloatTree tree0(background), tree1(background); - tree0.fill(openvdb::CoordBBox(openvdb::Coord(0),openvdb::Coord(dim-1)),2.0f, false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(0), tree0.activeVoxelCount()); - CPPUNIT_ASSERT(!tree0.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(0), tree0.root().onTileCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree0.leafCount() ); - - tree1.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree1.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree1.setValue(openvdb::Coord( dim, 11, 11), 6.0f); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree1.activeVoxelCount()); - CPPUNIT_ASSERT(!tree1.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree1.leafCount() ); - - tree1.topologyDifference(tree0); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(3), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(3), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(3), tree1.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(3), tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - } - {//active tile - const ValueType background=0.0f; - const openvdb::Index64 dim = openvdb::FloatTree::RootNodeType::ChildNodeType::DIM; - openvdb::FloatTree tree0(background), tree1(background); - tree1.fill(openvdb::CoordBBox(openvdb::Coord(0),openvdb::Coord(dim-1)),2.0f, true); - CPPUNIT_ASSERT_EQUAL(dim*dim*dim, tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree1.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree1.root().onTileCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree0.leafCount() ); - - tree0.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree0.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree0.setValue(openvdb::Coord( int(dim), 11, 11), 6.0f); - CPPUNIT_ASSERT(!tree0.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree0.leafCount() ); - CPPUNIT_ASSERT( tree0.isValueOn(openvdb::Coord( int(dim), 11, 11))); - CPPUNIT_ASSERT(!tree1.isValueOn(openvdb::Coord( int(dim), 11, 11))); - - tree1.topologyDifference(tree0); - - CPPUNIT_ASSERT(tree1.root().onTileCount() > 1); - CPPUNIT_ASSERT_EQUAL( dim*dim*dim - 2, tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - openvdb::tools::pruneInactive(tree1); - CPPUNIT_ASSERT_EQUAL( dim*dim*dim - 2, tree1.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - } - {//active tile - const ValueType background=0.0f; - const openvdb::Index64 dim = openvdb::FloatTree::RootNodeType::ChildNodeType::DIM; - openvdb::FloatTree tree0(background), tree1(background); - tree1.fill(openvdb::CoordBBox(openvdb::Coord(0),openvdb::Coord(dim-1)),2.0f, true); - CPPUNIT_ASSERT_EQUAL(dim*dim*dim, tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree1.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(1), tree1.root().onTileCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree0.leafCount() ); - - tree0.setValue(openvdb::Coord( 500, 301, 200), 4.0f); - tree0.setValue(openvdb::Coord( 400, 30, 20), 5.0f); - tree0.setValue(openvdb::Coord( dim, 11, 11), 6.0f); - CPPUNIT_ASSERT(!tree0.hasActiveTiles()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(3), tree0.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree0.leafCount() ); - - tree0.topologyDifference(tree1); - - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(1), tree0.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree0.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree0.empty()); - openvdb::tools::pruneInactive(tree0); - CPPUNIT_ASSERT_EQUAL( openvdb::Index32(1), tree0.leafCount() ); - CPPUNIT_ASSERT_EQUAL( openvdb::Index64(1), tree0.activeVoxelCount() ); - CPPUNIT_ASSERT(!tree1.empty()); - } - {// use tree with different voxel type - ValueType background=5.0f; - openvdb::FloatTree tree0(background), tree1(background), tree2(background); - CPPUNIT_ASSERT(tree2.empty()); - // tree0 = tree1.topologyIntersection(tree2) - tree0.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree0.setValue(openvdb::Coord(-5, 10,-20),0.1f); - tree0.setValue(openvdb::Coord( 5,-10,-20),0.2f); - tree0.setValue(openvdb::Coord(-5,-10,-20),0.3f); - - tree1.setValue(openvdb::Coord( 5, 10, 20),0.0f); - tree1.setValue(openvdb::Coord(-5, 10,-20),0.1f); - tree1.setValue(openvdb::Coord( 5,-10,-20),0.2f); - tree1.setValue(openvdb::Coord(-5,-10,-20),0.3f); - - tree2.setValue(openvdb::Coord( 5, 10, 20),0.4f); - tree2.setValue(openvdb::Coord(-5, 10,-20),0.5f); - tree2.setValue(openvdb::Coord( 5,-10,-20),0.6f); - tree2.setValue(openvdb::Coord(-5,-10,-20),0.7f); - - tree2.setValue(openvdb::Coord(-5000, 2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord( 5000,-2000,-3000),4.5678f); - tree2.setValue(openvdb::Coord(-5000,-2000, 3000),4.5678f); - - openvdb::FloatTree tree1_copy(tree1); - - // tree3 has the same topology as tree2 but a different value type - const openvdb::Vec3f background2(1.0f,3.4f,6.0f), vec_val(3.1f,5.3f,-9.5f); - openvdb::Vec3fTree tree3(background2); - for (openvdb::FloatTree::ValueOnCIter iter = tree2.cbeginValueOn(); iter; ++iter) { - tree3.setValue(iter.getCoord(), vec_val); - } - - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(4), tree0.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(4), tree1.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree2.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree3.leafCount()); - - - //tree1.topologyInterection(tree2);//should make tree1 = tree0 - tree1.topologyIntersection(tree3);//should make tree1 = tree0 - - CPPUNIT_ASSERT(tree0.leafCount()==tree1.leafCount()); - CPPUNIT_ASSERT(tree0.nonLeafCount()==tree1.nonLeafCount()); - CPPUNIT_ASSERT(tree0.activeLeafVoxelCount()==tree1.activeLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveLeafVoxelCount()==tree1.inactiveLeafVoxelCount()); - CPPUNIT_ASSERT(tree0.activeVoxelCount()==tree1.activeVoxelCount()); - CPPUNIT_ASSERT(tree0.inactiveVoxelCount()==tree1.inactiveVoxelCount()); - CPPUNIT_ASSERT(tree1.hasSameTopology(tree0)); - CPPUNIT_ASSERT(tree0.hasSameTopology(tree1)); - - for (openvdb::FloatTree::ValueOnCIter iter = tree0.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree1.isValueOn(p)); - CPPUNIT_ASSERT(tree2.isValueOn(p)); - CPPUNIT_ASSERT(tree3.isValueOn(p)); - CPPUNIT_ASSERT(tree1_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree1.getValue(p)); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1_copy.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT(tree1.isValueOn(iter.getCoord())); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree1.getValue(iter.getCoord())); - } - for (openvdb::FloatTree::ValueOnCIter iter = tree1.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree0.isValueOn(p)); - CPPUNIT_ASSERT(tree2.isValueOn(p)); - CPPUNIT_ASSERT(tree3.isValueOn(p)); - CPPUNIT_ASSERT(tree1_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter,tree0.getValue(p)); - } - } - {// test overlapping spheres - const float background=5.0f, R0=10.0f, R1=5.6f; - const openvdb::Vec3f C0(35.0f, 30.0f, 40.0f), C1(22.3f, 30.5f, 31.0f); - const openvdb::Coord dim(32, 32, 32); - openvdb::FloatGrid grid0(background); - openvdb::FloatGrid grid1(background); - unittest_util::makeSphere(dim, C0, R0, grid0, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - unittest_util::makeSphere(dim, C1, R1, grid1, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - openvdb::FloatTree& tree0 = grid0.tree(); - openvdb::FloatTree& tree1 = grid1.tree(); - openvdb::FloatTree tree0_copy(tree0); - - tree0.topologyDifference(tree1); - - const openvdb::Index64 n0 = tree0_copy.activeVoxelCount(); - const openvdb::Index64 n = tree0.activeVoxelCount(); - - CPPUNIT_ASSERT( n < n0 ); - - for (openvdb::FloatTree::ValueOnCIter iter = tree0.cbeginValueOn(); iter; ++iter) { - const openvdb::Coord p = iter.getCoord(); - CPPUNIT_ASSERT(tree1.isValueOff(p)); - CPPUNIT_ASSERT(tree0_copy.isValueOn(p)); - ASSERT_DOUBLES_EXACTLY_EQUAL(*iter, tree0_copy.getValue(p)); - } - } -}// testTopologyDifference - -void -TestTree::testSignedFloodFill() -{ - // Use a custom tree configuration to ensure we flood-fill at all levels! - typedef openvdb::tree::LeafNode LeafT;//4^3 - typedef openvdb::tree::InternalNode InternalT;//4^3 - typedef openvdb::tree::RootNode RootT;// child nodes are 16^3 - typedef openvdb::tree::Tree TreeT; - - const float outside = 2.0f, inside = -outside, radius = 20.0f; - - {//first test flood filling of a leaf node - - const LeafT::ValueType fill0=5, fill1=-fill0; - openvdb::tools::SignedFloodFillOp sff(fill0, fill1); - - int D = LeafT::dim(), C=D/2; - openvdb::Coord origin(0,0,0), left(0,0,C-1), right(0,0,C); - LeafT leaf(origin,fill0); - for (int i=0; i::Ptr grid = openvdb::Grid::create(outside); - TreeT& tree = grid->tree(); - const RootT& root = tree.root(); - const openvdb::Coord dim(3*16, 3*16, 3*16); - const openvdb::Coord C(16+8,16+8,16+8); - - CPPUNIT_ASSERT(!tree.isValueOn(C)); - CPPUNIT_ASSERT(root.getTableSize()==0); - - //make narrow band of sphere without setting sign for the background values! - openvdb::Grid::Accessor acc = grid->getAccessor(); - const openvdb::Vec3f center(static_cast(C[0]), - static_cast(C[1]), - static_cast(C[2])); - openvdb::Coord xyz; - for (xyz[0]=0; xyz[0]transform().indexToWorld(xyz); - const float dist = float((p-center).length() - radius); - if (fabs(dist) > outside) continue; - acc.setValue(xyz, dist); - } - } - } - // Check narrow band with incorrect background - const size_t size_before = root.getTableSize(); - CPPUNIT_ASSERT(size_before>0); - CPPUNIT_ASSERT(!tree.isValueOn(C)); - ASSERT_DOUBLES_EXACTLY_EQUAL(outside,tree.getValue(C)); - for (xyz[0]=0; xyz[0]transform().indexToWorld(xyz); - const float dist = float((p-center).length() - radius); - const float val = acc.getValue(xyz); - if (dist < inside) { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, outside); - } else if (dist>outside) { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, outside); - } else { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, dist ); - } - } - } - } - - CPPUNIT_ASSERT(tree.getValueDepth(C) == -1);//i.e. background value - openvdb::tools::signedFloodFill(tree); - CPPUNIT_ASSERT(tree.getValueDepth(C) == 0);//added inside tile to root - - // Check narrow band with correct background - for (xyz[0]=0; xyz[0]transform().indexToWorld(xyz); - const float dist = float((p-center).length() - radius); - const float val = acc.getValue(xyz); - if (dist < inside) { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, inside); - } else if (dist>outside) { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, outside); - } else { - ASSERT_DOUBLES_EXACTLY_EQUAL( val, dist ); - } - } - } - } - - CPPUNIT_ASSERT(root.getTableSize()>size_before);//added inside root tiles - CPPUNIT_ASSERT(!tree.isValueOn(C)); - ASSERT_DOUBLES_EXACTLY_EQUAL(inside,tree.getValue(C)); -} - - -void -TestTree::testPruneInactive() -{ - using openvdb::Coord; - using openvdb::Index32; - using openvdb::Index64; - - const float background = 5.0; - - openvdb::FloatTree tree(background); - - // Verify that the newly-constructed tree is empty and that pruning it has no effect. - CPPUNIT_ASSERT(tree.empty()); - openvdb::tools::prune(tree); - CPPUNIT_ASSERT(tree.empty()); - openvdb::tools::pruneInactive(tree); - CPPUNIT_ASSERT(tree.empty()); - - // Set some active values. - tree.setValue(Coord(-5, 10, 20), 0.1f); - tree.setValue(Coord(-5,-10, 20), 0.4f); - tree.setValue(Coord(-5, 10,-20), 0.5f); - tree.setValue(Coord(-5,-10,-20), 0.7f); - tree.setValue(Coord( 5, 10, 20), 0.0f); - tree.setValue(Coord( 5,-10, 20), 0.2f); - tree.setValue(Coord( 5,-10,-20), 0.6f); - tree.setValue(Coord( 5, 10,-20), 0.3f); - // Verify that the tree has the expected numbers of active voxels and leaf nodes. - CPPUNIT_ASSERT_EQUAL(Index64(8), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(8), tree.leafCount()); - - // Verify that prune() has no effect, since the values are all different. - openvdb::tools::prune(tree); - CPPUNIT_ASSERT_EQUAL(Index64(8), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(8), tree.leafCount()); - // Verify that pruneInactive() has no effect, since the values are active. - openvdb::tools::pruneInactive(tree); - CPPUNIT_ASSERT_EQUAL(Index64(8), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(8), tree.leafCount()); - - // Make some of the active values inactive, without changing their values. - tree.setValueOff(Coord(-5, 10, 20)); - tree.setValueOff(Coord(-5,-10, 20)); - tree.setValueOff(Coord(-5, 10,-20)); - tree.setValueOff(Coord(-5,-10,-20)); - CPPUNIT_ASSERT_EQUAL(Index64(4), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(8), tree.leafCount()); - // Verify that prune() has no effect, since the values are still different. - openvdb::tools::prune(tree); - CPPUNIT_ASSERT_EQUAL(Index64(4), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(8), tree.leafCount()); - // Verify that pruneInactive() prunes the nodes containing only inactive voxels. - openvdb::tools::pruneInactive(tree); - CPPUNIT_ASSERT_EQUAL(Index64(4), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(4), tree.leafCount()); - - // Make all of the active values inactive, without changing their values. - tree.setValueOff(Coord( 5, 10, 20)); - tree.setValueOff(Coord( 5,-10, 20)); - tree.setValueOff(Coord( 5,-10,-20)); - tree.setValueOff(Coord( 5, 10,-20)); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(4), tree.leafCount()); - // Verify that prune() has no effect, since the values are still different. - openvdb::tools::prune(tree); - CPPUNIT_ASSERT_EQUAL(Index64(0), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Index32(4), tree.leafCount()); - // Verify that pruneInactive() prunes all of the remaining leaf nodes. - openvdb::tools::pruneInactive(tree); - CPPUNIT_ASSERT(tree.empty()); -} - -void -TestTree::testPruneLevelSet() -{ - const float background=10.0f, R=5.6f; - const openvdb::Vec3f C(12.3f, 15.5f, 10.0f); - const openvdb::Coord dim(32, 32, 32); - - openvdb::FloatGrid grid(background); - unittest_util::makeSphere(dim, C, R, grid, - 1.0f, unittest_util::SPHERE_SPARSE_NARROW_BAND); - openvdb::FloatTree& tree = grid.tree(); - - openvdb::Index64 count = 0; - openvdb::Coord xyz; - for (xyz[0]=0; xyz[0]beginValueOn(); vIter; ++vIter) { - if (fabs(*vIter)setValueOff(vIter.pos(), *vIter > 0.0f ? background : -background); - ++removed; - } - } - // The following version is slower since it employs - // FloatTree::ValueOnIter that visits both tiles and voxels and - // also uses random acceess to set the voxels off. - /* - for (openvdb::FloatTree::ValueOnIter i = tree.beginValueOn(); i; ++i) { - if (fabs(*i) 0.0f ? background : -background); - ++removed2; - } - */ - - CPPUNIT_ASSERT_EQUAL(leafCount, tree.leafCount()); - //std::cerr << "Leaf count=" << tree.leafCount() << std::endl; - CPPUNIT_ASSERT_EQUAL(tree.activeVoxelCount(), count-removed); - CPPUNIT_ASSERT_EQUAL(tree.activeLeafVoxelCount(), count-removed); - - openvdb::tools::pruneLevelSet(tree); - - CPPUNIT_ASSERT(tree.leafCount() < leafCount); - //std::cerr << "Leaf count=" << tree.leafCount() << std::endl; - CPPUNIT_ASSERT_EQUAL(tree.activeVoxelCount(), count-removed); - CPPUNIT_ASSERT_EQUAL(tree.activeLeafVoxelCount(), count-removed); - - openvdb::FloatTree::ValueOnCIter i = tree.cbeginValueOn(); - for (; i; ++i) CPPUNIT_ASSERT( *i < new_width); - - for (xyz[0]=0; xyz[0]getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - CPPUNIT_ASSERT(tree->touchLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(!tree->isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree->getValue(xyz)); - } - {// test accessor - openvdb::FloatTree::Ptr tree(new openvdb::FloatTree(background)); - openvdb::tree::ValueAccessor acc(*tree); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - CPPUNIT_ASSERT(acc.touchLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(!acc.isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, acc.getValue(xyz)); - } -} - - -void -TestTree::testProbeLeaf() -{ - const float background=10.0f, value = 2.0f; - const openvdb::Coord xyz(-20,30,10); - {// test Tree::probeLeaf - openvdb::FloatTree::Ptr tree(new openvdb::FloatTree(background)); - CPPUNIT_ASSERT_EQUAL(-1, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - CPPUNIT_ASSERT(tree->probeLeaf(xyz)==NULL); - CPPUNIT_ASSERT_EQUAL(-1, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - tree->setValue(xyz, value); - CPPUNIT_ASSERT_EQUAL( 3, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(tree->probeLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, tree->getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(tree->isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree->getValue(xyz)); - } - {// test Tree::probeConstLeaf - const openvdb::FloatTree tree1(background); - CPPUNIT_ASSERT_EQUAL(-1, tree1.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree1.leafCount())); - CPPUNIT_ASSERT(tree1.probeConstLeaf(xyz)==NULL); - CPPUNIT_ASSERT_EQUAL(-1, tree1.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree1.leafCount())); - openvdb::FloatTree tmp(tree1); - tmp.setValue(xyz, value); - const openvdb::FloatTree tree2(tmp); - CPPUNIT_ASSERT_EQUAL( 3, tree2.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree2.leafCount())); - CPPUNIT_ASSERT(tree2.probeConstLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, tree2.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree2.leafCount())); - CPPUNIT_ASSERT(tree2.isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree2.getValue(xyz)); - } - {// test ValueAccessor::probeLeaf - openvdb::FloatTree::Ptr tree(new openvdb::FloatTree(background)); - openvdb::tree::ValueAccessor acc(*tree); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - CPPUNIT_ASSERT(acc.probeLeaf(xyz)==NULL); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree->leafCount())); - acc.setValue(xyz, value); - CPPUNIT_ASSERT_EQUAL( 3, acc.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(acc.probeLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, acc.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree->leafCount())); - CPPUNIT_ASSERT(acc.isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(xyz)); - } - {// test ValueAccessor::probeConstLeaf - const openvdb::FloatTree tree1(background); - openvdb::tree::ValueAccessor acc1(tree1); - CPPUNIT_ASSERT_EQUAL(-1, acc1.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree1.leafCount())); - CPPUNIT_ASSERT(acc1.probeConstLeaf(xyz)==NULL); - CPPUNIT_ASSERT_EQUAL(-1, acc1.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 0, int(tree1.leafCount())); - openvdb::FloatTree tmp(tree1); - tmp.setValue(xyz, value); - const openvdb::FloatTree tree2(tmp); - openvdb::tree::ValueAccessor acc2(tree2); - CPPUNIT_ASSERT_EQUAL( 3, acc2.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree2.leafCount())); - CPPUNIT_ASSERT(acc2.probeConstLeaf(xyz)!=NULL); - CPPUNIT_ASSERT_EQUAL( 3, acc2.getValueDepth(xyz)); - CPPUNIT_ASSERT_EQUAL( 1, int(tree2.leafCount())); - CPPUNIT_ASSERT(acc2.isValueOn(xyz)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc2.getValue(xyz)); - } -} - - -void -TestTree::testAddLeaf() -{ - using namespace openvdb; - - typedef FloatTree::LeafNodeType LeafT; - - const Coord ijk(100); - FloatGrid grid; - FloatTree& tree = grid.tree(); - - tree.setValue(ijk, 5.0); - const LeafT* oldLeaf = tree.probeLeaf(ijk); - CPPUNIT_ASSERT(oldLeaf != NULL); - ASSERT_DOUBLES_EXACTLY_EQUAL(5.0, oldLeaf->getValue(ijk)); - - LeafT* newLeaf = new LeafT; - newLeaf->setOrigin(oldLeaf->origin()); - newLeaf->fill(3.0); - - tree.addLeaf(*newLeaf); - CPPUNIT_ASSERT_EQUAL(newLeaf, tree.probeLeaf(ijk)); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.0, tree.getValue(ijk)); -} - - -void -TestTree::testAddTile() -{ - using namespace openvdb; - - const Coord ijk(100); - FloatGrid grid; - FloatTree& tree = grid.tree(); - - tree.setValue(ijk, 5.0); - CPPUNIT_ASSERT(tree.probeLeaf(ijk) != NULL); - - const Index lvl = FloatTree::DEPTH >> 1; - if (lvl > 0) tree.addTile(lvl,ijk, 3.0, /*active=*/true); - else tree.addTile(1,ijk, 3.0, /*active=*/true); - - CPPUNIT_ASSERT(tree.probeLeaf(ijk) == NULL); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.0, tree.getValue(ijk)); -} - - -struct BBoxOp -{ - std::vector bbox; - std::vector level; - - // This method is required by Tree::visitActiveBBox - // Since it will return false if LEVEL==0 it will never descent to - // the active voxels. In other words the smallest BBoxes - // correspond to LeafNodes or active tiles at LEVEL=1 - template - inline bool descent() { return LEVEL>0; } - - // This method is required by Tree::visitActiveBBox - template - inline void operator()(const openvdb::CoordBBox &_bbox) { - bbox.push_back(_bbox); - level.push_back(LEVEL); - } -}; - -void -TestTree::testProcessBBox() -{ - using openvdb::Coord; - using openvdb::CoordBBox; - //check two leaf nodes and two tiles at each level 1, 2 and 3 - const int size[4]={1<<3, 1<<3, 1<<(3+4), 1<<(3+4+5)}; - for (int level=0; level<=3; ++level) { - openvdb::FloatTree tree; - const int n = size[level]; - const CoordBBox bbox[]={CoordBBox::createCube(Coord(-n,-n,-n), n), - CoordBBox::createCube(Coord( 0, 0, 0), n)}; - if (level==0) { - tree.setValue(Coord(-1,-2,-3), 1.0f); - tree.setValue(Coord( 1, 2, 3), 1.0f); - } else { - tree.fill(bbox[0], 1.0f, true); - tree.fill(bbox[1], 1.0f, true); - } - BBoxOp op; - tree.visitActiveBBox(op); - CPPUNIT_ASSERT_EQUAL(2, int(op.bbox.size())); - - for (int i=0; i<2; ++i) { - //std::cerr <<"\nLevel="< and Tree::getNodes()"); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(leafCount, array.size()); - size_t sum = 0; - for (size_t i=0; ionVoxelCount(); - CPPUNIT_ASSERT_EQUAL(voxelCount, sum); - } - {//testing Tree::getNodes() with std::vector - std::vector array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::vector and Tree::getNodes()"); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(leafCount, array.size()); - size_t sum = 0; - for (size_t i=0; ionVoxelCount(); - CPPUNIT_ASSERT_EQUAL(voxelCount, sum); - } - {//testing Tree::getNodes() const with std::vector - std::vector array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::vector and Tree::getNodes() const"); - const FloatTree& tmp = tree; - tmp.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(leafCount, array.size()); - size_t sum = 0; - for (size_t i=0; ionVoxelCount(); - CPPUNIT_ASSERT_EQUAL(voxelCount, sum); - } - {//testing Tree::getNodes() with std::vector and std::vector::reserve - std::vector array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::vector, std::vector::reserve and Tree::getNodes"); - array.reserve(tree.leafCount()); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(leafCount, array.size()); - size_t sum = 0; - for (size_t i=0; ionVoxelCount(); - CPPUNIT_ASSERT_EQUAL(voxelCount, sum); - } - {//testing Tree::getNodes() with std::deque - std::deque array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::deque and Tree::getNodes"); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(leafCount, array.size()); - size_t sum = 0; - for (size_t i=0; ionVoxelCount(); - CPPUNIT_ASSERT_EQUAL(voxelCount, sum); - } - {//testing Tree::getNodes() with std::deque - std::deque array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::deque and Tree::getNodes"); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(size_t(1), array.size()); - } - {//testing Tree::getNodes() with std::deque - std::deque array; - CPPUNIT_ASSERT_EQUAL(size_t(0), array.size()); - //timer.start("\nstd::deque and Tree::getNodes"); - tree.getNodes(array); - //timer.stop(); - CPPUNIT_ASSERT_EQUAL(size_t(1), array.size()); - } - /* - {//testing Tree::getNodes() with std::deque where T is not part of the tree configuration - typedef openvdb::tree::LeafNode NodeT; - std::deque array; - tree.getNodes(array);//should NOT compile since NodeT is not part of the FloatTree configuration - } - {//testing Tree::getNodes() const with std::deque where T is not part of the tree configuration - typedef openvdb::tree::LeafNode NodeT; - std::deque array; - const FloatTree& tmp = tree; - tmp.getNodes(array);//should NOT compile since NodeT is not part of the FloatTree configuration - } - */ -}// testGetNodes - -void -TestTree::testLeafManager() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Vec3f; - using openvdb::FloatGrid; - using openvdb::FloatTree; - - const Vec3f center(0.35f, 0.35f, 0.35f); - const float radius = 0.15f; - const int dim = 128, half_width = 5; - const float voxel_size = 1.0f/dim; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/half_width*voxel_size); - FloatTree& tree = grid->tree(); - grid->setTransform(openvdb::math::Transform::createLinearTransform(/*voxel size=*/voxel_size)); - - unittest_util::makeSphere( - Coord(dim), center, radius, *grid, unittest_util::SPHERE_SPARSE_NARROW_BAND); - const size_t leafCount = tree.leafCount(); - - //grid->print(std::cout, 3); - {// test with no aux buffers - openvdb::tree::LeafManager r(tree); - CPPUNIT_ASSERT_EQUAL(leafCount, r.leafCount()); - CPPUNIT_ASSERT_EQUAL(size_t(0), r.auxBufferCount()); - CPPUNIT_ASSERT_EQUAL(size_t(0), r.auxBuffersPerLeaf()); - size_t n = 0; - for (FloatTree::LeafCIter iter=tree.cbeginLeaf(); iter; ++iter, ++n) { - CPPUNIT_ASSERT(r.leaf(n) == *iter); - CPPUNIT_ASSERT(r.getBuffer(n,0) == iter->buffer()); - } - CPPUNIT_ASSERT_EQUAL(r.leafCount(), n); - CPPUNIT_ASSERT(!r.swapBuffer(0,0)); - - r.rebuildAuxBuffers(2); - - CPPUNIT_ASSERT_EQUAL(leafCount, r.leafCount()); - CPPUNIT_ASSERT_EQUAL(size_t(2), r.auxBuffersPerLeaf()); - CPPUNIT_ASSERT_EQUAL(size_t(2*leafCount),r.auxBufferCount()); - - for (n=0; n r(tree, 2); - CPPUNIT_ASSERT_EQUAL(leafCount, r.leafCount()); - CPPUNIT_ASSERT_EQUAL(size_t(2), r.auxBuffersPerLeaf()); - CPPUNIT_ASSERT_EQUAL(size_t(2*leafCount),r.auxBufferCount()); - size_t n = 0; - for (FloatTree::LeafCIter iter=tree.cbeginLeaf(); iter; ++iter, ++n) { - CPPUNIT_ASSERT(r.leaf(n) == *iter); - CPPUNIT_ASSERT(r.getBuffer(n,0) == iter->buffer()); - - CPPUNIT_ASSERT(r.getBuffer(n,0) == r.getBuffer(n,1)); - CPPUNIT_ASSERT(r.getBuffer(n,1) == r.getBuffer(n,2)); - CPPUNIT_ASSERT(r.getBuffer(n,0) == r.getBuffer(n,2)); - } - CPPUNIT_ASSERT_EQUAL(r.leafCount(), n); - for (n=0; n r(tree); - - for (size_t numAuxBuffers = 0; numAuxBuffers <= 2; ++numAuxBuffers += 2) { - r.rebuildAuxBuffers(numAuxBuffers); - - CPPUNIT_ASSERT_EQUAL(leafCount, r.leafCount()); - CPPUNIT_ASSERT_EQUAL(int(numAuxBuffers * leafCount), int(r.auxBufferCount())); - CPPUNIT_ASSERT_EQUAL(numAuxBuffers, r.auxBuffersPerLeaf()); - - size_t n = 0; - for (FloatTree::LeafCIter iter = tree.cbeginLeaf(); iter; ++iter, ++n) { - CPPUNIT_ASSERT(r.leaf(n) == *iter); - // Verify that each aux buffer was initialized with a copy of the leaf buffer. - for (size_t bufIdx = 0; bufIdx < numAuxBuffers; ++bufIdx) { - CPPUNIT_ASSERT(r.getBuffer(n, bufIdx) == iter->buffer()); - } - } - CPPUNIT_ASSERT_EQUAL(r.leafCount(), n); - - for (size_t i = 0; i < numAuxBuffers; ++i) { - for (size_t j = 0; j < numAuxBuffers; ++j) { - // Verify that swapping buffers with themselves and swapping - // leaf buffers with aux buffers have no effect. - const bool canSwap = (i != j && i != 0 && j != 0); - CPPUNIT_ASSERT_EQUAL(canSwap, r.swapBuffer(i, j)); - } - } - } - } -} - -void -TestTree::testNodeManager() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - using openvdb::Vec3f; - using openvdb::Index64; - using openvdb::FloatGrid; - using openvdb::FloatTree; - - const Vec3f center(0.35f, 0.35f, 0.35f); - const float radius = 0.15f; - const int dim = 128, half_width = 5; - const float voxel_size = 1.0f/dim; - - FloatGrid::Ptr grid = FloatGrid::create(/*background=*/half_width*voxel_size); - FloatTree& tree = grid->tree(); - grid->setTransform(openvdb::math::Transform::createLinearTransform(/*voxel size=*/voxel_size)); - - unittest_util::makeSphere(Coord(dim), center, - radius, *grid, unittest_util::SPHERE_SPARSE_NARROW_BAND); - - CPPUNIT_ASSERT_EQUAL(4, int(FloatTree::DEPTH)); - CPPUNIT_ASSERT_EQUAL(3, int(openvdb::tree::NodeManager::LEVELS)); - - std::vector nodeCount; - for (openvdb::Index i=0; i -#include -#include -#include -#include -#include "util.h" // for unittest_util::makeSphere() -#include // for std::numeric_limits -#include // for boost::math::isnan() and isinf() - -#define TEST_CSG_VERBOSE 0 - -#if TEST_CSG_VERBOSE -#include -#endif - -namespace { -typedef openvdb::tree::Tree4::Type Float433Tree; -typedef openvdb::Grid Float433Grid; -} - - -class TestTreeCombine: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); Float433Grid::registerGrid(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestTreeCombine); - CPPUNIT_TEST(testCombine); - CPPUNIT_TEST(testCombine2); - CPPUNIT_TEST(testCompMax); - CPPUNIT_TEST(testCompMin); - CPPUNIT_TEST(testCompSum); - CPPUNIT_TEST(testCompProd); - CPPUNIT_TEST(testCompDiv); - CPPUNIT_TEST(testCompDivByZero); - CPPUNIT_TEST(testCompReplace); - CPPUNIT_TEST(testBoolTree); -#ifdef DWA_OPENVDB - CPPUNIT_TEST(testCsg); -#endif - CPPUNIT_TEST_SUITE_END(); - - void testCombine(); - void testCombine2(); - void testCompMax(); - void testCompMin(); - void testCompSum(); - void testCompProd(); - void testCompDiv(); - void testCompDivByZero(); - void testCompReplace(); - void testBoolTree(); - void testCsg(); - -private: - template - void testComp(const TreeComp&, const ValueComp&); - - template - void testCompRepl(); - - template - typename TreeT::Ptr - visitCsg(const TreeT& a, const TreeT& b, const TreeT& ref, const VisitorT&); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTreeCombine); - - -//////////////////////////////////////// - - -namespace { -namespace Local { - -template -struct OrderDependentCombineOp { - OrderDependentCombineOp() {} - void operator()(const ValueT& a, const ValueT& b, ValueT& result) const { - result = a + 100 * b; // result is order-dependent on A and B - } -}; - -/// Test Tree::combine(), which takes a functor that accepts three arguments -/// (the a, b and result values). -template -void combine(TreeT& a, TreeT& b) -{ - a.combine(b, OrderDependentCombineOp()); -} - -/// Test Tree::combineExtended(), which takes a functor that accepts a single -/// CombineArgs argument, in which the functor can return a computed active state -/// for the output value. -template -void extendedCombine(TreeT& a, TreeT& b) -{ - typedef typename TreeT::ValueType ValueT; - struct ArgsOp { - static void order(openvdb::CombineArgs& args) { - // The result is order-dependent on A and B. - args.setResult(args.a() + 100 * args.b()); - args.setResultIsActive(args.aIsActive() || args.bIsActive()); - } - }; - a.combineExtended(b, ArgsOp::order); -} - -template void compMax(TreeT& a, TreeT& b) { openvdb::tools::compMax(a, b); } -template void compMin(TreeT& a, TreeT& b) { openvdb::tools::compMin(a, b); } -template void compSum(TreeT& a, TreeT& b) { openvdb::tools::compSum(a, b); } -template void compMul(TreeT& a, TreeT& b) { openvdb::tools::compMul(a, b); }\ -template void compDiv(TreeT& a, TreeT& b) { openvdb::tools::compDiv(a, b); }\ - -float orderf(float a, float b) { return a + 100 * b; } -float maxf(float a, float b) { return std::max(a, b); } -float minf(float a, float b) { return std::min(a, b); } -float sumf(float a, float b) { return a + b; } -float mulf(float a, float b) { return a * b; } -float divf(float a, float b) { return a / b; } - -openvdb::Vec3f orderv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { return a + 100 * b; } -openvdb::Vec3f maxv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { - const float aMag = a.lengthSqr(), bMag = b.lengthSqr(); - return (aMag > bMag ? a : (bMag > aMag ? b : std::max(a, b))); -} -openvdb::Vec3f minv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { - const float aMag = a.lengthSqr(), bMag = b.lengthSqr(); - return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b))); -} -openvdb::Vec3f sumv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { return a + b; } -openvdb::Vec3f mulv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { return a * b; } -openvdb::Vec3f divv(const openvdb::Vec3f& a, const openvdb::Vec3f& b) { return a / b; } - -} // namespace Local -} // unnamed namespace - - -void -TestTreeCombine::testCombine() -{ - testComp(Local::combine, Local::orderf); - testComp(Local::combine, Local::orderv); - - testComp(Local::extendedCombine, Local::orderf); - testComp(Local::extendedCombine, Local::orderv); -} - - -void -TestTreeCombine::testCompMax() -{ - testComp(Local::compMax, Local::maxf); - testComp(Local::compMax, Local::maxv); -} - - -void -TestTreeCombine::testCompMin() -{ - testComp(Local::compMin, Local::minf); - testComp(Local::compMin, Local::minv); -} - - -void -TestTreeCombine::testCompSum() -{ - testComp(Local::compSum, Local::sumf); - testComp(Local::compSum, Local::sumv); -} - - -void -TestTreeCombine::testCompProd() -{ - testComp(Local::compMul, Local::mulf); - testComp(Local::compMul, Local::mulv); -} - - -void -TestTreeCombine::testCompDiv() -{ - testComp(Local::compDiv, Local::divf); - testComp(Local::compDiv, Local::divv); -} - - -void -TestTreeCombine::testCompDivByZero() -{ - const openvdb::Coord c0(0), c1(1), c2(2), c3(3), c4(4); - - // Verify that integer-valued grids behave well w.r.t. division by zero. - { - const openvdb::Int32 inf = std::numeric_limits::max(); - - openvdb::Int32Tree a(/*background=*/1), b(0); - - a.setValueOn(c0); - a.setValueOn(c1); - a.setValueOn(c2, -1); - a.setValueOn(c3, -1); - a.setValueOn(c4, 0); - b.setValueOn(c1); - b.setValueOn(c3); - - openvdb::tools::compDiv(a, b); - - CPPUNIT_ASSERT_EQUAL( inf, a.getValue(c0)); // 1 / 0 - CPPUNIT_ASSERT_EQUAL( inf, a.getValue(c1)); // 1 / 0 - CPPUNIT_ASSERT_EQUAL(-inf, a.getValue(c2)); // -1 / 0 - CPPUNIT_ASSERT_EQUAL(-inf, a.getValue(c3)); // -1 / 0 - CPPUNIT_ASSERT_EQUAL( 0, a.getValue(c4)); // 0 / 0 - } - { - const openvdb::Index32 zero(0), inf = std::numeric_limits::max(); - - openvdb::UInt32Tree a(/*background=*/1), b(0); - - a.setValueOn(c0); - a.setValueOn(c1); - a.setValueOn(c2, zero); - b.setValueOn(c1); - - openvdb::tools::compDiv(a, b); - - CPPUNIT_ASSERT_EQUAL( inf, a.getValue(c0)); // 1 / 0 - CPPUNIT_ASSERT_EQUAL( inf, a.getValue(c1)); // 1 / 0 - CPPUNIT_ASSERT_EQUAL(zero, a.getValue(c2)); // 0 / 0 - } - - // Verify that non-integer-valued grids don't use integer division semantics. - { - openvdb::FloatTree a(/*background=*/1.0), b(0.0); - - a.setValueOn(c0); - a.setValueOn(c1); - a.setValueOn(c2, -1.0); - a.setValueOn(c3, -1.0); - a.setValueOn(c4, 0.0); - b.setValueOn(c1); - b.setValueOn(c3); - - openvdb::tools::compDiv(a, b); - - CPPUNIT_ASSERT(boost::math::isinf(a.getValue(c0))); // 1 / 0 - CPPUNIT_ASSERT(boost::math::isinf(a.getValue(c1))); // 1 / 0 - CPPUNIT_ASSERT(boost::math::isinf(a.getValue(c2))); // -1 / 0 - CPPUNIT_ASSERT(boost::math::isinf(a.getValue(c3))); // -1 / 0 - CPPUNIT_ASSERT(boost::math::isnan(a.getValue(c4))); // 0 / 0 - } -} - - -void -TestTreeCombine::testCompReplace() -{ - testCompRepl(); - testCompRepl(); -} - - -template -void -TestTreeCombine::testComp(const TreeComp& comp, const ValueComp& op) -{ - typedef typename TreeT::ValueType ValueT; - - const ValueT - zero = openvdb::zeroVal(), - minusOne = zero + (-1), - minusTwo = zero + (-2), - one = zero + 1, - three = zero + 3, - four = zero + 4, - five = zero + 5; - - { - TreeT aTree(/*background=*/one); - aTree.setValueOn(openvdb::Coord(0, 0, 0), three); - aTree.setValueOn(openvdb::Coord(0, 0, 1), three); - aTree.setValueOn(openvdb::Coord(0, 0, 2), aTree.background()); - aTree.setValueOn(openvdb::Coord(0, 1, 2), aTree.background()); - aTree.setValueOff(openvdb::Coord(1, 0, 0), three); - aTree.setValueOff(openvdb::Coord(1, 0, 1), three); - - TreeT bTree(five); - bTree.setValueOn(openvdb::Coord(0, 0, 0), minusOne); - bTree.setValueOn(openvdb::Coord(0, 1, 0), four); - bTree.setValueOn(openvdb::Coord(0, 1, 2), minusTwo); - bTree.setValueOff(openvdb::Coord(1, 0, 0), minusOne); - bTree.setValueOff(openvdb::Coord(1, 1, 0), four); - - // Call aTree.compMax(bTree), aTree.compSum(bTree), etc. - comp(aTree, bTree); - - // a = 3 (On), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(op(three, minusOne), aTree.getValue(openvdb::Coord(0, 0, 0))); - - // a = 3 (On), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(three, five), aTree.getValue(openvdb::Coord(0, 0, 1))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 0, 1))); - - // a = 1 (On, = bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(one, five), aTree.getValue(openvdb::Coord(0, 0, 2))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 0, 2))); - - // a = 1 (On, = bg), b = -2 (On) - CPPUNIT_ASSERT_EQUAL(op(one, minusTwo), aTree.getValue(openvdb::Coord(0, 1, 2))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 1, 2))); - - // a = 1 (bg), b = 4 (On) - CPPUNIT_ASSERT_EQUAL(op(one, four), aTree.getValue(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 1, 0))); - - // a = 3 (Off), b = -1 (Off) - CPPUNIT_ASSERT_EQUAL(op(three, minusOne), aTree.getValue(openvdb::Coord(1, 0, 0))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 0, 0))); - - // a = 3 (Off), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(three, five), aTree.getValue(openvdb::Coord(1, 0, 1))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 0, 1))); - - // a = 1 (bg), b = 4 (Off) - CPPUNIT_ASSERT_EQUAL(op(one, four), aTree.getValue(openvdb::Coord(1, 1, 0))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 1, 0))); - - // a = 1 (bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(one, five), aTree.getValue(openvdb::Coord(1000, 1, 2))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1000, 1, 2))); - } - - // As above, but combining the A grid into the B grid - { - TreeT aTree(/*bg=*/one); - aTree.setValueOn(openvdb::Coord(0, 0, 0), three); - aTree.setValueOn(openvdb::Coord(0, 0, 1), three); - aTree.setValueOn(openvdb::Coord(0, 0, 2), aTree.background()); - aTree.setValueOn(openvdb::Coord(0, 1, 2), aTree.background()); - aTree.setValueOff(openvdb::Coord(1, 0, 0), three); - aTree.setValueOff(openvdb::Coord(1, 0, 1), three); - - TreeT bTree(five); - bTree.setValueOn(openvdb::Coord(0, 0, 0), minusOne); - bTree.setValueOn(openvdb::Coord(0, 1, 0), four); - bTree.setValueOn(openvdb::Coord(0, 1, 2), minusTwo); - bTree.setValueOff(openvdb::Coord(1, 0, 0), minusOne); - bTree.setValueOff(openvdb::Coord(1, 1, 0), four); - - // Call bTree.compMax(aTree), bTree.compSum(aTree), etc. - comp(bTree, aTree); - - // a = 3 (On), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(op(minusOne, three), bTree.getValue(openvdb::Coord(0, 0, 0))); - - // a = 3 (On), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(five, three), bTree.getValue(openvdb::Coord(0, 0, 1))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 0, 1))); - - // a = 1 (On, = bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(five, one), bTree.getValue(openvdb::Coord(0, 0, 2))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 0, 2))); - - // a = 1 (On, = bg), b = -2 (On) - CPPUNIT_ASSERT_EQUAL(op(minusTwo, one), bTree.getValue(openvdb::Coord(0, 1, 2))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 1, 2))); - - // a = 1 (bg), b = 4 (On) - CPPUNIT_ASSERT_EQUAL(op(four, one), bTree.getValue(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 1, 0))); - - // a = 3 (Off), b = -1 (Off) - CPPUNIT_ASSERT_EQUAL(op(minusOne, three), bTree.getValue(openvdb::Coord(1, 0, 0))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 0, 0))); - - // a = 3 (Off), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(five, three), bTree.getValue(openvdb::Coord(1, 0, 1))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 0, 1))); - - // a = 1 (bg), b = 4 (Off) - CPPUNIT_ASSERT_EQUAL(op(four, one), bTree.getValue(openvdb::Coord(1, 1, 0))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 1, 0))); - - // a = 1 (bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(op(five, one), bTree.getValue(openvdb::Coord(1000, 1, 2))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1000, 1, 2))); - } -} - - -//////////////////////////////////////// - - -void -TestTreeCombine::testCombine2() -{ - using openvdb::Coord; - using openvdb::Vec3d; - - struct Local { - static void floatAverage(const float& a, const float& b, float& result) - { result = 0.5f * (a + b); } - static void vec3dAverage(const Vec3d& a, const Vec3d& b, Vec3d& result) - { result = 0.5 * (a + b); } - static void vec3dFloatMultiply(const Vec3d& a, const float& b, Vec3d& result) - { result = a * b; } - static void vec3dBoolMultiply(const Vec3d& a, const bool& b, Vec3d& result) - { result = a * b; } - }; - - const Coord c0(0, 0, 0), c1(0, 0, 1), c2(0, 1, 0), c3(1, 0, 0), c4(1000, 1, 2); - - openvdb::FloatTree aFloatTree(/*bg=*/1.0), bFloatTree(5.0), outFloatTree(1.0); - aFloatTree.setValue(c0, 3.0); - aFloatTree.setValue(c1, 3.0); - bFloatTree.setValue(c0, -1.0); - bFloatTree.setValue(c2, 4.0); - outFloatTree.combine2(aFloatTree, bFloatTree, Local::floatAverage); - - const float tolerance = 0.0; - // Average of set value 3 and set value -1 - CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, outFloatTree.getValue(c0), tolerance); - // Average of set value 3 and bg value 5 - CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, outFloatTree.getValue(c1), tolerance); - // Average of bg value 1 and set value 4 - CPPUNIT_ASSERT_DOUBLES_EQUAL(2.5, outFloatTree.getValue(c2), tolerance); - // Average of bg value 1 and bg value 5 - CPPUNIT_ASSERT(outFloatTree.isValueOff(c3)); - CPPUNIT_ASSERT(outFloatTree.isValueOff(c4)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, outFloatTree.getValue(c3), tolerance); - CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, outFloatTree.getValue(c4), tolerance); - - // As above, but combining vector grids: - const Vec3d zero(0), one(1), two(2), three(3), four(4), five(5); - openvdb::Vec3DTree aVecTree(/*bg=*/one), bVecTree(five), outVecTree(one); - aVecTree.setValue(c0, three); - aVecTree.setValue(c1, three); - bVecTree.setValue(c0, -1.0 * one); - bVecTree.setValue(c2, four); - outVecTree.combine2(aVecTree, bVecTree, Local::vec3dAverage); - - // Average of set value 3 and set value -1 - CPPUNIT_ASSERT_EQUAL(one, outVecTree.getValue(c0)); - // Average of set value 3 and bg value 5 - CPPUNIT_ASSERT_EQUAL(four, outVecTree.getValue(c1)); - // Average of bg value 1 and set value 4 - CPPUNIT_ASSERT_EQUAL(2.5 * one, outVecTree.getValue(c2)); - // Average of bg value 1 and bg value 5 - CPPUNIT_ASSERT(outVecTree.isValueOff(c3)); - CPPUNIT_ASSERT(outVecTree.isValueOff(c4)); - CPPUNIT_ASSERT_EQUAL(three, outVecTree.getValue(c3)); - CPPUNIT_ASSERT_EQUAL(three, outVecTree.getValue(c4)); - - // Multiply the vector tree by the scalar tree. - { - openvdb::Vec3DTree vecTree(one); - vecTree.combine2(outVecTree, outFloatTree, Local::vec3dFloatMultiply); - - // Product of set value (1, 1, 1) and set value 1 - CPPUNIT_ASSERT(vecTree.isValueOn(c0)); - CPPUNIT_ASSERT_EQUAL(one, vecTree.getValue(c0)); - // Product of set value (4, 4, 4) and set value 4 - CPPUNIT_ASSERT(vecTree.isValueOn(c1)); - CPPUNIT_ASSERT_EQUAL(4 * 4 * one, vecTree.getValue(c1)); - // Product of set value (2.5, 2.5, 2.5) and set value 2.5 - CPPUNIT_ASSERT(vecTree.isValueOn(c2)); - CPPUNIT_ASSERT_EQUAL(2.5 * 2.5 * one, vecTree.getValue(c2)); - // Product of bg value (3, 3, 3) and bg value 3 - CPPUNIT_ASSERT(vecTree.isValueOff(c3)); - CPPUNIT_ASSERT(vecTree.isValueOff(c4)); - CPPUNIT_ASSERT_EQUAL(3 * 3 * one, vecTree.getValue(c3)); - CPPUNIT_ASSERT_EQUAL(3 * 3 * one, vecTree.getValue(c4)); - } - - // Multiply the vector tree by a boolean tree. - { - openvdb::BoolTree boolTree(0); - boolTree.setValue(c0, true); - boolTree.setValue(c1, false); - boolTree.setValue(c2, true); - - openvdb::Vec3DTree vecTree(one); - vecTree.combine2(outVecTree, boolTree, Local::vec3dBoolMultiply); - - // Product of set value (1, 1, 1) and set value 1 - CPPUNIT_ASSERT(vecTree.isValueOn(c0)); - CPPUNIT_ASSERT_EQUAL(one, vecTree.getValue(c0)); - // Product of set value (4, 4, 4) and set value 0 - CPPUNIT_ASSERT(vecTree.isValueOn(c1)); - CPPUNIT_ASSERT_EQUAL(zero, vecTree.getValue(c1)); - // Product of set value (2.5, 2.5, 2.5) and set value 1 - CPPUNIT_ASSERT(vecTree.isValueOn(c2)); - CPPUNIT_ASSERT_EQUAL(2.5 * one, vecTree.getValue(c2)); - // Product of bg value (3, 3, 3) and bg value 0 - CPPUNIT_ASSERT(vecTree.isValueOff(c3)); - CPPUNIT_ASSERT(vecTree.isValueOff(c4)); - CPPUNIT_ASSERT_EQUAL(zero, vecTree.getValue(c3)); - CPPUNIT_ASSERT_EQUAL(zero, vecTree.getValue(c4)); - } - - // Verify that a vector tree can't be combined into a scalar tree - // (although the reverse is allowed). - { - struct Local2 { - static void f(const float& a, const Vec3d&, float& result) { result = a; } - }; - openvdb::FloatTree floatTree(5.0), outTree; - openvdb::Vec3DTree vecTree(one); - CPPUNIT_ASSERT_THROW(outTree.combine2(floatTree, vecTree, Local2::f), openvdb::TypeError); - } -} - - -//////////////////////////////////////// - - -void -TestTreeCombine::testBoolTree() -{ - openvdb::BoolGrid::Ptr sphere = openvdb::BoolGrid::create(); - - unittest_util::makeSphere(/*dim=*/openvdb::Coord(32), - /*ctr=*/openvdb::Vec3f(0), - /*radius=*/20.0, *sphere, - unittest_util::SPHERE_SPARSE_NARROW_BAND); - - openvdb::BoolGrid::Ptr - aGrid = sphere->copy(), - bGrid = sphere->copy(); - - // CSG operations work only on level sets with a nonzero inside and outside values. - CPPUNIT_ASSERT_THROW(openvdb::tools::csgUnion(aGrid->tree(), bGrid->tree()), - openvdb::ValueError); - CPPUNIT_ASSERT_THROW(openvdb::tools::csgIntersection(aGrid->tree(), bGrid->tree()), - openvdb::ValueError); - CPPUNIT_ASSERT_THROW(openvdb::tools::csgDifference(aGrid->tree(), bGrid->tree()), - openvdb::ValueError); - - openvdb::tools::compSum(aGrid->tree(), bGrid->tree()); - - bGrid = sphere->copy(); - openvdb::tools::compMax(aGrid->tree(), bGrid->tree()); - - int mismatches = 0; - openvdb::BoolGrid::ConstAccessor acc = sphere->getConstAccessor(); - for (openvdb::BoolGrid::ValueAllCIter it = aGrid->cbeginValueAll(); it; ++it) { - if (*it != acc.getValue(it.getCoord())) ++mismatches; - } - CPPUNIT_ASSERT_EQUAL(0, mismatches); -} - - -//////////////////////////////////////// - - -template -void -TestTreeCombine::testCompRepl() -{ - typedef typename TreeT::ValueType ValueT; - - const ValueT - zero = openvdb::zeroVal(), - minusOne = zero + (-1), - one = zero + 1, - three = zero + 3, - four = zero + 4, - five = zero + 5; - - { - TreeT aTree(/*bg=*/one); - aTree.setValueOn(openvdb::Coord(0, 0, 0), three); - aTree.setValueOn(openvdb::Coord(0, 0, 1), three); - aTree.setValueOn(openvdb::Coord(0, 0, 2), aTree.background()); - aTree.setValueOn(openvdb::Coord(0, 1, 2), aTree.background()); - aTree.setValueOff(openvdb::Coord(1, 0, 0), three); - aTree.setValueOff(openvdb::Coord(1, 0, 1), three); - - TreeT bTree(five); - bTree.setValueOn(openvdb::Coord(0, 0, 0), minusOne); - bTree.setValueOn(openvdb::Coord(0, 1, 0), four); - bTree.setValueOn(openvdb::Coord(0, 1, 2), minusOne); - bTree.setValueOff(openvdb::Coord(1, 0, 0), minusOne); - bTree.setValueOff(openvdb::Coord(1, 1, 0), four); - - // Copy active voxels of bTree into aTree. - openvdb::tools::compReplace(aTree, bTree); - - // a = 3 (On), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(minusOne, aTree.getValue(openvdb::Coord(0, 0, 0))); - - // a = 3 (On), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(three, aTree.getValue(openvdb::Coord(0, 0, 1))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 0, 1))); - - // a = 1 (On, = bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(one, aTree.getValue(openvdb::Coord(0, 0, 2))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 0, 2))); - - // a = 1 (On, = bg), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(minusOne, aTree.getValue(openvdb::Coord(0, 1, 2))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 1, 2))); - - // a = 1 (bg), b = 4 (On) - CPPUNIT_ASSERT_EQUAL(four, aTree.getValue(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT(aTree.isValueOn(openvdb::Coord(0, 1, 0))); - - // a = 3 (Off), b = -1 (Off) - CPPUNIT_ASSERT_EQUAL(three, aTree.getValue(openvdb::Coord(1, 0, 0))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 0, 0))); - - // a = 3 (Off), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(three, aTree.getValue(openvdb::Coord(1, 0, 1))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 0, 1))); - - // a = 1 (bg), b = 4 (Off) - CPPUNIT_ASSERT_EQUAL(one, aTree.getValue(openvdb::Coord(1, 1, 0))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1, 1, 0))); - - // a = 1 (bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(one, aTree.getValue(openvdb::Coord(1000, 1, 2))); - CPPUNIT_ASSERT(aTree.isValueOff(openvdb::Coord(1000, 1, 2))); - } - - // As above, but combining the A grid into the B grid - { - TreeT aTree(/*background=*/one); - aTree.setValueOn(openvdb::Coord(0, 0, 0), three); - aTree.setValueOn(openvdb::Coord(0, 0, 1), three); - aTree.setValueOn(openvdb::Coord(0, 0, 2), aTree.background()); - aTree.setValueOn(openvdb::Coord(0, 1, 2), aTree.background()); - aTree.setValueOff(openvdb::Coord(1, 0, 0), three); - aTree.setValueOff(openvdb::Coord(1, 0, 1), three); - - TreeT bTree(five); - bTree.setValueOn(openvdb::Coord(0, 0, 0), minusOne); - bTree.setValueOn(openvdb::Coord(0, 1, 0), four); - bTree.setValueOn(openvdb::Coord(0, 1, 2), minusOne); - bTree.setValueOff(openvdb::Coord(1, 0, 0), minusOne); - bTree.setValueOff(openvdb::Coord(1, 1, 0), four); - - // Copy active voxels of aTree into bTree. - openvdb::tools::compReplace(bTree, aTree); - - // a = 3 (On), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(three, bTree.getValue(openvdb::Coord(0, 0, 0))); - - // a = 3 (On), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(three, bTree.getValue(openvdb::Coord(0, 0, 1))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 0, 1))); - - // a = 1 (On, = bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(one, bTree.getValue(openvdb::Coord(0, 0, 2))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 0, 2))); - - // a = 1 (On, = bg), b = -1 (On) - CPPUNIT_ASSERT_EQUAL(one, bTree.getValue(openvdb::Coord(0, 1, 2))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 1, 2))); - - // a = 1 (bg), b = 4 (On) - CPPUNIT_ASSERT_EQUAL(four, bTree.getValue(openvdb::Coord(0, 1, 0))); - CPPUNIT_ASSERT(bTree.isValueOn(openvdb::Coord(0, 1, 0))); - - // a = 3 (Off), b = -1 (Off) - CPPUNIT_ASSERT_EQUAL(minusOne, bTree.getValue(openvdb::Coord(1, 0, 0))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 0, 0))); - - // a = 3 (Off), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(five, bTree.getValue(openvdb::Coord(1, 0, 1))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 0, 1))); - - // a = 1 (bg), b = 4 (Off) - CPPUNIT_ASSERT_EQUAL(four, bTree.getValue(openvdb::Coord(1, 1, 0))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1, 1, 0))); - - // a = 1 (bg), b = 5 (bg) - CPPUNIT_ASSERT_EQUAL(five, bTree.getValue(openvdb::Coord(1000, 1, 2))); - CPPUNIT_ASSERT(bTree.isValueOff(openvdb::Coord(1000, 1, 2))); - } -} - - -//////////////////////////////////////// - - -void -TestTreeCombine::testCsg() -{ - typedef openvdb::FloatTree TreeT; - typedef TreeT::Ptr TreePtr; - typedef openvdb::Grid GridT; - - struct Local { - static TreePtr readFile(const std::string& fname) { - std::string filename(fname), gridName("LevelSet"); - size_t space = filename.find_last_of(' '); - if (space != std::string::npos) { - gridName = filename.substr(space + 1); - filename.erase(space); - } - - TreePtr tree; - openvdb::io::File file(filename); - file.open(); - if (openvdb::GridBase::Ptr basePtr = file.readGrid(gridName)) { - if (GridT::Ptr gridPtr = openvdb::gridPtrCast(basePtr)) { - tree = gridPtr->treePtr(); - } - } - file.close(); - return tree; - } - - static void writeFile(TreePtr tree, const std::string& filename) { - openvdb::io::File file(filename); - openvdb::GridPtrVec grids; - GridT::Ptr grid = openvdb::createGrid(tree); - grid->setName("LevelSet"); - grids.push_back(grid); - file.write(grids); - } - - static void visitorUnion(TreeT& a, TreeT& b) { openvdb::tools::csgUnion(a, b); } - static void visitorIntersect(TreeT& a, TreeT& b) { openvdb::tools::csgIntersection(a, b); } - static void visitorDiff(TreeT& a, TreeT& b) { openvdb::tools::csgDifference(a, b); } - }; - - TreePtr smallTree1, smallTree2, largeTree1, largeTree2, refTree, outTree; - -#if TEST_CSG_VERBOSE - openvdb::util::CpuTimer timer; - timer.start(); -#endif - - const std::string testDir("/work/rd/fx_tools/vdb_unittest/TestGridCombine::testCsg/"); - smallTree1 = Local::readFile(testDir + "small1.vdb2 LevelSet"); - CPPUNIT_ASSERT(smallTree1.get() != NULL); - smallTree2 = Local::readFile(testDir + "small2.vdb2 Cylinder"); - CPPUNIT_ASSERT(smallTree2.get() != NULL); - largeTree1 = Local::readFile(testDir + "large1.vdb2 LevelSet"); - CPPUNIT_ASSERT(largeTree1.get() != NULL); - largeTree2 = Local::readFile(testDir + "large2.vdb2 LevelSet"); - CPPUNIT_ASSERT(largeTree2.get() != NULL); - -#if TEST_CSG_VERBOSE - std::cerr << "file read: " << timer.delta() << " sec\n"; -#endif - -#if TEST_CSG_VERBOSE - std::cerr << "\n\n"; -#endif - refTree = Local::readFile(testDir + "small_union.vdb2"); - outTree = visitCsg(*smallTree1, *smallTree2, *refTree, Local::visitorUnion); - //Local::writeFile(outTree, "/tmp/small_union_out.vdb2"); - refTree = Local::readFile(testDir + "large_union.vdb2"); - outTree = visitCsg(*largeTree1, *largeTree2, *refTree, Local::visitorUnion); - //Local::writeFile(outTree, "/tmp/large_union_out.vdb2"); - -#if TEST_CSG_VERBOSE - std::cerr << "\n\n"; -#endif - refTree = Local::readFile(testDir + "small_intersection.vdb2"); - outTree = visitCsg(*smallTree1, *smallTree2, *refTree, Local::visitorIntersect); - //Local::writeFile(outTree, "/tmp/small_intersection_out.vdb2"); - refTree = Local::readFile(testDir + "large_intersection.vdb2"); - outTree = visitCsg(*largeTree1, *largeTree2, *refTree, Local::visitorIntersect); - //Local::writeFile(outTree, "/tmp/large_intersection_out.vdb2"); - -#if TEST_CSG_VERBOSE - std::cerr << "\n\n"; -#endif - refTree = Local::readFile(testDir + "small_difference.vdb2"); - outTree = visitCsg(*smallTree1, *smallTree2, *refTree, Local::visitorDiff); - //Local::writeFile(outTree, "/tmp/small_difference_out.vdb2"); - refTree = Local::readFile(testDir + "large_difference.vdb2"); - outTree = visitCsg(*largeTree1, *largeTree2, *refTree, Local::visitorDiff); - //Local::writeFile(outTree, "/tmp/large_difference_out.vdb2"); -} - - -template -typename TreeT::Ptr -TestTreeCombine::visitCsg(const TreeT& aInputTree, const TreeT& bInputTree, - const TreeT& refTree, const VisitorT& visitor) -{ - typedef typename TreeT::Ptr TreePtr; - -#if TEST_CSG_VERBOSE - openvdb::util::CpuTimer timer; - timer.start(); -#endif - TreePtr aTree(new TreeT(aInputTree)); - TreeT bTree(bInputTree); -#if TEST_CSG_VERBOSE - std::cerr << "deep copy: " << timer.delta() << " ms\n"; -#endif - -#if (TEST_CSG_VERBOSE > 1) - std::cerr << "\nA grid:\n"; - aTree->print(std::cerr, /*verbose=*/3); - std::cerr << "\nB grid:\n"; - bTree.print(std::cerr, /*verbose=*/3); - std::cerr << "\nExpected:\n"; - refTree.print(std::cerr, /*verbose=*/3); - std::cerr << "\n"; -#endif - - // Compute the CSG combination of the two grids. -#if TEST_CSG_VERBOSE - timer.start(); -#endif - visitor(*aTree, bTree); -#if TEST_CSG_VERBOSE - std::cerr << "combine: " << timer.delta() << " ms\n"; -#endif -#if (TEST_CSG_VERBOSE > 1) - std::cerr << "\nActual:\n"; - aTree->print(std::cerr, /*verbose=*/3); -#endif - - std::ostringstream aInfo, refInfo; - aTree->print(aInfo, /*verbose=*/2); - refTree.print(refInfo, /*verbose=*/2); - - CPPUNIT_ASSERT_EQUAL(refInfo.str(), aInfo.str()); - - CPPUNIT_ASSERT(aTree->hasSameTopology(refTree)); - - return aTree; -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTreeGetSetValues.cc b/openvdb_3_0_0_library/unittest/TestTreeGetSetValues.cc deleted file mode 100755 index fbef514..0000000 --- a/openvdb_3_0_0_library/unittest/TestTreeGetSetValues.cc +++ /dev/null @@ -1,466 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include // for tools::setValueOnMin() et al. -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - - -class TestTreeGetSetValues: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestTreeGetSetValues); - CPPUNIT_TEST(testGetValues); - CPPUNIT_TEST(testSetValues); - CPPUNIT_TEST(testUnsetValues); - CPPUNIT_TEST(testFill); - CPPUNIT_TEST(testSetActiveStates); - CPPUNIT_TEST(testHasActiveTiles); - CPPUNIT_TEST_SUITE_END(); - - void testGetBackground(); - void testGetValues(); - void testSetValues(); - void testUnsetValues(); - void testFill(); - void testSetActiveStates(); - void testHasActiveTiles(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTreeGetSetValues); - -namespace { -typedef openvdb::tree::Tree4::Type Tree323f; // 8^3 x 4^3 x 8^3 -} - - -void -TestTreeGetSetValues::testGetBackground() -{ - const float background = 256.0f; - Tree323f tree(background); - - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.background()); -} - - -void -TestTreeGetSetValues::testGetValues() -{ - Tree323f tree(/*background=*/256.0f); - - tree.setValue(openvdb::Coord(0, 0, 0), 1.0); - tree.setValue(openvdb::Coord(1, 0, 0), 1.5); - tree.setValue(openvdb::Coord(0, 0, 8), 2.0); - tree.setValue(openvdb::Coord(1, 0, 8), 2.5); - tree.setValue(openvdb::Coord(0, 0, 16), 3.0); - tree.setValue(openvdb::Coord(1, 0, 16), 3.5); - tree.setValue(openvdb::Coord(0, 0, 24), 4.0); - tree.setValue(openvdb::Coord(1, 0, 24), 4.5); - - ASSERT_DOUBLES_EXACTLY_EQUAL(1.0, tree.getValue(openvdb::Coord(0, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(1.5, tree.getValue(openvdb::Coord(1, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(2.0, tree.getValue(openvdb::Coord(0, 0, 8))); - ASSERT_DOUBLES_EXACTLY_EQUAL(2.5, tree.getValue(openvdb::Coord(1, 0, 8))); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.0, tree.getValue(openvdb::Coord(0, 0, 16))); - ASSERT_DOUBLES_EXACTLY_EQUAL(3.5, tree.getValue(openvdb::Coord(1, 0, 16))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.0, tree.getValue(openvdb::Coord(0, 0, 24))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5, tree.getValue(openvdb::Coord(1, 0, 24))); -} - - -void -TestTreeGetSetValues::testSetValues() -{ - using namespace openvdb; - - const float background = 256.0; - Tree323f tree(background); - - for (int activeTile = 0; activeTile < 2; ++activeTile) { - if (activeTile) tree.fill(CoordBBox(Coord(0), Coord(31)), background, /*active=*/true); - - tree.setValue(openvdb::Coord(0, 0, 0), 1.0); - tree.setValue(openvdb::Coord(1, 0, 0), 1.5); - tree.setValue(openvdb::Coord(0, 0, 8), 2.0); - tree.setValue(openvdb::Coord(1, 0, 8), 2.5); - tree.setValue(openvdb::Coord(0, 0, 16), 3.0); - tree.setValue(openvdb::Coord(1, 0, 16), 3.5); - tree.setValue(openvdb::Coord(0, 0, 24), 4.0); - tree.setValue(openvdb::Coord(1, 0, 24), 4.5); - - const int expectedActiveCount = (!activeTile ? 8 : 32 * 32 * 32); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - - float val = 1.f; - for (Tree323f::LeafCIter iter = tree.cbeginLeaf(); iter; ++iter) { - ASSERT_DOUBLES_EXACTLY_EQUAL(val, iter->getValue(openvdb::Coord(0, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(val+0.5, iter->getValue(openvdb::Coord(1, 0, 0))); - val = val + 1.f; - } - } -} - - -void -TestTreeGetSetValues::testUnsetValues() -{ - using namespace openvdb; - - const float background = 256.0; - Tree323f tree(background); - - for (int activeTile = 0; activeTile < 2; ++activeTile) { - if (activeTile) tree.fill(CoordBBox(Coord(0), Coord(31)), background, /*active=*/true); - - Coord setCoords[8] = { - Coord(0, 0, 0), - Coord(1, 0, 0), - Coord(0, 0, 8), - Coord(1, 0, 8), - Coord(0, 0, 16), - Coord(1, 0, 16), - Coord(0, 0, 24), - Coord(1, 0, 24) - }; - - for (int i = 0; i < 8; ++i) { - tree.setValue(setCoords[i], 1.0); - } - const int expectedActiveCount = (!activeTile ? 8 : 32 * 32 * 32); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - - // Unset some voxels. - for (int i = 0; i < 8; i += 2) { - tree.setValueOff(setCoords[i]); - } - CPPUNIT_ASSERT_EQUAL(expectedActiveCount - 4, int(tree.activeVoxelCount())); - - // Unset some voxels, but change their values. - for (int i = 0; i < 8; i += 2) { - tree.setValueOff(setCoords[i], background); - } - CPPUNIT_ASSERT_EQUAL(expectedActiveCount - 4, int(tree.activeVoxelCount())); - for (int i = 0; i < 8; i += 2) { - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(setCoords[i])); - } - } -} - - -void -TestTreeGetSetValues::testFill() -{ - using openvdb::CoordBBox; - using openvdb::Coord; - - const float background = 256.0; - Tree323f tree(background); - - // Fill from (-2,-2,-2) to (2,2,2) with active value 2. - tree.fill(CoordBBox(Coord(-2), Coord(2)), 2.0); - Coord xyz, xyzMin = Coord::max(), xyzMax = Coord::min(); - for (Tree323f::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - xyz = iter.getCoord(); - xyzMin = std::min(xyzMin, xyz); - xyzMax = std::max(xyz, xyzMax); - ASSERT_DOUBLES_EXACTLY_EQUAL(2.0, *iter); - } - CPPUNIT_ASSERT_EQUAL(openvdb::Index64(5*5*5), tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Coord(-2), xyzMin); - CPPUNIT_ASSERT_EQUAL(Coord( 2), xyzMax); - - // Fill from (1,1,1) to (3,3,3) with active value 3. - tree.fill(CoordBBox(Coord(1), Coord(3)), 3.0); - xyzMin = Coord::max(); xyzMax = Coord::min(); - for (Tree323f::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - xyz = iter.getCoord(); - xyzMin = std::min(xyzMin, xyz); - xyzMax = std::max(xyz, xyzMax); - const float expectedValue = (xyz[0] >= 1 && xyz[1] >= 1 && xyz[2] >= 1 - && xyz[0] <= 3 && xyz[1] <= 3 && xyz[2] <= 3) ? 3.0 : 2.0; - ASSERT_DOUBLES_EXACTLY_EQUAL(expectedValue, *iter); - } - openvdb::Index64 expectedCount = - 5*5*5 // (-2,-2,-2) to (2,2,2) - + 3*3*3 // (1,1,1) to (3,3,3) - - 2*2*2; // (1,1,1) to (2,2,2) overlap - CPPUNIT_ASSERT_EQUAL(expectedCount, tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Coord(-2), xyzMin); - CPPUNIT_ASSERT_EQUAL(Coord( 3), xyzMax); - - // Fill from (10,10,10) to (20,20,20) with active value 10. - tree.fill(CoordBBox(Coord(10), Coord(20)), 10.0); - xyzMin = Coord::max(); xyzMax = Coord::min(); - for (Tree323f::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - xyz = iter.getCoord(); - xyzMin = std::min(xyzMin, xyz); - xyzMax = std::max(xyz, xyzMax); - float expectedValue = 2.0; - if (xyz[0] >= 1 && xyz[1] >= 1 && xyz[2] >= 1 - && xyz[0] <= 3 && xyz[1] <= 3 && xyz[2] <= 3) - { - expectedValue = 3.0; - } else if (xyz[0] >= 10 && xyz[1] >= 10 && xyz[2] >= 10 - && xyz[0] <= 20 && xyz[1] <= 20 && xyz[2] <= 20) - { - expectedValue = 10.0; - } - ASSERT_DOUBLES_EXACTLY_EQUAL(expectedValue, *iter); - } - expectedCount = - 5*5*5 // (-2,-2,-2) to (2,2,2) - + 3*3*3 // (1,1,1) to (3,3,3) - - 2*2*2 // (1,1,1) to (2,2,2) overlap - + 11*11*11; // (10,10,10) to (20,20,20) - CPPUNIT_ASSERT_EQUAL(expectedCount, tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Coord(-2), xyzMin); - CPPUNIT_ASSERT_EQUAL(Coord(20), xyzMax); - - // "Undo" previous fill from (10,10,10) to (20,20,20). - tree.fill(CoordBBox(Coord(10), Coord(20)), background, /*active=*/false); - xyzMin = Coord::max(); xyzMax = Coord::min(); - for (Tree323f::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - xyz = iter.getCoord(); - xyzMin = std::min(xyzMin, xyz); - xyzMax = std::max(xyz, xyzMax); - const float expectedValue = (xyz[0] >= 1 && xyz[1] >= 1 && xyz[2] >= 1 - && xyz[0] <= 3 && xyz[1] <= 3 && xyz[2] <= 3) ? 3.0 : 2.0; - ASSERT_DOUBLES_EXACTLY_EQUAL(expectedValue, *iter); - } - expectedCount = - 5*5*5 // (-2,-2,-2) to (2,2,2) - + 3*3*3 // (1,1,1) to (3,3,3) - - 2*2*2; // (1,1,1) to (2,2,2) overlap - CPPUNIT_ASSERT_EQUAL(expectedCount, tree.activeVoxelCount()); - CPPUNIT_ASSERT_EQUAL(Coord(-2), xyzMin); - CPPUNIT_ASSERT_EQUAL(Coord( 3), xyzMax); - - // The following tests assume a [3,2,3] tree configuration. - - tree.clear(); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); // root node - - // Partially fill a single leaf node. - tree.fill(CoordBBox(Coord(8), Coord(14)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - // Completely fill the leaf node, replacing it with a tile. - tree.fill(CoordBBox(Coord(8), Coord(15)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - { - const int activeVoxelCount = int(tree.activeVoxelCount()); - - // Fill a single voxel of the tile with a different (active) value. - tree.fill(CoordBBox(Coord(10), Coord(10)), 1.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - CPPUNIT_ASSERT_EQUAL(activeVoxelCount, int(tree.activeVoxelCount())); - // Fill the voxel with an inactive value. - tree.fill(CoordBBox(Coord(10), Coord(10)), 1.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - CPPUNIT_ASSERT_EQUAL(activeVoxelCount - 1, int(tree.activeVoxelCount())); - - // Completely fill the leaf node, replacing it with a tile again. - tree.fill(CoordBBox(Coord(8), Coord(15)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - } - - // Expand by one voxel, creating seven neighboring leaf nodes. - tree.fill(CoordBBox(Coord(8), Coord(16)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - // Completely fill the internal node containing the tile, replacing it with - // a tile at the next level of the tree. - tree.fill(CoordBBox(Coord(0), Coord(31)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(2), tree.nonLeafCount()); - - // Expand by one voxel, creating a layer of leaf nodes on three faces. - tree.fill(CoordBBox(Coord(0), Coord(32)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(5*5 + 4*5 + 4*4), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(2 + 7), tree.nonLeafCount()); // +7 internal nodes - - // Completely fill the second-level internal node, replacing it with a root-level tile. - tree.fill(CoordBBox(Coord(0), Coord(255)), 0.0); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); - - // Repeat, filling with an inactive value. - - tree.clear(); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); // root node - - // Partially fill a single leaf node. - tree.fill(CoordBBox(Coord(8), Coord(14)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - // Completely fill the leaf node, replacing it with a tile. - tree.fill(CoordBBox(Coord(8), Coord(15)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - // Expand by one voxel, creating seven neighboring leaf nodes. - tree.fill(CoordBBox(Coord(8), Coord(16)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(7), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(3), tree.nonLeafCount()); - - // Completely fill the internal node containing the tile, replacing it with - // a tile at the next level of the tree. - tree.fill(CoordBBox(Coord(0), Coord(31)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(2), tree.nonLeafCount()); - - // Expand by one voxel, creating a layer of leaf nodes on three faces. - tree.fill(CoordBBox(Coord(0), Coord(32)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(5*5 + 4*5 + 4*4), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(2 + 7), tree.nonLeafCount()); // +7 internal nodes - - // Completely fill the second-level internal node, replacing it with a root-level tile. - tree.fill(CoordBBox(Coord(0), Coord(255)), 0.0, /*active=*/false); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); - - tree.clear(); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); // root node - - // Partially fill a region with the background value. - tree.fill(CoordBBox(Coord(27), Coord(254)), background, /*active=*/false); - // Confirm that after pruning, the tree is empty. - openvdb::tools::prune(tree); - CPPUNIT_ASSERT(tree.empty()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(0), tree.leafCount()); - CPPUNIT_ASSERT_EQUAL(openvdb::Index32(1), tree.nonLeafCount()); // root node -} - - -// Verify that setting voxels inside active tiles works correctly. -// In particular, it should preserve the active states of surrounding voxels. -void -TestTreeGetSetValues::testSetActiveStates() -{ - using namespace openvdb; - - const float background = 256.0; - Tree323f tree(background); - - const Coord xyz(10); - const float val = 42.0; - const int expectedActiveCount = 32 * 32 * 32; - -#define RESET_TREE() \ - tree.fill(CoordBBox(Coord(0), Coord(31)), background, /*active=*/true) // create an active tile - - RESET_TREE(); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - - tree.setValueOff(xyz); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount - 1, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(xyz)); - - RESET_TREE(); - tree.setValueOn(xyz); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(xyz)); - - RESET_TREE(); - tree.setValueOff(xyz, val); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount - 1, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(val, tree.getValue(xyz)); - - RESET_TREE(); - tree.setActiveState(xyz, true); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(xyz)); - - RESET_TREE(); - tree.setActiveState(xyz, false); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount - 1, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(xyz)); - - RESET_TREE(); - tree.setValueOn(xyz, val); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(val, tree.getValue(xyz)); - - RESET_TREE(); - tools::setValueOnMin(tree, xyz, val); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(std::min(val, background), tree.getValue(xyz)); - - RESET_TREE(); - tools::setValueOnMax(tree, xyz, val); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(std::max(val, background), tree.getValue(xyz)); - - RESET_TREE(); - tools::setValueOnSum(tree, xyz, val); - CPPUNIT_ASSERT_EQUAL(expectedActiveCount, int(tree.activeVoxelCount())); - ASSERT_DOUBLES_EXACTLY_EQUAL(val + background, tree.getValue(xyz)); - -#undef RESET_TREE -} - - -void -TestTreeGetSetValues::testHasActiveTiles() -{ - Tree323f tree(/*background=*/256.0f); - - CPPUNIT_ASSERT(!tree.hasActiveTiles()); - - // Fill from (-2,-2,-2) to (2,2,2) with active value 2. - tree.fill(openvdb::CoordBBox(openvdb::Coord(-2), openvdb::Coord(2)), 2.0f); - CPPUNIT_ASSERT(!tree.hasActiveTiles()); - - // Fill from (-200,-200,-200) to (-4,-4,-4) with active value 3. - tree.fill(openvdb::CoordBBox(openvdb::Coord(-200), openvdb::Coord(-4)), 3.0f); - CPPUNIT_ASSERT(tree.hasActiveTiles()); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTreeIterators.cc b/openvdb_3_0_0_library/unittest/TestTreeIterators.cc deleted file mode 100755 index 559c8b0..0000000 --- a/openvdb_3_0_0_library/unittest/TestTreeIterators.cc +++ /dev/null @@ -1,605 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include // for tools::createLevelSetSphere() - - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0) - - -class TestTreeIterators: public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestTreeIterators); - CPPUNIT_TEST(testLeafIterator); - CPPUNIT_TEST(testEmptyLeafIterator); - CPPUNIT_TEST(testOnlyNegative); - CPPUNIT_TEST(testValueAllIterator); - CPPUNIT_TEST(testValueOnIterator); - CPPUNIT_TEST(testValueOffIterator); - CPPUNIT_TEST(testModifyValue); - CPPUNIT_TEST(testDepthBounds); - CPPUNIT_TEST_SUITE_END(); - - void testLeafIterator(); - void testEmptyLeafIterator(); - void testOnlyNegative(); - void testValueAllIterator(); - void testValueOnIterator(); - void testValueOffIterator(); - void testModifyValue(); - void testDepthBounds(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTreeIterators); - - -typedef openvdb::FloatTree TreeType; - - -void -TestTreeIterators::testLeafIterator() -{ - const float fillValue = 256.0f; - - TreeType tree(fillValue); - - tree.setValue(openvdb::Coord(0, 0, 0), 1.0); - tree.setValue(openvdb::Coord(1, 0, 0), 1.5); - tree.setValue(openvdb::Coord(0, 0, 8), 2.0); - tree.setValue(openvdb::Coord(1, 0, 8), 2.5); - tree.setValue(openvdb::Coord(0, 0, 16), 3.0); - tree.setValue(openvdb::Coord(1, 0, 16), 3.5); - tree.setValue(openvdb::Coord(0, 0, 24), 4.0); - tree.setValue(openvdb::Coord(1, 0, 24), 4.5); - - float val = 1.f; - for (TreeType::LeafCIter iter = tree.cbeginLeaf(); iter; ++iter) { - const TreeType::LeafNodeType* leaf = iter.getLeaf(); - CPPUNIT_ASSERT(leaf != NULL); - ASSERT_DOUBLES_EXACTLY_EQUAL(val, leaf->getValue(openvdb::Coord(0, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(val + 0.5, iter->getValue(openvdb::Coord(1, 0, 0))); - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue, iter->getValue(openvdb::Coord(1, 1, 1))); - val = val + 1.f; - } -} - - -// Test the leaf iterator over a tree without any leaf nodes. -void -TestTreeIterators::testEmptyLeafIterator() -{ - using namespace openvdb; - - TreeType tree(/*fillValue=*/256.0); - - std::vector dims; - tree.getNodeLog2Dims(dims); - CPPUNIT_ASSERT_EQUAL(4, int(dims.size())); - - // Start with an iterator over an empty tree. - TreeType::LeafCIter iter = tree.cbeginLeaf(); - CPPUNIT_ASSERT(!iter); - - // Using sparse fill, add internal nodes but no leaf nodes to the tree. - - // Fill the region subsumed by a level-2 internal node (assuming a four-level tree). - Index log2Sum = dims[1] + dims[2] + dims[3]; - CoordBBox bbox(Coord(0), Coord((1 << log2Sum) - 1)); - tree.fill(bbox, /*value=*/1.0); - iter = tree.cbeginLeaf(); - CPPUNIT_ASSERT(!iter); - - // Fill the region subsumed by a level-1 internal node. - log2Sum = dims[2] + dims[3]; - bbox.reset(Coord(0), Coord((1 << log2Sum) - 1)); - tree.fill(bbox, /*value=*/2.0); - iter = tree.cbeginLeaf(); - CPPUNIT_ASSERT(!iter); -} - - -void -TestTreeIterators::testOnlyNegative() -{ - using openvdb::Index64; - - const float fillValue = 5.0f; - - TreeType tree(fillValue); - - CPPUNIT_ASSERT(tree.empty()); - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue, tree.getValue(openvdb::Coord(5, -10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(fillValue, tree.getValue(openvdb::Coord(-500, 200, 300))); - - tree.setValue(openvdb::Coord(-5, 10, 20), 0.1f); - tree.setValue(openvdb::Coord( 5, -10, 20), 0.2f); - tree.setValue(openvdb::Coord( 5, 10, -20), 0.3f); - tree.setValue(openvdb::Coord(-5, -10, 20), 0.4f); - tree.setValue(openvdb::Coord(-5, 10, -20), 0.5f); - tree.setValue(openvdb::Coord( 5, -10, -20), 0.6f); - tree.setValue(openvdb::Coord(-5, -10, -20), 0.7f); - tree.setValue(openvdb::Coord(-500, 200, -300), 4.5678f); - tree.setValue(openvdb::Coord( 500, -200, -300), 4.5678f); - tree.setValue(openvdb::Coord(-500, -200, 300), 4.5678f); - - ASSERT_DOUBLES_EXACTLY_EQUAL(0.1f, tree.getValue(openvdb::Coord(-5, 10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.2f, tree.getValue(openvdb::Coord( 5, -10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.3f, tree.getValue(openvdb::Coord( 5, 10, -20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.4f, tree.getValue(openvdb::Coord(-5, -10, 20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.5f, tree.getValue(openvdb::Coord(-5, 10, -20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.6f, tree.getValue(openvdb::Coord( 5, -10, -20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.7f, tree.getValue(openvdb::Coord(-5, -10, -20))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord(-500, 200, -300))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord( 500, -200, -300))); - ASSERT_DOUBLES_EXACTLY_EQUAL(4.5678f, tree.getValue(openvdb::Coord(-500, -200, 300))); - - int count = 0; - for (int i = -25; i < 25; ++i) { - for (int j = -25; j < 25; ++j) { - for (int k = -25; k < 25; ++k) { - if (tree.getValue(openvdb::Coord(i, j, k)) < 1.0f) { - //fprintf(stderr, "(%i, %i, %i) = %f\n", - // i, j, k, tree.getValue(openvdb::Coord(i, j, k))); - ++count; - } - } - } - } - CPPUNIT_ASSERT_EQUAL(7, count); - - openvdb::Coord xyz; - int count2 = 0; - for (TreeType::ValueOnCIter iter = tree.cbeginValueOn();iter; ++iter) { - ++count2; - xyz = iter.getCoord(); - //std::cerr << xyz << " = " << *iter << "\n"; - } - CPPUNIT_ASSERT_EQUAL(10, count2); - CPPUNIT_ASSERT_EQUAL(Index64(10), tree.activeVoxelCount()); -} - - -void -TestTreeIterators::testValueAllIterator() -{ - const openvdb::Index DIM0 = 3, DIM1 = 2, DIM2 = 3; - - typedef openvdb::tree::Tree4::Type Tree323f; - - typedef Tree323f::RootNodeType RootT; - typedef RootT::ChildNodeType Int1T; - typedef Int1T::ChildNodeType Int2T; - typedef Int2T::ChildNodeType LeafT; - - Tree323f tree(/*fillValue=*/256.0f); - tree.setValue(openvdb::Coord(4), 0.0f); - tree.setValue(openvdb::Coord(-4), -1.0f); - - const size_t expectedNumOff = - 2 * ((1 << (3 * DIM2)) - 1) // 2 8x8x8 InternalNodes - 1 child pointer each - + 2 * ((1 << (3 * DIM1)) - 1) // 2 4x4x4 InternalNodes - 1 child pointer each - + 2 * ((1 << (3 * DIM0)) - 1); // 2 8x8x8 LeafNodes - 1 active value each - - { - Tree323f::ValueAllIter iter = tree.beginValueAll(); - CPPUNIT_ASSERT(iter.test()); - - // Read all tile and voxel values through a non-const value iterator. - size_t numOn = 0, numOff = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(iter.getLevel() <= 3); - const openvdb::Index iterLevel = iter.getLevel(); - for (openvdb::Index lvl = 0; lvl <= 3; ++lvl) { - RootT* root; Int1T* int1; Int2T* int2; LeafT* leaf; - iter.getNode(root); CPPUNIT_ASSERT(root != NULL); - iter.getNode(int1); CPPUNIT_ASSERT(iterLevel < 3 ? int1 != NULL: int1 == NULL); - iter.getNode(int2); CPPUNIT_ASSERT(iterLevel < 2 ? int2 != NULL: int2 == NULL); - iter.getNode(leaf); CPPUNIT_ASSERT(iterLevel < 1 ? leaf != NULL: leaf == NULL); - } - - if (iter.isValueOn()) { - ++numOn; - const float f = iter.getValue(); - if (openvdb::math::isZero(f)) { - CPPUNIT_ASSERT(iter.getCoord() == openvdb::Coord(4)); - CPPUNIT_ASSERT(iter.isVoxelValue()); - } else { - ASSERT_DOUBLES_EXACTLY_EQUAL(-1.0f, f); - CPPUNIT_ASSERT(iter.getCoord() == openvdb::Coord(-4)); - CPPUNIT_ASSERT(iter.isVoxelValue()); - } - } else { - ++numOff; - - // For every tenth inactive value, check that the size of - // the tile or voxel is as expected. - if (numOff % 10 == 0) { - const int dim[4] = { - 1, 1 << DIM0, 1 << (DIM1 + DIM0), 1 << (DIM2 + DIM1 + DIM0) - }; - const int lvl = iter.getLevel(); - CPPUNIT_ASSERT(lvl < 4); - openvdb::CoordBBox bbox; - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL( - bbox.extents(), openvdb::Coord(dim[lvl], dim[lvl], dim[lvl])); - } - } - } - CPPUNIT_ASSERT_EQUAL(2, int(numOn)); - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } - { - Tree323f::ValueAllCIter iter = tree.cbeginValueAll(); - CPPUNIT_ASSERT(iter.test()); - - // Read all tile and voxel values through a const value iterator. - size_t numOn = 0, numOff = 0; - for ( ; iter.test(); iter.next()) { - if (iter.isValueOn()) ++numOn; else ++numOff; - } - CPPUNIT_ASSERT_EQUAL(2, int(numOn)); - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } - { - Tree323f::ValueAllIter iter = tree.beginValueAll(); - CPPUNIT_ASSERT(iter.test()); - - // Read all tile and voxel values through a non-const value iterator - // and overwrite all active values. - size_t numOn = 0, numOff = 0; - for ( ; iter; ++iter) { - if (iter.isValueOn()) { - iter.setValue(iter.getValue() - 5); - ++numOn; - } else { - ++numOff; - } - } - CPPUNIT_ASSERT_EQUAL(2, int(numOn)); - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } -} - - -void -TestTreeIterators::testValueOnIterator() -{ - typedef openvdb::tree::Tree4::Type Tree323f; - - Tree323f tree(/*fillValue=*/256.0f); - - { - Tree323f::ValueOnIter iter = tree.beginValueOn(); - CPPUNIT_ASSERT(!iter.test()); // empty tree - } - - const int STEP = 8/*100*/, NUM_STEPS = 10; - for (int i = 0; i < NUM_STEPS; ++i) { - tree.setValue(openvdb::Coord(STEP * i), 0.0f); - } - - { - Tree323f::ValueOnIter iter = tree.beginValueOn(); - CPPUNIT_ASSERT(iter.test()); - - // Read all active tile and voxel values through a non-const value iterator. - int numOn = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(iter.isVoxelValue()); - CPPUNIT_ASSERT(iter.isValueOn()); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.0f, iter.getValue()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(STEP * numOn), iter.getCoord()); - ++numOn; - } - CPPUNIT_ASSERT_EQUAL(NUM_STEPS, numOn); - } - { - Tree323f::ValueOnCIter iter = tree.cbeginValueOn(); - CPPUNIT_ASSERT(iter.test()); - - // Read all active tile and voxel values through a const value iterator. - int numOn = 0; - for ( ; iter.test(); iter.next()) { - CPPUNIT_ASSERT(iter.isVoxelValue()); - CPPUNIT_ASSERT(iter.isValueOn()); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.0f, iter.getValue()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(STEP * numOn), iter.getCoord()); - ++numOn; - } - CPPUNIT_ASSERT_EQUAL(NUM_STEPS, numOn); - } - { - Tree323f::ValueOnIter iter = tree.beginValueOn(); - CPPUNIT_ASSERT(iter.test()); - - // Read all active tile and voxel values through a non-const value iterator - // and overwrite the values. - int numOn = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(iter.isVoxelValue()); - CPPUNIT_ASSERT(iter.isValueOn()); - ASSERT_DOUBLES_EXACTLY_EQUAL(0.0f, iter.getValue()); - iter.setValue(5.0f); - ASSERT_DOUBLES_EXACTLY_EQUAL(5.0f, iter.getValue()); - CPPUNIT_ASSERT_EQUAL(openvdb::Coord(STEP * numOn), iter.getCoord()); - ++numOn; - } - CPPUNIT_ASSERT_EQUAL(NUM_STEPS, numOn); - } -} - - -void -TestTreeIterators::testValueOffIterator() -{ - const openvdb::Index DIM0 = 3, DIM1 = 2, DIM2 = 3; - - typedef openvdb::tree::Tree4::Type Tree323f; - - Tree323f tree(/*fillValue=*/256.0f); - tree.setValue(openvdb::Coord(4), 0.0f); - tree.setValue(openvdb::Coord(-4), -1.0f); - - const size_t expectedNumOff = - 2 * ((1 << (3 * DIM2)) - 1) // 2 8x8x8 InternalNodes - 1 child pointer each - + 2 * ((1 << (3 * DIM1)) - 1) // 2 4x4x4 InternalNodes - 1 child pointer each - + 2 * ((1 << (3 * DIM0)) - 1); // 2 8x8x8 LeafNodes - 1 active value each - - { - Tree323f::ValueOffIter iter = tree.beginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - // Read all inactive tile and voxel values through a non-const value iterator. - size_t numOff = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(!iter.isValueOn()); - ++numOff; - // For every tenth inactive value, check that the size of - // the tile or voxel is as expected. - if (numOff % 10 == 0) { - const int dim[4] = { - 1, 1 << DIM0, 1 << (DIM1 + DIM0), 1 << (DIM2 + DIM1 + DIM0) - }; - const int lvl = iter.getLevel(); - CPPUNIT_ASSERT(lvl < 4); - openvdb::CoordBBox bbox; - iter.getBoundingBox(bbox); - CPPUNIT_ASSERT_EQUAL(bbox.extents(), openvdb::Coord(dim[lvl], dim[lvl], dim[lvl])); - } - } - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } - { - Tree323f::ValueOffCIter iter = tree.cbeginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - // Read all inactive tile and voxel values through a const value iterator. - size_t numOff = 0; - for ( ; iter.test(); iter.next(), ++numOff) { - CPPUNIT_ASSERT(!iter.isValueOn()); - } - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } - { - Tree323f::ValueOffIter iter = tree.beginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - // Read all inactive tile and voxel values through a non-const value iterator - // and overwrite the values. - size_t numOff = 0; - for ( ; iter; ++iter, ++numOff) { - iter.setValue(iter.getValue() - 5); - iter.setValueOff(); - } - for (iter = tree.beginValueOff(); iter; ++iter, --numOff); - CPPUNIT_ASSERT_EQUAL(size_t(0), numOff); - } -} - - -void -TestTreeIterators::testModifyValue() -{ - using openvdb::Coord; - - const openvdb::Index DIM0 = 3, DIM1 = 2, DIM2 = 3; - { - typedef openvdb::tree::Tree4::Type IntTree323f; - - IntTree323f tree(/*background=*/256); - tree.addTile(/*level=*/3, Coord(-1), /*value=*/ 4, /*active=*/true); - tree.addTile(/*level=*/2, Coord(1 << (DIM0 + DIM1)), /*value=*/-3, /*active=*/true); - tree.addTile(/*level=*/1, Coord(1 << DIM0), /*value=*/ 2, /*active=*/true); - tree.addTile(/*level=*/0, Coord(0), /*value=*/-1, /*active=*/true); - - struct Local { static inline void negate(int32_t& n) { n = -n; } }; - - for (IntTree323f::ValueAllIter iter = tree.beginValueAll(); iter; ++iter) { - iter.modifyValue(Local::negate); - } - - for (IntTree323f::ValueAllCIter iter = tree.cbeginValueAll(); iter; ++iter) { - const int32_t val = *iter; - if (val < 0) CPPUNIT_ASSERT((-val) % 2 == 0); // negative values are even - else CPPUNIT_ASSERT(val % 2 == 1); // positive values are odd - } - - // Because modifying values through a const iterator is not allowed, - // uncommenting the following line should result in a static assertion failure: - //tree.cbeginValueOn().modifyValue(Local::negate); - } - { - typedef openvdb::tree::Tree4::Type BoolTree323f; - - BoolTree323f tree; - tree.addTile(/*level=*/3, Coord(-1), /*value=*/false, /*active=*/true); - tree.addTile(/*level=*/2, Coord(1 << (DIM0 + DIM1)), /*value=*/ true, /*active=*/true); - tree.addTile(/*level=*/1, Coord(1 << DIM0), /*value=*/false, /*active=*/true); - tree.addTile(/*level=*/0, Coord(0), /*value=*/ true, /*active=*/true); - - struct Local { static inline void negate(bool& b) { b = !b; } }; - - for (BoolTree323f::ValueAllIter iter = tree.beginValueAll(); iter; ++iter) { - iter.modifyValue(Local::negate); - } - - CPPUNIT_ASSERT(!tree.getValue(Coord(0))); - CPPUNIT_ASSERT( tree.getValue(Coord(1 << DIM0))); - CPPUNIT_ASSERT(!tree.getValue(Coord(1 << (DIM0 + DIM1)))); - CPPUNIT_ASSERT( tree.getValue(Coord(-1))); - - // Because modifying values through a const iterator is not allowed, - // uncommenting the following line should result in a static assertion failure: - //tree.cbeginValueOn().modifyValue(Local::negate); - } - { - typedef openvdb::tree::Tree4::Type StringTree323f; - - StringTree323f tree(/*background=*/""); - tree.addTile(/*level=*/3, Coord(-1), /*value=*/"abc", /*active=*/true); - tree.addTile(/*level=*/2, Coord(1 << (DIM0 + DIM1)), /*value=*/"abc", /*active=*/true); - tree.addTile(/*level=*/1, Coord(1 << DIM0), /*value=*/"abc", /*active=*/true); - tree.addTile(/*level=*/0, Coord(0), /*value=*/"abc", /*active=*/true); - - struct Local { static inline void op(std::string& s) { s.append("def"); } }; - - for (StringTree323f::ValueOnIter iter = tree.beginValueOn(); iter; ++iter) { - iter.modifyValue(Local::op); - } - - const std::string expectedVal("abcdef"); - for (StringTree323f::ValueOnCIter iter = tree.cbeginValueOn(); iter; ++iter) { - CPPUNIT_ASSERT_EQUAL(expectedVal, *iter); - } - for (StringTree323f::ValueOffCIter iter = tree.cbeginValueOff(); iter; ++iter) { - CPPUNIT_ASSERT((*iter).empty()); - } - } -} - - -void -TestTreeIterators::testDepthBounds() -{ - const openvdb::Index DIM0 = 3, DIM1 = 2, DIM2 = 3; - - typedef openvdb::tree::Tree4::Type Tree323f; - - Tree323f tree(/*fillValue=*/256.0f); - tree.setValue(openvdb::Coord(4), 0.0f); - tree.setValue(openvdb::Coord(-4), -1.0f); - - const size_t - numDepth1 = 2 * ((1 << (3 * DIM2)) - 1), // 2 8x8x8 InternalNodes - 1 child pointer each - numDepth2 = 2 * ((1 << (3 * DIM1)) - 1), // 2 4x4x4 InternalNodes - 1 child pointer each - numDepth3 = 2 * ((1 << (3 * DIM0)) - 1), // 2 8x8x8 LeafNodes - 1 active value each - expectedNumOff = numDepth1 + numDepth2 + numDepth3; - - { - Tree323f::ValueOffCIter iter = tree.cbeginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - // Read all inactive tile and voxel values through a non-const value iterator. - size_t numOff = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(!iter.isValueOn()); - ++numOff; - } - CPPUNIT_ASSERT_EQUAL(expectedNumOff, numOff); - } - { - // Repeat, setting the minimum iterator depth to 2. - Tree323f::ValueOffCIter iter = tree.cbeginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - iter.setMinDepth(2); - CPPUNIT_ASSERT(iter.test()); - - size_t numOff = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(!iter.isValueOn()); - ++numOff; - const int depth = iter.getDepth(); - CPPUNIT_ASSERT(depth > 1); - } - CPPUNIT_ASSERT_EQUAL(expectedNumOff - numDepth1, numOff); - } - { - // Repeat, setting the minimum and maximum depths to 2. - Tree323f::ValueOffCIter iter = tree.cbeginValueOff(); - CPPUNIT_ASSERT(iter.test()); - - iter.setMinDepth(2); - CPPUNIT_ASSERT(iter.test()); - - iter.setMaxDepth(2); - CPPUNIT_ASSERT(iter.test()); - - size_t numOff = 0; - for ( ; iter; ++iter) { - CPPUNIT_ASSERT(!iter.isValueOn()); - ++numOff; - const int depth = iter.getDepth(); - CPPUNIT_ASSERT_EQUAL(2, depth); - } - CPPUNIT_ASSERT_EQUAL(expectedNumOff - numDepth1 - numDepth3, numOff); - } - { - // FX-7884 regression test - using namespace openvdb; - - const float radius = 4.3f, voxelSize = 0.1f, width = 2.0f; - const Vec3f center(15.8f, 13.2f, 16.7f); - FloatGrid::Ptr sphereGrid = tools::createLevelSetSphere( - radius, center, voxelSize, width); - const FloatTree& sphereTree = sphereGrid->tree(); - - FloatGrid::ValueOffIter iter = sphereGrid->beginValueOff(); - iter.setMaxDepth(2); - for ( ; iter; ++iter) { - const Coord ijk = iter.getCoord(); - ASSERT_DOUBLES_EXACTLY_EQUAL(sphereTree.getValue(ijk), *iter); - } - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestTreeVisitor.cc b/openvdb_3_0_0_library/unittest/TestTreeVisitor.cc deleted file mode 100755 index 62c9201..0000000 --- a/openvdb_3_0_0_library/unittest/TestTreeVisitor.cc +++ /dev/null @@ -1,375 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file TestTreeVisitor.h -/// -/// @author Peter Cucka - -#include -#include -#include -#include -#include -#include -#include - - -class TestTreeVisitor: public CppUnit::TestCase -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestTreeVisitor); - CPPUNIT_TEST(testVisitTreeBool); - CPPUNIT_TEST(testVisitTreeInt32); - CPPUNIT_TEST(testVisitTreeFloat); - CPPUNIT_TEST(testVisitTreeVec2I); - CPPUNIT_TEST(testVisitTreeVec3S); - CPPUNIT_TEST(testVisit2Trees); - CPPUNIT_TEST_SUITE_END(); - - void testVisitTreeBool() { visitTree(); } - void testVisitTreeInt32() { visitTree(); } - void testVisitTreeFloat() { visitTree(); } - void testVisitTreeVec2I() { visitTree(); } - void testVisitTreeVec3S() { visitTree(); } - void testVisit2Trees(); - -private: - template TreeT createTestTree() const; - template void visitTree(); -}; - - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTreeVisitor); - - -//////////////////////////////////////// - - -template -TreeT -TestTreeVisitor::createTestTree() const -{ - typedef typename TreeT::ValueType ValueT; - const ValueT zero = openvdb::zeroVal(), one = zero + 1; - - // Create a sparse test tree comprising the eight corners of - // a 200 x 200 x 200 cube. - TreeT tree(/*background=*/one); - tree.setValue(openvdb::Coord( 0, 0, 0), /*value=*/zero); - tree.setValue(openvdb::Coord(200, 0, 0), zero); - tree.setValue(openvdb::Coord( 0, 200, 0), zero); - tree.setValue(openvdb::Coord( 0, 0, 200), zero); - tree.setValue(openvdb::Coord(200, 0, 200), zero); - tree.setValue(openvdb::Coord( 0, 200, 200), zero); - tree.setValue(openvdb::Coord(200, 200, 0), zero); - tree.setValue(openvdb::Coord(200, 200, 200), zero); - - // Verify that the bounding box of all On values is 200 x 200 x 200. - openvdb::CoordBBox bbox; - CPPUNIT_ASSERT(tree.evalActiveVoxelBoundingBox(bbox)); - CPPUNIT_ASSERT(bbox.min() == openvdb::Coord(0, 0, 0)); - CPPUNIT_ASSERT(bbox.max() == openvdb::Coord(200, 200, 200)); - - return tree; -} - - -//////////////////////////////////////// - - -namespace { - -/// Single-tree visitor that accumulates node counts -class Visitor -{ -public: - typedef std::map > NodeMap; - - Visitor(): mSkipLeafNodes(false) { reset(); } - - void reset() - { - mSkipLeafNodes = false; - mNodes.clear(); - mNonConstIterUseCount = mConstIterUseCount = 0; - } - - void setSkipLeafNodes(bool b) { mSkipLeafNodes = b; } - - template - bool operator()(IterT& iter) - { - incrementIterUseCount(boost::is_const::value); - CPPUNIT_ASSERT(iter.getParentNode() != NULL); - - if (mSkipLeafNodes && iter.parent().getLevel() == 1) return true; - - typedef typename IterT::NonConstValueType ValueT; - typedef typename IterT::ChildNodeType ChildT; - ValueT value; - if (const ChildT* child = iter.probeChild(value)) { - insertChild(child); - } - return false; - } - - openvdb::Index leafCount() const - { - NodeMap::const_iterator it = mNodes.find(0); - return openvdb::Index((it != mNodes.end()) ? it->second.size() : 0); - } - openvdb::Index nonLeafCount() const - { - openvdb::Index count = 1; // root node - for (NodeMap::const_iterator i = mNodes.begin(), e = mNodes.end(); i != e; ++i) { - if (i->first != 0) count = openvdb::Index(count + i->second.size()); - } - return count; - } - - bool usedOnlyConstIterators() const - { - return (mConstIterUseCount > 0 && mNonConstIterUseCount == 0); - } - bool usedOnlyNonConstIterators() const - { - return (mConstIterUseCount == 0 && mNonConstIterUseCount > 0); - } - -private: - template - void insertChild(const ChildT* child) - { - if (child != NULL) { - const openvdb::Index level = child->getLevel(); - if (!mSkipLeafNodes || level > 0) { - mNodes[level].insert(child); - } - } - } - - void incrementIterUseCount(bool isConst) - { - if (isConst) ++mConstIterUseCount; else ++mNonConstIterUseCount; - } - - bool mSkipLeafNodes; - NodeMap mNodes; - int mNonConstIterUseCount, mConstIterUseCount; -}; - -/// Specialization for LeafNode iterators, whose ChildNodeType is void -/// (therefore can't call child->getLevel()) -template<> inline void Visitor::insertChild(const void*) {} - -} // unnamed namespace - - -template -void -TestTreeVisitor::visitTree() -{ - TreeT tree = createTestTree(); - { - // Traverse the tree, accumulating node counts. - Visitor visitor; - const_cast(tree).visit(visitor); - - CPPUNIT_ASSERT(visitor.usedOnlyConstIterators()); - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.leafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.nonLeafCount()); - } - { - // Traverse the tree, accumulating node counts as above, - // but using non-const iterators. - Visitor visitor; - tree.visit(visitor); - - CPPUNIT_ASSERT(visitor.usedOnlyNonConstIterators()); - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.leafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.nonLeafCount()); - } - { - // Traverse the tree, accumulating counts of non-leaf nodes only. - Visitor visitor; - visitor.setSkipLeafNodes(true); - const_cast(tree).visit(visitor); - - CPPUNIT_ASSERT(visitor.usedOnlyConstIterators()); - CPPUNIT_ASSERT_EQUAL(0U, visitor.leafCount()); // leaf nodes were skipped - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.nonLeafCount()); - } -} - - -//////////////////////////////////////// - - -namespace { - -/// Two-tree visitor that accumulates node counts -class Visitor2 -{ -public: - typedef std::map > NodeMap; - - Visitor2() { reset(); } - - void reset() - { - mSkipALeafNodes = mSkipBLeafNodes = false; - mANodeCount.clear(); - mBNodeCount.clear(); - } - - void setSkipALeafNodes(bool b) { mSkipALeafNodes = b; } - void setSkipBLeafNodes(bool b) { mSkipBLeafNodes = b; } - - openvdb::Index aLeafCount() const { return leafCount(/*useA=*/true); } - openvdb::Index bLeafCount() const { return leafCount(/*useA=*/false); } - openvdb::Index aNonLeafCount() const { return nonLeafCount(/*useA=*/true); } - openvdb::Index bNonLeafCount() const { return nonLeafCount(/*useA=*/false); } - - template - int operator()(AIterT& aIter, BIterT& bIter) - { - CPPUNIT_ASSERT(aIter.getParentNode() != NULL); - CPPUNIT_ASSERT(bIter.getParentNode() != NULL); - - typename AIterT::NodeType& aNode = aIter.parent(); - typename BIterT::NodeType& bNode = bIter.parent(); - - const openvdb::Index aLevel = aNode.getLevel(), bLevel = bNode.getLevel(); - mANodeCount[aLevel].insert(&aNode); - mBNodeCount[bLevel].insert(&bNode); - - int skipBranch = 0; - if (aLevel == 1 && mSkipALeafNodes) skipBranch = (skipBranch | 1); - if (bLevel == 1 && mSkipBLeafNodes) skipBranch = (skipBranch | 2); - return skipBranch; - } - -private: - openvdb::Index leafCount(bool useA) const - { - const NodeMap& theMap = (useA ? mANodeCount : mBNodeCount); - NodeMap::const_iterator it = theMap.find(0); - if (it != theMap.end()) return openvdb::Index(it->second.size()); - return 0; - } - openvdb::Index nonLeafCount(bool useA) const - { - openvdb::Index count = 0; - const NodeMap& theMap = (useA ? mANodeCount : mBNodeCount); - for (NodeMap::const_iterator i = theMap.begin(), e = theMap.end(); i != e; ++i) { - if (i->first != 0) count = openvdb::Index(count + i->second.size()); - } - return count; - } - - bool mSkipALeafNodes, mSkipBLeafNodes; - NodeMap mANodeCount, mBNodeCount; -}; - -} // unnamed namespace - - -void -TestTreeVisitor::testVisit2Trees() -{ - typedef openvdb::FloatTree TreeT; - typedef openvdb::VectorTree Tree2T; - typedef TreeT::ValueType ValueT; - - // Create a test tree. - TreeT tree = createTestTree(); - // Create another test tree of a different type but with the same topology. - Tree2T tree2 = createTestTree(); - - // Traverse both trees. - Visitor2 visitor; - tree.visit2(tree2, visitor); - - //CPPUNIT_ASSERT(visitor.usedOnlyConstIterators()); - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.aLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.leafCount(), visitor.bLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.aNonLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.nonLeafCount(), visitor.bNonLeafCount()); - - visitor.reset(); - - // Change the topology of the first tree. - tree.setValue(openvdb::Coord(-200, -200, -200), openvdb::zeroVal()); - - // Traverse both trees. - tree.visit2(tree2, visitor); - - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.aLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.leafCount(), visitor.bLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.aNonLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.nonLeafCount(), visitor.bNonLeafCount()); - - visitor.reset(); - - // Traverse the two trees in the opposite order. - tree2.visit2(tree, visitor); - - CPPUNIT_ASSERT_EQUAL(tree2.leafCount(), visitor.aLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.bLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.nonLeafCount(), visitor.aNonLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.bNonLeafCount()); - - // Repeat, skipping leaf nodes of tree2. - visitor.reset(); - visitor.setSkipALeafNodes(true); - tree2.visit2(tree, visitor); - - CPPUNIT_ASSERT_EQUAL(0U, visitor.aLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.leafCount(), visitor.bLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.nonLeafCount(), visitor.aNonLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.bNonLeafCount()); - - // Repeat, skipping leaf nodes of tree. - visitor.reset(); - visitor.setSkipBLeafNodes(true); - tree2.visit2(tree, visitor); - - CPPUNIT_ASSERT_EQUAL(tree2.leafCount(), visitor.aLeafCount()); - CPPUNIT_ASSERT_EQUAL(0U, visitor.bLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree2.nonLeafCount(), visitor.aNonLeafCount()); - CPPUNIT_ASSERT_EQUAL(tree.nonLeafCount(), visitor.bNonLeafCount()); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestValueAccessor.cc b/openvdb_3_0_0_library/unittest/TestValueAccessor.cc deleted file mode 100755 index dd09628..0000000 --- a/openvdb_3_0_0_library/unittest/TestValueAccessor.cc +++ /dev/null @@ -1,551 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - - -typedef float ValueType; -typedef openvdb::tree::Tree< - openvdb::tree::RootNode< - openvdb::tree::LeafNode > > Tree2Type; -typedef openvdb::tree::Tree< - openvdb::tree::RootNode< - openvdb::tree::InternalNode< - openvdb::tree::LeafNode, 4> > > Tree3Type; -typedef openvdb::tree::Tree4::Type Tree4Type; -typedef openvdb::tree::Tree< - openvdb::tree::RootNode< - openvdb::tree::InternalNode< - openvdb::tree::InternalNode< - openvdb::tree::InternalNode< - openvdb::tree::LeafNode, 4>, 5>, 5> > > Tree5Type; -typedef Tree4Type TreeType; - - -using namespace openvdb::tree; - -class TestValueAccessor: public CppUnit::TestFixture -{ -public: - virtual void setUp() { openvdb::initialize(); } - virtual void tearDown() { openvdb::uninitialize(); } - - CPPUNIT_TEST_SUITE(TestValueAccessor); - - CPPUNIT_TEST(testTree2Accessor); - CPPUNIT_TEST(testTree2AccessorRW); - CPPUNIT_TEST(testTree2ConstAccessor); - CPPUNIT_TEST(testTree2ConstAccessorRW); - - CPPUNIT_TEST(testTree3Accessor); - CPPUNIT_TEST(testTree3AccessorRW); - CPPUNIT_TEST(testTree3ConstAccessor); - CPPUNIT_TEST(testTree3ConstAccessorRW); - - CPPUNIT_TEST(testTree4Accessor); - CPPUNIT_TEST(testTree4AccessorRW); - CPPUNIT_TEST(testTree4ConstAccessor); - CPPUNIT_TEST(testTree4ConstAccessorRW); - - CPPUNIT_TEST(testTree5Accessor); - CPPUNIT_TEST(testTree5AccessorRW); - CPPUNIT_TEST(testTree5ConstAccessor); - CPPUNIT_TEST(testTree5ConstAccessorRW); - - CPPUNIT_TEST(testTree3Accessor2); - CPPUNIT_TEST(testTree3ConstAccessor2); - CPPUNIT_TEST(testTree4Accessor2); - CPPUNIT_TEST(testTree4ConstAccessor2); - CPPUNIT_TEST(testTree4Accessor1); - CPPUNIT_TEST(testTree4ConstAccessor1); - CPPUNIT_TEST(testTree4Accessor0); - CPPUNIT_TEST(testTree4ConstAccessor0); - CPPUNIT_TEST(testTree5Accessor2); - CPPUNIT_TEST(testTree5ConstAccessor2); - CPPUNIT_TEST(testTree4Accessor12);//cache node level 2 - CPPUNIT_TEST(testTree5Accessor213);//cache node level 1 and 3 - - CPPUNIT_TEST(testMultithreadedAccessor); - CPPUNIT_TEST(testAccessorRegistration); - CPPUNIT_TEST(testGetNode); - - CPPUNIT_TEST_SUITE_END(); - // cache all node levels - void testTree2Accessor() { accessorTest >(); } - void testTree2AccessorRW() { accessorTest >(); } - void testTree2ConstAccessor() { constAccessorTest >(); } - void testTree2ConstAccessorRW() { constAccessorTest >(); } - // cache all node levels - void testTree3Accessor() { accessorTest >(); } - void testTree3AccessorRW() { accessorTest >(); } - void testTree3ConstAccessor() { constAccessorTest >(); } - void testTree3ConstAccessorRW() { constAccessorTest >(); } - // cache all node levels - void testTree4Accessor() { accessorTest >(); } - void testTree4AccessorRW() { accessorTest >(); } - void testTree4ConstAccessor() { constAccessorTest >(); } - void testTree4ConstAccessorRW() { constAccessorTest >(); } - // cache all node levels - void testTree5Accessor() { accessorTest >(); } - void testTree5AccessorRW() { accessorTest >(); } - void testTree5ConstAccessor() { constAccessorTest >(); } - void testTree5ConstAccessorRW() { constAccessorTest >(); } - - // Test odd combinations of trees and ValueAccessors - // cache node level 0 and 1 - void testTree3Accessor2() { accessorTest >(); } - void testTree3ConstAccessor2() { constAccessorTest >(); } - void testTree4Accessor2() { accessorTest >(); } - void testTree4ConstAccessor2() { constAccessorTest >(); } - void testTree5Accessor2() { accessorTest >(); } - void testTree5ConstAccessor2() { constAccessorTest >(); } - // only cache leaf level - void testTree4Accessor1() { accessorTest >(); } - void testTree4ConstAccessor1() { constAccessorTest >(); } - // disable node caching - void testTree4Accessor0() { accessorTest >(); } - void testTree4ConstAccessor0() { constAccessorTest >(); } - //cache node level 2 - void testTree4Accessor12() { accessorTest >(); } - //cache node level 1 and 3 - void testTree5Accessor213() { accessorTest >(); } - - void testMultithreadedAccessor(); - void testAccessorRegistration(); - void testGetNode(); - -private: - template void accessorTest(); - template void constAccessorTest(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestValueAccessor); - - -//////////////////////////////////////// - - -namespace { - -struct Plus -{ - float addend; - Plus(float f): addend(f) {} - inline void operator()(float& f) const { f += addend; } - inline void operator()(float& f, bool& b) const { f += addend; b = false; } -}; - -} - - -template -void -TestValueAccessor::accessorTest() -{ - typedef typename AccessorT::TreeType TreeType; - const int leafDepth = int(TreeType::DEPTH) - 1; - // subtract one because getValueDepth() returns 0 for values at the root - - const ValueType background = 5.0f, value = -9.345f; - const openvdb::Coord c0(5, 10, 20), c1(500000, 200000, 300000); - - { - TreeType tree(background); - CPPUNIT_ASSERT(!tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c1)); - tree.setValue(c0, value); - CPPUNIT_ASSERT(tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c1)); - } - { - TreeType tree(background); - AccessorT acc(tree); - ValueType v; - - CPPUNIT_ASSERT(!tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT(!acc.isCached(c1)); - CPPUNIT_ASSERT(!acc.probeValue(c0,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT(!acc.probeValue(c1,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(!acc.isVoxel(c0)); - CPPUNIT_ASSERT(!acc.isVoxel(c1)); - - acc.setValue(c0, value); - - CPPUNIT_ASSERT(tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c1)); - CPPUNIT_ASSERT(acc.probeValue(c0,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, v); - CPPUNIT_ASSERT(!acc.probeValue(c1,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); // leaf-level voxel value - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c1)); // background value - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(openvdb::Coord(7, 10, 20))); - const int depth = leafDepth == 1 ? -1 : leafDepth - 1; - CPPUNIT_ASSERT_EQUAL(depth, acc.getValueDepth(openvdb::Coord(8, 10, 20))); - CPPUNIT_ASSERT( acc.isVoxel(c0)); // leaf-level voxel value - CPPUNIT_ASSERT(!acc.isVoxel(c1)); - CPPUNIT_ASSERT( acc.isVoxel(openvdb::Coord(7, 10, 20))); - CPPUNIT_ASSERT(!acc.isVoxel(openvdb::Coord(8, 10, 20))); - - ASSERT_DOUBLES_EXACTLY_EQUAL(background, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c1)); // uncached background value - CPPUNIT_ASSERT(!acc.isValueOn(c1)); // inactive background value - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c0)); - CPPUNIT_ASSERT( - (acc.numCacheLevels()>0) == acc.isCached(c0)); // active, leaf-level voxel value - CPPUNIT_ASSERT(acc.isValueOn(c0)); - - acc.setValue(c1, value); - - CPPUNIT_ASSERT(acc.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c1)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(acc.isVoxel(c0)); - CPPUNIT_ASSERT(acc.isVoxel(c1)); - - tree.setValueOff(c1); - - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - CPPUNIT_ASSERT( acc.isValueOn(c0)); - CPPUNIT_ASSERT(!acc.isValueOn(c1)); - - acc.setValueOn(c1); - - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - CPPUNIT_ASSERT( acc.isValueOn(c0)); - CPPUNIT_ASSERT( acc.isValueOn(c1)); - - acc.modifyValueAndActiveState(c1, Plus(-value)); // subtract value & mark inactive - CPPUNIT_ASSERT(!acc.isValueOn(c1)); - - acc.modifyValue(c1, Plus(-value)); // subtract value again & mark active - - CPPUNIT_ASSERT(acc.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(-value, tree.getValue(c1)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(-value, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(acc.isVoxel(c0)); - CPPUNIT_ASSERT(acc.isVoxel(c1)); - - acc.setValueOnly(c1, 3*value); - - CPPUNIT_ASSERT(acc.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(3*value, tree.getValue(c1)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(3*value, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(acc.isVoxel(c0)); - CPPUNIT_ASSERT(acc.isVoxel(c1)); - - acc.clear(); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT(!acc.isCached(c1)); - } -} - - -template -void -TestValueAccessor::constAccessorTest() -{ - typedef typename boost::remove_const::type TreeType; - const int leafDepth = int(TreeType::DEPTH) - 1; - // subtract one because getValueDepth() returns 0 for values at the root - - const ValueType background = 5.0f, value = -9.345f; - const openvdb::Coord c0(5, 10, 20), c1(500000, 200000, 300000); - ValueType v; - - TreeType tree(background); - AccessorT acc(tree); - - CPPUNIT_ASSERT(!tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, tree.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT(!acc.isCached(c1)); - CPPUNIT_ASSERT(!acc.probeValue(c0,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT(!acc.probeValue(c1,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(!acc.isVoxel(c0)); - CPPUNIT_ASSERT(!acc.isVoxel(c1)); - - tree.setValue(c0, value); - - CPPUNIT_ASSERT(tree.isValueOn(c0)); - CPPUNIT_ASSERT(!tree.isValueOn(c1)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT(acc.isValueOn(c0)); - CPPUNIT_ASSERT(!acc.isValueOn(c1)); - CPPUNIT_ASSERT(acc.probeValue(c0,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(value, v); - CPPUNIT_ASSERT(!acc.probeValue(c1,v)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, v); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(-1, acc.getValueDepth(c1)); - CPPUNIT_ASSERT( acc.isVoxel(c0)); - CPPUNIT_ASSERT(!acc.isVoxel(c1)); - - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c0)); - ASSERT_DOUBLES_EXACTLY_EQUAL(background, acc.getValue(c1)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c0)); - CPPUNIT_ASSERT(!acc.isCached(c1)); - CPPUNIT_ASSERT(acc.isValueOn(c0)); - CPPUNIT_ASSERT(!acc.isValueOn(c1)); - - tree.setValue(c1, value); - - ASSERT_DOUBLES_EXACTLY_EQUAL(value, acc.getValue(c1)); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT((acc.numCacheLevels()>0) == acc.isCached(c1)); - CPPUNIT_ASSERT(acc.isValueOn(c0)); - CPPUNIT_ASSERT(acc.isValueOn(c1)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c0)); - CPPUNIT_ASSERT_EQUAL(leafDepth, acc.getValueDepth(c1)); - CPPUNIT_ASSERT(acc.isVoxel(c0)); - CPPUNIT_ASSERT(acc.isVoxel(c1)); - - // The next two lines should not compile, because the acc references a const tree: - //acc.setValue(c1, value); - //acc.setValueOff(c1); - - acc.clear(); - CPPUNIT_ASSERT(!acc.isCached(c0)); - CPPUNIT_ASSERT(!acc.isCached(c1)); -} - - -void -TestValueAccessor::testMultithreadedAccessor() -{ -#define MAX_COORD 5000 - - typedef openvdb::tree::ValueAccessorRW AccessorT; - // Substituting the following typedef typically results in assertion failures: - //typedef openvdb::tree::ValueAccessor AccessorT; - - // Task to perform multiple reads through a shared accessor - struct ReadTask: public tbb::task { - AccessorT& acc; - ReadTask(AccessorT& c): acc(c) {} - tbb::task* execute() - { - for (int i = -MAX_COORD; i < MAX_COORD; ++i) { - ASSERT_DOUBLES_EXACTLY_EQUAL(double(i), acc.getValue(openvdb::Coord(i))); - } - return NULL; - } - }; - // Task to perform multiple writes through a shared accessor - struct WriteTask: public tbb::task { - AccessorT& acc; - WriteTask(AccessorT& c): acc(c) {} - tbb::task* execute() - { - for (int i = -MAX_COORD; i < MAX_COORD; ++i) { - float f = acc.getValue(openvdb::Coord(i)); - ASSERT_DOUBLES_EXACTLY_EQUAL(float(i), f); - acc.setValue(openvdb::Coord(i), float(i)); - ASSERT_DOUBLES_EXACTLY_EQUAL(float(i), acc.getValue(openvdb::Coord(i))); - } - return NULL; - } - }; - // Parent task to spawn multiple parallel read and write tasks - struct RootTask: public tbb::task { - AccessorT& acc; - RootTask(AccessorT& c): acc(c) {} - tbb::task* execute() - { - ReadTask* r[3]; WriteTask* w[3]; - for (int i = 0; i < 3; ++i) { - r[i] = new(allocate_child()) ReadTask(acc); - w[i] = new(allocate_child()) WriteTask(acc); - } - set_ref_count(6 /*children*/ + 1 /*wait*/); - for (int i = 0; i < 3; ++i) { - spawn(*r[i]); spawn(*w[i]); - } - wait_for_all(); - return NULL; - } - }; - - Tree4Type tree(/*background=*/0.5); - AccessorT acc(tree); - // Populate the tree. - for (int i = -MAX_COORD; i < MAX_COORD; ++i) { - acc.setValue(openvdb::Coord(i), float(i)); - } - - // Run multiple read and write tasks in parallel. - RootTask& root = *new(tbb::task::allocate_root()) RootTask(acc); - tbb::task::spawn_root_and_wait(root); - -#undef MAX_COORD -} - - -void -TestValueAccessor::testAccessorRegistration() -{ - using openvdb::Index; - - const float background = 5.0f, value = -9.345f; - const openvdb::Coord c0(5, 10, 20); - - openvdb::FloatTree::Ptr tree(new openvdb::FloatTree(background)); - openvdb::tree::ValueAccessor acc(*tree); - - // Set a single leaf voxel via the accessor and verify that - // the cache is populated. - acc.setValue(c0, value); - CPPUNIT_ASSERT_EQUAL(Index(1), tree->leafCount()); - CPPUNIT_ASSERT_EQUAL(tree->root().getLevel(), tree->nonLeafCount()); - CPPUNIT_ASSERT(acc.getNode() != NULL); - - // Reset the voxel to the background value and verify that no nodes - // have been deleted and that the cache is still populated. - tree->setValueOff(c0, background); - CPPUNIT_ASSERT_EQUAL(Index(1), tree->leafCount()); - CPPUNIT_ASSERT_EQUAL(tree->root().getLevel(), tree->nonLeafCount()); - CPPUNIT_ASSERT(acc.getNode() != NULL); - - // Prune the tree and verify that only the root node remains and that - // the cache has been cleared. - openvdb::tools::prune(*tree); - //tree->prune(); - CPPUNIT_ASSERT_EQUAL(Index(0), tree->leafCount()); - CPPUNIT_ASSERT_EQUAL(Index(1), tree->nonLeafCount()); // root node only - CPPUNIT_ASSERT(acc.getNode() == NULL); - - // Set the leaf voxel again and verify that the cache is repopulated. - acc.setValue(c0, value); - CPPUNIT_ASSERT_EQUAL(Index(1), tree->leafCount()); - CPPUNIT_ASSERT_EQUAL(tree->root().getLevel(), tree->nonLeafCount()); - CPPUNIT_ASSERT(acc.getNode() != NULL); - - // Delete the tree and verify that the cache has been cleared. - tree.reset(); - CPPUNIT_ASSERT(acc.getTree() == NULL); - CPPUNIT_ASSERT(acc.getNode() == NULL); - CPPUNIT_ASSERT(acc.getNode() == NULL); -} - - -void -TestValueAccessor::testGetNode() -{ - typedef Tree4Type::LeafNodeType LeafT; - - const ValueType background = 5.0f, value = -9.345f; - const openvdb::Coord c0(5, 10, 20); - - Tree4Type tree(background); - tree.setValue(c0, value); - { - openvdb::tree::ValueAccessor acc(tree); - // Prime the cache. - acc.getValue(c0); - // Verify that the cache contains a leaf node. - LeafT* node = acc.getNode(); - CPPUNIT_ASSERT(node != NULL); - - // Erase the leaf node from the cache and verify that it is gone. - acc.eraseNode(); - node = acc.getNode(); - CPPUNIT_ASSERT(node == NULL); - } - { - // As above, but with a const tree. - openvdb::tree::ValueAccessor acc(tree); - acc.getValue(c0); - const LeafT* node = acc.getNode(); - CPPUNIT_ASSERT(node != NULL); - - acc.eraseNode(); - node = acc.getNode(); - CPPUNIT_ASSERT(node == NULL); - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestVec2Metadata.cc b/openvdb_3_0_0_library/unittest/TestVec2Metadata.cc deleted file mode 100755 index e0f96ae..0000000 --- a/openvdb_3_0_0_library/unittest/TestVec2Metadata.cc +++ /dev/null @@ -1,128 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestVec2Metadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestVec2Metadata); - CPPUNIT_TEST(testVec2i); - CPPUNIT_TEST(testVec2s); - CPPUNIT_TEST(testVec2d); - CPPUNIT_TEST_SUITE_END(); - - void testVec2i(); - void testVec2s(); - void testVec2d(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestVec2Metadata); - -void -TestVec2Metadata::testVec2i() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec2IMetadata(openvdb::Vec2i(1, 1))); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("vec2i") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("vec2i") == 0); - - Vec2IMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2i(1, 1)); - s->value() = openvdb::Vec2i(2, 2); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2i(2, 2)); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2i(2, 2)); -} - -void -TestVec2Metadata::testVec2s() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec2SMetadata(openvdb::Vec2s(1, 1))); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("vec2s") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("vec2s") == 0); - - Vec2SMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2s(1, 1)); - s->value() = openvdb::Vec2s(2, 2); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2s(2, 2)); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2s(2, 2)); -} - -void -TestVec2Metadata::testVec2d() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec2DMetadata(openvdb::Vec2d(1, 1))); - Metadata::Ptr m2 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast(m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m2.get()) != 0); - - CPPUNIT_ASSERT(m->typeName().compare("vec2d") == 0); - CPPUNIT_ASSERT(m2->typeName().compare("vec2d") == 0); - - Vec2DMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2d(1, 1)); - s->value() = openvdb::Vec2d(2, 2); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2d(2, 2)); - - m2->copy(*s); - - s = dynamic_cast(m2.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec2d(2, 2)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestVec3Metadata.cc b/openvdb_3_0_0_library/unittest/TestVec3Metadata.cc deleted file mode 100755 index 04691b9..0000000 --- a/openvdb_3_0_0_library/unittest/TestVec3Metadata.cc +++ /dev/null @@ -1,128 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class TestVec3Metadata : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestVec3Metadata); - CPPUNIT_TEST(testVec3i); - CPPUNIT_TEST(testVec3s); - CPPUNIT_TEST(testVec3d); - CPPUNIT_TEST_SUITE_END(); - - void testVec3i(); - void testVec3s(); - void testVec3d(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestVec3Metadata); - -void -TestVec3Metadata::testVec3i() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec3IMetadata(openvdb::Vec3i(1, 1, 1))); - Metadata::Ptr m3 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast( m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m3.get()) != 0); - - CPPUNIT_ASSERT( m->typeName().compare("vec3i") == 0); - CPPUNIT_ASSERT(m3->typeName().compare("vec3i") == 0); - - Vec3IMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3i(1, 1, 1)); - s->value() = openvdb::Vec3i(3, 3, 3); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3i(3, 3, 3)); - - m3->copy(*s); - - s = dynamic_cast(m3.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3i(3, 3, 3)); -} - -void -TestVec3Metadata::testVec3s() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec3SMetadata(openvdb::Vec3s(1, 1, 1))); - Metadata::Ptr m3 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast( m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m3.get()) != 0); - - CPPUNIT_ASSERT( m->typeName().compare("vec3s") == 0); - CPPUNIT_ASSERT(m3->typeName().compare("vec3s") == 0); - - Vec3SMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3s(1, 1, 1)); - s->value() = openvdb::Vec3s(3, 3, 3); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3s(3, 3, 3)); - - m3->copy(*s); - - s = dynamic_cast(m3.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3s(3, 3, 3)); -} - -void -TestVec3Metadata::testVec3d() -{ - using namespace openvdb; - - Metadata::Ptr m(new Vec3DMetadata(openvdb::Vec3d(1, 1, 1))); - Metadata::Ptr m3 = m->copy(); - - CPPUNIT_ASSERT(dynamic_cast( m.get()) != 0); - CPPUNIT_ASSERT(dynamic_cast(m3.get()) != 0); - - CPPUNIT_ASSERT( m->typeName().compare("vec3d") == 0); - CPPUNIT_ASSERT(m3->typeName().compare("vec3d") == 0); - - Vec3DMetadata *s = dynamic_cast(m.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3d(1, 1, 1)); - s->value() = openvdb::Vec3d(3, 3, 3); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3d(3, 3, 3)); - - m3->copy(*s); - - s = dynamic_cast(m3.get()); - CPPUNIT_ASSERT(s->value() == openvdb::Vec3d(3, 3, 3)); -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestVolumeRayIntersector.cc b/openvdb_3_0_0_library/unittest/TestVolumeRayIntersector.cc deleted file mode 100755 index 5defed6..0000000 --- a/openvdb_3_0_0_library/unittest/TestVolumeRayIntersector.cc +++ /dev/null @@ -1,336 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -/// @author Ken Museth - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define ASSERT_DOUBLES_EXACTLY_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/0.0); - -#define ASSERT_DOUBLES_APPROX_EQUAL(expected, actual) \ - CPPUNIT_ASSERT_DOUBLES_EQUAL((expected), (actual), /*tolerance=*/1.e-6); - - -class TestVolumeRayIntersector : public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestVolumeRayIntersector); - CPPUNIT_TEST(testAll); - CPPUNIT_TEST_SUITE_END(); - - void testAll(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestVolumeRayIntersector); - -void -TestVolumeRayIntersector::testAll() -{ - using namespace openvdb; - typedef math::Ray RayT; - typedef RayT::Vec3Type Vec3T; - - {//one single leaf node - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0,0,0), 1.0f); - grid.tree().setValue(Coord(7,7,7), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL( 9.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//same as above but with dilation - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0,0,0), 1.0f); - grid.tree().setValue(Coord(7,7,7), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid, 1); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 0.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//one single leaf node - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(1,1,1), 1.0f); - grid.tree().setValue(Coord(7,3,3), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL( 9.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//same as above but with dilation - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(1,1,1), 1.0f); - grid.tree().setValue(Coord(7,3,3), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid, 1); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//two adjacent leaf nodes - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0,0,0), 1.0f); - grid.tree().setValue(Coord(8,0,0), 1.0f); - grid.tree().setValue(Coord(15,7,7), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//two adjacent leafs followed by a gab and leaf - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0*8,0,0), 1.0f); - grid.tree().setValue(Coord(1*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8+7,7,7), 1.0f); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, t1); - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL(25.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(33.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - {//two adjacent leafs followed by a gab, a leaf and an active tile - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0*8,0,0), 1.0f); - grid.tree().setValue(Coord(1*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8,0,0), 1.0f); - grid.fill(CoordBBox(Coord(4*8,0,0), Coord(4*8+7,7,7)), 2.0f, true); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, t1); - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL(25.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(41.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - - {//two adjacent leafs followed by a gab, a leaf and an active tile - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0*8,0,0), 1.0f); - grid.tree().setValue(Coord(1*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8,0,0), 1.0f); - grid.fill(CoordBBox(Coord(4*8,0,0), Coord(4*8+7,7,7)), 2.0f, true); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - - std::vector list; - inter.hits(list); - CPPUNIT_ASSERT(list.size() == 2); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, list[0].t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, list[0].t1); - ASSERT_DOUBLES_APPROX_EQUAL(25.0, list[1].t0); - ASSERT_DOUBLES_APPROX_EQUAL(41.0, list[1].t1); - } - - {//same as above but now with std::deque instead of std::vector - FloatGrid grid(0.0f); - - grid.tree().setValue(Coord(0*8,0,0), 1.0f); - grid.tree().setValue(Coord(1*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8,0,0), 1.0f); - grid.fill(CoordBBox(Coord(4*8,0,0), Coord(4*8+7,7,7)), 2.0f, true); - - const Vec3T dir( 1.0, 0.0, 0.0); - const Vec3T eye(-1.0, 0.0, 0.0); - const RayT ray(eye, dir);//ray in index space - tools::VolumeRayIntersector inter(grid); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - - std::deque list; - inter.hits(list); - CPPUNIT_ASSERT(list.size() == 2); - ASSERT_DOUBLES_APPROX_EQUAL( 1.0, list[0].t0); - ASSERT_DOUBLES_APPROX_EQUAL(17.0, list[0].t1); - ASSERT_DOUBLES_APPROX_EQUAL(25.0, list[1].t0); - ASSERT_DOUBLES_APPROX_EQUAL(41.0, list[1].t1); - } - - {// Test submitted by "Jan" @ GitHub - FloatGrid grid(0.0f); - grid.tree().setValue(Coord(0*8,0,0), 1.0f); - grid.tree().setValue(Coord(1*8,0,0), 1.0f); - grid.tree().setValue(Coord(3*8,0,0), 1.0f); - tools::VolumeRayIntersector inter(grid); - - const Vec3T dir(-1.0, 0.0, 0.0); - const Vec3T eye(50.0, 0.0, 0.0); - const RayT ray(eye, dir); - CPPUNIT_ASSERT(inter.setIndexRay(ray)); - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL(18.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(26.0, t1); - CPPUNIT_ASSERT(inter.march(t0, t1)); - ASSERT_DOUBLES_APPROX_EQUAL(34.0, t0); - ASSERT_DOUBLES_APPROX_EQUAL(50.0, t1); - CPPUNIT_ASSERT(!inter.march(t0, t1)); - } - - {// Test submitted by "Trevor" @ GitHub - - FloatGrid::Ptr grid = createGrid(0.0f); - grid->tree().setValue(Coord(0,0,0), 1.0f); - tools::dilateVoxels(grid->tree()); - tools::VolumeRayIntersector inter(*grid); - - //std::cerr << "BBox = " << inter.bbox() << std::endl; - - const Vec3T eye(-0.25, -0.25, 10.0); - const Vec3T dir( 0.00, 0.00, -1.0); - const RayT ray(eye, dir); - CPPUNIT_ASSERT(inter.setIndexRay(ray));// hits bbox - - double t0=0, t1=0; - CPPUNIT_ASSERT(!inter.march(t0, t1));// misses leafs - } - - {// Test submitted by "Trevor" @ GitHub - - FloatGrid::Ptr grid = createGrid(0.0f); - grid->tree().setValue(Coord(0,0,0), 1.0f); - tools::dilateVoxels(grid->tree()); - tools::VolumeRayIntersector inter(*grid); - - //GridPtrVec grids; - //grids.push_back(grid); - //io::File vdbfile("/tmp/trevor_v1.vdb"); - //vdbfile.write(grids); - - //std::cerr << "BBox = " << inter.bbox() << std::endl; - - const Vec3T eye(0.75, 0.75, 10.0); - const Vec3T dir( 0.00, 0.00, -1.0); - const RayT ray(eye, dir); - CPPUNIT_ASSERT(inter.setIndexRay(ray));// hits bbox - - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1));// misses leafs - //std::cerr << "t0=" << t0 << " t1=" << t1 << std::endl; - } - - {// Test derived from the test submitted by "Trevor" @ GitHub - - FloatGrid grid(0.0f); - grid.fill(math::CoordBBox(Coord(-1,-1,-1),Coord(1,1,1)), 1.0f); - tools::VolumeRayIntersector inter(grid); - //std::cerr << "BBox = " << inter.bbox() << std::endl; - - const Vec3T eye(-0.25, -0.25, 10.0); - const Vec3T dir( 0.00, 0.00, -1.0); - const RayT ray(eye, dir); - CPPUNIT_ASSERT(inter.setIndexRay(ray));// hits bbox - - double t0=0, t1=0; - CPPUNIT_ASSERT(inter.march(t0, t1));// hits leafs - //std::cerr << "t0=" << t0 << " t1=" << t1 << std::endl; - } -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/TestVolumeToMesh.cc b/openvdb_3_0_0_library/unittest/TestVolumeToMesh.cc deleted file mode 100755 index f4e9e44..0000000 --- a/openvdb_3_0_0_library/unittest/TestVolumeToMesh.cc +++ /dev/null @@ -1,141 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include - -#include -#include -#include - -#include - -class TestVolumeToMesh: public CppUnit::TestCase -{ -public: - CPPUNIT_TEST_SUITE(TestVolumeToMesh); - CPPUNIT_TEST(testAuxData); - CPPUNIT_TEST(testConversion); - CPPUNIT_TEST_SUITE_END(); - - void testAuxData(); - void testConversion(); -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestVolumeToMesh); - - -//////////////////////////////////////// - - -void -TestVolumeToMesh::testAuxData() -{ - typedef openvdb::tree::Tree4::Type Tree543f; - Tree543f::Ptr tree(new Tree543f(0)); - - // create one voxel with 3 upwind edges (that have a sign change) - tree->setValue(openvdb::Coord(0,0,0), -1); - tree->setValue(openvdb::Coord(1,0,0), 1); - tree->setValue(openvdb::Coord(0,1,0), 1); - tree->setValue(openvdb::Coord(0,0,1), 1); - - typedef openvdb::tree::LeafManager LeafManager; - - LeafManager leafs(*tree); - - CPPUNIT_ASSERT(openvdb::tools::internal::needsActiveVoxePadding(leafs, 0.0, 1.0)); - - openvdb::tools::internal::SignData op(*tree, leafs, 0.0); - op.run(); - - CPPUNIT_ASSERT(op.signTree()->activeVoxelCount() == 1); - CPPUNIT_ASSERT(op.signTree()->activeVoxelCount() == op.idxTree()->activeVoxelCount()); - - - int flags = int(op.signTree()->getValue(openvdb::Coord(0,0,0))); - - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::INSIDE)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::EDGES)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::XEDGE)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::YEDGE)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::ZEDGE)); - - - tree->setValueOff(openvdb::Coord(0,0,1), -1); - op.run(); - - CPPUNIT_ASSERT(op.signTree()->activeVoxelCount() == 1); - CPPUNIT_ASSERT(op.signTree()->activeVoxelCount() == op.idxTree()->activeVoxelCount()); - - flags = int(op.signTree()->getValue(openvdb::Coord(0,0,0))); - - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::INSIDE)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::EDGES)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::XEDGE)); - CPPUNIT_ASSERT(bool(flags & openvdb::tools::internal::YEDGE)); - CPPUNIT_ASSERT(!bool(flags & openvdb::tools::internal::ZEDGE)); -} - - -void -TestVolumeToMesh::testConversion() -{ - using namespace openvdb; - - typedef tree::Tree4::Type Tree543f; - typedef Grid GridType; - - GridType::Ptr grid = createGrid(/*background=*/1); - - grid->fill(CoordBBox(Coord(0), Coord(7)), 0.0); - grid->fill(CoordBBox(Coord(1), Coord(6)), -1.0); - - std::vector points; - std::vector quads; - std::vector triangles; - - openvdb::tools::volumeToMesh(*grid, points, quads); - CPPUNIT_ASSERT(points.size() >= 4); - CPPUNIT_ASSERT(!quads.empty()); - /// @todo validate output - - points.clear(); - quads.clear(); - triangles.clear(); - - tools::volumeToMesh(*grid, points, triangles, quads, /*isovalue=*/0.01, /*adaptivity=*/0); - CPPUNIT_ASSERT(points.size() >= 3); - CPPUNIT_ASSERT(!triangles.empty() || !quads.empty()); - /// @todo validate output -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/main.cc b/openvdb_3_0_0_library/unittest/main.cc deleted file mode 100755 index 7225fe1..0000000 --- a/openvdb_3_0_0_library/unittest/main.cc +++ /dev/null @@ -1,217 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifdef DWA_OPENVDB - -#include -#include - -#else - -#include // for EXIT_SUCCESS -#include // for strrchr() -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef OPENVDB_USE_LOG4CPLUS -#include -#include -#include -#endif - - -void -usage(const char* progName) -{ - std::cerr << - "Usage: " << progName << " [options]\n" << - "Which: runs OpenVDB library unit tests\n" << - "Options:\n" << - " -l list all available tests\n" << - " -t test specific suite or test to run, e.g., \"-t TestGrid\"\n" << - " or \"-t TestGrid::testGetGrid\" (default: run all tests)\n" << - " -v verbose output\n"; -#ifdef OPENVDB_USE_LOG4CPLUS - std::cerr << "\n" << - " -error log fatal and non-fatal errors (default: log only fatal errors)\n" << - " -warn log warnings and errors\n" << - " -info log info messages, warnings and errors\n" << - " -debug log debugging messages, info messages, warnings and errors\n"; -#endif -} - - -static void -dump(CppUnit::Test* test) -{ - if (test == NULL) { - std::cerr << "Error: no tests found\n"; - return; - } - - std::cout << test->getName() << std::endl; - for (int i = 0; i < test->getChildTestCount(); i++) { - dump(test->getChildTestAt(i)); - } -} - - -int -run(int argc, char* argv[]) -{ - const char* progName = argv[0]; - if (const char* ptr = ::strrchr(progName, '/')) progName = ptr + 1; - - bool verbose = false; - std::vector tests; - for (int i = 1; i < argc; ++i) { - const std::string arg = argv[i]; - if (arg == "-l") { - dump(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); - return EXIT_SUCCESS; - } else if (arg == "-v") { - verbose = true; - } else if (arg == "-t") { - if (i + 1 < argc) { - ++i; - tests.push_back(argv[i]); - } else { - usage(progName); - return EXIT_FAILURE; - } - } else if (arg == "-h" || arg == "-help" || arg == "--help") { - usage(progName); - return EXIT_SUCCESS; - } else { - std::cerr << progName << ": unrecognized option '" << arg << "'\n"; - usage(progName); - return EXIT_FAILURE; - } - } - if (tests.empty()) tests.push_back(""); // run all tests - - try { - CppUnit::TestFactoryRegistry& registry = - CppUnit::TestFactoryRegistry::getRegistry(); - - CppUnit::TestRunner runner; - runner.addTest(registry.makeTest()); - - CppUnit::TestResult controller; - - CppUnit::TestResultCollector result; - controller.addListener(&result); - - CppUnit::TextTestProgressListener progress; - CppUnit::BriefTestProgressListener vProgress; - if (verbose) { - controller.addListener(&vProgress); - } else { - controller.addListener(&progress); - } - - for (size_t i = 0; i < tests.size(); ++i) { - runner.run(controller, tests[i]); - } - - CppUnit::CompilerOutputter outputter(&result, std::cerr); - outputter.write(); - - return result.wasSuccessful() ? EXIT_SUCCESS : EXIT_FAILURE; - - } catch (std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - return EXIT_FAILURE; - } -} -#endif - - -int -main(int argc, char *argv[]) -{ -#ifdef DWA_OPENVDB - - // Disable logging by default ("-quiet") unless overridden - // with "-debug" or "-info". - bool quiet = false; - { - std::vector args(argv, argv + argc); - int numArgs = int(args.size()); - logging_base::Config config(numArgs, &args[0]); - quiet = (!config.useInfo() && !config.useDebug()); - } - const std::string quietArg("-quiet"); - std::vector args(argv, argv + argc); - if (quiet) args.insert(++args.begin(), quietArg.c_str()); - int numArgs = int(args.size()); - - logging_base::Config config(numArgs, &args[0]); - logging_base::configure(config); - - return pdevunit::run(numArgs, const_cast(&args[0])); - -#else // ifndef DWA_OPENVDB - -#ifndef OPENVDB_USE_LOG4CPLUS - return run(argc, argv); -#else - log4cplus::BasicConfigurator::doConfigure(); - - std::vector args; - args.push_back(argv[0]); - - log4cplus::Logger log = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main")); - log.setLogLevel(log4cplus::FATAL_LOG_LEVEL); - for (int i = 1; i < argc; ++i) { - char* arg = argv[i]; - if (std::string("-info") == arg) log.setLogLevel(log4cplus::INFO_LOG_LEVEL); - else if (std::string("-warn") == arg) log.setLogLevel(log4cplus::WARN_LOG_LEVEL); - else if (std::string("-error") == arg) log.setLogLevel(log4cplus::ERROR_LOG_LEVEL); - else if (std::string("-debug") == arg) log.setLogLevel(log4cplus::DEBUG_LOG_LEVEL); - else args.push_back(arg); - } - - return run(int(args.size()), &args[0]); -#endif // OPENVDB_USE_LOG4CPLUS - -#endif // DWA_OPENVDB -} - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/unittest/util.h b/openvdb_3_0_0_library/unittest/util.h deleted file mode 100755 index ac7b0c7..0000000 --- a/openvdb_3_0_0_library/unittest/util.h +++ /dev/null @@ -1,130 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_UNITTEST_UTIL_HAS_BEEN_INCLUDED -#define OPENVDB_UNITTEST_UTIL_HAS_BEEN_INCLUDED - -#include -#include // for pruneLevelSet -#include - -namespace unittest_util { - -enum SphereMode { SPHERE_DENSE, SPHERE_DENSE_NARROW_BAND, SPHERE_SPARSE_NARROW_BAND }; - -/// @brief Generates the signed distance to a sphere located at @a center -/// and with a specified @a radius (both in world coordinates). Only voxels -/// in the domain [0,0,0] -> @a dim are considered. Also note that the -/// level set is either dense, dense narrow-band or sparse narrow-band. -/// -/// @note This method is VERY SLOW and should only be used for debugging purposes! -/// However it works for any transform and even with open level sets. -/// A faster approch for closed narrow band generation is to only set voxels -/// sparsely and then use grid::signedFloodFill to defined the sign -/// of the background values and tiles! This is implemented in openvdb/tools/LevelSetSphere.h -template -inline void -makeSphere(const openvdb::Coord& dim, const openvdb::Vec3f& center, float radius, - GridType& grid, SphereMode mode) -{ - typedef typename GridType::ValueType ValueT; - const ValueT - zero = openvdb::zeroVal(), - outside = grid.background(), - inside = -outside; - - typename GridType::Accessor acc = grid.getAccessor(); - openvdb::Coord xyz; - for (xyz[0]=0; xyz[0] -inline void -makeSphere(const openvdb::Coord& dim, const openvdb::Vec3f& center, - float radius, openvdb::BoolGrid& grid, SphereMode) -{ - openvdb::BoolGrid::Accessor acc = grid.getAccessor(); - openvdb::Coord xyz; - for (xyz[0]=0; xyz[0]((p-center).length() - radius); - if (dist <= 0) acc.setValue(xyz, true); - } - } - } -} - -// This method will soon be replaced by the one above!!!!! -template -inline void -makeSphere(const openvdb::Coord& dim, const openvdb::Vec3f& center, float radius, - GridType &grid, float dx, SphereMode mode) -{ - grid.setTransform(openvdb::math::Transform::createLinearTransform(/*voxel size=*/dx)); - makeSphere(dim, center, radius, grid, mode); -} - -// @todo makePlane - -} // namespace unittest_util - -#endif // OPENVDB_UNITTEST_UTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/CpuTimer.h b/openvdb_3_0_0_library/util/CpuTimer.h deleted file mode 100755 index 987dee7..0000000 --- a/openvdb_3_0_0_library/util/CpuTimer.h +++ /dev/null @@ -1,107 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_UTIL_CPUTIMER_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_CPUTIMER_HAS_BEEN_INCLUDED - -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -/// @brief Simple timer for basic profiling. -/// @code -/// Cputimer timer; -/// timer.start("My algorithm"); -/// // code to be timed goes here -/// timer.stop(); -/// @endcode -class CpuTimer -{ -public: - - /// @brief Initiate timer - CpuTimer() : mT0(tbb::tick_count::now()) {} - - /// @brief Restart timer - /// @note Should normally be followed by a call to time() - inline void start() { mT0 = tbb::tick_count::now(); } - - /// @brief Print message and re-start timer. - /// @note Should normally be followed by a call to stop() - inline void start(const std::string& msg) - { - std::cerr << msg << " ... "; - this->start(); - } - - /// @brief Stops previous timer, print message and re-start timer. - /// @note Should normally be followed by a call to stop() - inline void restart(const std::string& msg) - { - this->stop(); - this->start(msg); - } - - /// Return Time diference in milliseconds since construction or start was called. - inline double delta() const - { - tbb::tick_count::interval_t dt = tbb::tick_count::now() - mT0; - return 1000.0*dt.seconds(); - } - - /// @brief Prints time in milliseconds since construction or start was called. - inline void stop() const - { - const double t = this->delta(); - std::ostringstream ostr; - ostr << "completed in " << std::setprecision(3) << t << " ms\n"; - std::cerr << ostr.str(); - } - -private: - - tbb::tick_count mT0; -};// CpuTimer - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - - -#endif // OPENVDB_UTIL_CPUTIMER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/Formats.cc b/openvdb_3_0_0_library/util/Formats.cc deleted file mode 100755 index b617120..0000000 --- a/openvdb_3_0_0_library/util/Formats.cc +++ /dev/null @@ -1,121 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Formats.h" - -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -int -printBytes(std::ostream& os, uint64_t bytes, - const std::string& head, const std::string& tail, - bool exact, int width, int precision) -{ - const uint64_t one = 1; - int group = 0; - - // Write to a string stream so that I/O manipulators like - // std::setprecision() don't alter the output stream. - std::ostringstream ostr; - ostr << head; - ostr << std::setprecision(precision) << std::setiosflags(std::ios::fixed); - if (bytes >> 40) { - ostr << std::setw(width) << (double(bytes) / double(one << 40)) << " TB"; - group = 4; - } else if (bytes >> 30) { - ostr << std::setw(width) << (double(bytes) / double(one << 30)) << " GB"; - group = 3; - } else if (bytes >> 20) { - ostr << std::setw(width) << (double(bytes) / double(one << 20)) << " MB"; - group = 2; - } else if (bytes >> 10) { - ostr << std::setw(width) << (double(bytes) / double(one << 10)) << " KB"; - group = 1; - } else { - ostr << std::setw(width) << bytes << " Bytes"; - } - if (exact && group) ostr << " (" << bytes << " Bytes)"; - ostr << tail; - - os << ostr.str(); - - return group; -} - - -int -printNumber(std::ostream& os, uint64_t number, - const std::string& head, const std::string& tail, - bool exact, int width, int precision) -{ - int group = 0; - - // Write to a string stream so that I/O manipulators like - // std::setprecision() don't alter the output stream. - std::ostringstream ostr; - ostr << head; - ostr << std::setprecision(precision) << std::setiosflags(std::ios::fixed); - if (number / UINT64_C(1000000000000)) { - ostr << std::setw(width) << (double(number) / 1000000000000.0) << " trillion"; - group = 4; - } else if (number / UINT64_C(1000000000)) { - ostr << std::setw(width) << (double(number) / 1000000000.0) << " billion"; - group = 3; - } else if (number / UINT64_C(1000000)) { - ostr << std::setw(width) << (double(number) / 1000000.0) << " million"; - group = 2; - } else if (number / UINT64_C(1000)) { - ostr << std::setw(width) << (double(number) / 1000.0) << " thousand"; - group = 1; - } else { - ostr << std::setw(width) << number; - } - if (exact && group) ostr << " (" << number << ")"; - ostr << tail; - - os << ostr.str(); - - return group; -} - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/Formats.h b/openvdb_3_0_0_library/util/Formats.h deleted file mode 100755 index 250aed2..0000000 --- a/openvdb_3_0_0_library/util/Formats.h +++ /dev/null @@ -1,140 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file Formats.h -/// -/// @brief Utility routines to output nicely-formatted numeric values - - -#ifndef OPENVDB_UTIL_FORMATS_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_FORMATS_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -/// Output a byte count with the correct binary suffix (KB, MB, GB or TB). -/// @param os the output stream -/// @param bytes the byte count to be output -/// @param head a string to be output before the numeric text -/// @param tail a string to be output after the numeric text -/// @param exact if true, also output the unmodified count, e.g., "4.6 KB (4620 Bytes)" -/// @param width a fixed width for the numeric text -/// @param precision the number of digits after the decimal point -/// @return 0, 1, 2, 3 or 4, denoting the order of magnitude of the count. -OPENVDB_API int -printBytes(std::ostream& os, uint64_t bytes, - const std::string& head = "", - const std::string& tail = "\n", - bool exact = false, int width = 8, int precision = 3); - -/// Output a number with the correct SI suffix (thousand, million, billion or trillion) -/// @param os the output stream -/// @param number the number to be output -/// @param head a string to be output before the numeric text -/// @param tail a string to be output after the numeric text -/// @param exact if true, also output the unmodified count, e.g., "4.6 Thousand (4620)" -/// @param width a fixed width for the numeric text -/// @param precision the number of digits after the decimal point -/// @return 0, 1, 2, 3 or 4, denoting the order of magnitude of the number. -OPENVDB_API int -printNumber(std::ostream& os, uint64_t number, - const std::string& head = "", - const std::string& tail = "\n", - bool exact = true, int width = 8, int precision = 3); - - -//////////////////////////////////////// - - -/// @brief I/O manipulator that formats integer values with thousands separators -template -class FormattedInt -{ -public: - static char sep() { return ','; } - - FormattedInt(IntT n): mInt(n) {} - - std::ostream& put(std::ostream& os) const - { - // Convert the integer to a string. - std::ostringstream ostr; - ostr << mInt; - std::string s = ostr.str(); - // Prefix the string with spaces if its length is not a multiple of three. - size_t padding = (s.size() % 3) ? 3 - (s.size() % 3) : 0; - s = std::string(padding, ' ') + s; - // Construct a new string in which groups of three digits are followed - // by a separator character. - ostr.str(""); - for (size_t i = 0, N = s.size(); i < N; ) { - ostr << s[i]; - ++i; - if (i >= padding && i % 3 == 0 && i < s.size()) { - ostr << sep(); - } - } - // Remove any padding that was added and output the string. - s = ostr.str(); - os << s.substr(padding, s.size()); - return os; - } - -private: - IntT mInt; -}; - -template -std::ostream& operator<<(std::ostream& os, const FormattedInt& n) { return n.put(os); } - -/// @return an I/O manipulator that formats the given integer value for output to a stream. -template -FormattedInt formattedInt(IntT n) { return FormattedInt(n); } - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_FORMATS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/MapsUtil.h b/openvdb_3_0_0_library/util/MapsUtil.h deleted file mode 100755 index 271397b..0000000 --- a/openvdb_3_0_0_library/util/MapsUtil.h +++ /dev/null @@ -1,321 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file MapsUtil.h - -#ifndef OPENVDB_UTIL_MAPSUTIL_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_MAPSUTIL_HAS_BEEN_INCLUDED - -#include - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -// Utility methods for calculating bounding boxes - -/// @brief Calculate an axis-aligned bounding box in the given map's domain -/// (e.g., index space) from an axis-aligned bounding box in its range -/// (e.g., world space) -template -inline void -calculateBounds(const MapType& map, const BBoxd& in, BBoxd& out) -{ - const Vec3d& min = in.min(); - const Vec3d& max = in.max(); - - // the pre-image of the 8 corners of the box - Vec3d corners[8]; - corners[0] = in.min();; - corners[1] = Vec3d(min(0), min(1), min(2)); - corners[2] = Vec3d(max(0), max(1), min(2)); - corners[3] = Vec3d(min(0), max(1), min(2)); - corners[4] = Vec3d(min(0), min(1), max(2)); - corners[5] = Vec3d(max(0), min(1), max(2)); - corners[6] = max; - corners[7] = Vec3d(min(0), max(1), max(2)); - - Vec3d pre_image; - Vec3d& out_min = out.min(); - Vec3d& out_max = out.max(); - out_min = map.applyInverseMap(corners[0]); - out_max = min; - for (int i = 1; i < 8; ++i) { - pre_image = map.applyInverseMap(corners[i]); - for (int j = 0; j < 3; ++j) { - out_min(j) = std::min( out_min(j), pre_image(j)); - out_max(j) = std::max( out_max(j), pre_image(j)); - } - } -} - - -/// @brief Calculate an axis-aligned bounding box in the given map's domain -/// from a spherical bounding box in its range. -template -inline void -calculateBounds(const MapType& map, const Vec3d& center, const Real radius, BBoxd& out) -{ - // On return, out gives a bounding box in continuous index space - // that encloses the sphere. - // - // the image of a sphere under the inverse of the linearMap will be an ellipsoid. - - if (math::is_linear::value) { - // I want to find extrema for three functions f(x', y', z') = x', or = y', or = z' - // with the constraint that g = (x-xo)^2 + (y-yo)^2 + (z-zo)^2 = r^2. - // Where the point x,y,z is the image of x',y',z' - // Solve: \lambda Grad(g) = Grad(f) and g = r^2. - // Note: here (x,y,z) is the image of (x',y',z'), and the gradient - // is w.r.t the (') space. - // - // This can be solved exactly: e_a^T (x' -xo') =\pm r\sqrt(e_a^T J^(-1)J^(-T)e_a) - // where e_a is one of the three unit vectors. - djh. - - /// find the image of the center of the sphere - Vec3d center_pre_image = map.applyInverseMap(center); - - std::vector coordinate_units; - coordinate_units.push_back(Vec3d(1,0,0)); - coordinate_units.push_back(Vec3d(0,1,0)); - coordinate_units.push_back(Vec3d(0,0,1)); - - Vec3d& out_min = out.min(); - Vec3d& out_max = out.max(); - for (int direction = 0; direction < 3; ++direction) { - Vec3d temp = map.applyIJT(coordinate_units[direction]); - double offset = - radius * sqrt(temp.x()*temp.x() + temp.y()*temp.y() + temp.z()*temp.z()); - out_min(direction) = center_pre_image(direction) - offset; - out_max(direction) = center_pre_image(direction) + offset; - } - - } else { - // This is some unknown map type. In this case, we form an axis-aligned - // bounding box for the sphere in world space and find the pre-images of - // the corners in index space. From these corners we compute an axis-aligned - // bounding box in index space. - BBoxd bounding_box(center - radius*Vec3d(1,1,1), center + radius*Vec3d(1,1,1)); - calculateBounds(map, bounding_box, out); - } -} - - -namespace { // anonymous namespace for this helper function - -/// @brief Find the intersection of a line passing through the point -/// \f$ (x=0, z=-1/g)\f$ with the circle \f$ (x-xo)^2 + (z-zo)^2 = r^2 \f$ -/// at a point tangent to the circle. -/// @return 0 if the focal point (0, -1/g) is inside the circle, -/// 1 if the focal point touches the circle, or 2 when both points are found. -inline int -findTangentPoints(const double g, const double xo, const double zo, - const double r, double& xp, double& zp, double& xm, double& zm) -{ - double x2 = xo * xo; - double r2 = r * r; - double xd = g * xo; - double xd2 = xd*xd; - double zd = g * zo + 1.; - double zd2 = zd*zd; - double rd2 = r2*g*g; - - double distA = xd2 + zd2; - double distB = distA - rd2; - - if (distB > 0) { - double discriminate = sqrt(distB); - - xp = xo - xo*rd2/distA + r * zd *discriminate / distA; - xm = xo - xo*rd2/distA - r * zd *discriminate / distA; - - zp = (zo*zd2 + zd*g*(x2 - r2) - xo*xo*g - r*xd*discriminate) / distA; - zm = (zo*zd2 + zd*g*(x2 - r2) - xo*xo*g + r*xd*discriminate) / distA; - - return 2; - - } if (0 >= distB && distB >= -1e-9) { - // the circle touches the focal point (x=0, z = -1/g) - xp = 0; xm = 0; - zp = -1/g; zm = -1/g; - - return 1; - } - - return 0; -} - -} // end anonymous namespace - - -/// @brief Calculate an axis-aligned bounding box in index space -/// from a spherical bounding box in world space. -/// @note This specialization is optimized for a frustum map -template<> -inline void -calculateBounds(const math::NonlinearFrustumMap& frustum, - const Vec3d& center, const Real radius, BBoxd& out) -{ - // The frustum is a nonlinear map followed by a uniform scale, rotation, translation. - // First we invert the translation, rotation and scale to find the spherical pre-image - // of the sphere in "local" coordinates where the frustum is aligned with the near plane - // on the z=0 plane and the "camera" is located at (x=0, y=0, z=-1/g). - - // check that the internal map has no shear. - const math::AffineMap& secondMap = frustum.secondMap(); - // test if the linear part has shear or non-uniform scaling - if (!frustum.hasSimpleAffine()) { - - // In this case, we form an axis-aligned bounding box for sphere in world space - // and find the pre_images of the corners in voxel space. From these corners we - // compute an axis-algined bounding box in voxel-spae - BBoxd bounding_box(center - radius*Vec3d(1,1,1), center + radius*Vec3d(1,1,1)); - calculateBounds(frustum, bounding_box, out); - return; - } - - // for convenience - Vec3d& out_min = out.min(); - Vec3d& out_max = out.max(); - - Vec3d centerLS = secondMap.applyInverseMap(center); - Vec3d voxelSize = secondMap.voxelSize(); - - // all the voxels have the same size since we know this is a simple affine map - double radiusLS = radius / voxelSize(0); - - double gamma = frustum.getGamma(); - double xp; - double zp; - double xm; - double zm; - int soln_number; - - // the bounding box in index space for the points in the frustum - const BBoxd& bbox = frustum.getBBox(); - // initialize min and max - const double x_min = bbox.min().x(); - const double y_min = bbox.min().y(); - const double z_min = bbox.min().z(); - - const double x_max = bbox.max().x(); - const double y_max = bbox.max().y(); - const double z_max = bbox.max().z(); - - out_min.x() = x_min; - out_max.x() = x_max; - out_min.y() = y_min; - out_max.y() = y_max; - - Vec3d extreme; - Vec3d extreme2; - Vec3d pre_image; - // find the x-range - soln_number = findTangentPoints(gamma, centerLS.x(), centerLS.z(), radiusLS, xp, zp, xm, zm); - if (soln_number == 2) { - extreme.x() = xp; - extreme.y() = centerLS.y(); - extreme.z() = zp; - - // location in world space of the tangent point - extreme2 = secondMap.applyMap(extreme); - // convert back to voxel space - pre_image = frustum.applyInverseMap(extreme2); - out_max.x() = std::max(x_min, std::min(x_max, pre_image.x())); - - extreme.x() = xm; - extreme.y() = centerLS.y(); - extreme.z() = zm; - // location in world space of the tangent point - extreme2 = secondMap.applyMap(extreme); - - // convert back to voxel space - pre_image = frustum.applyInverseMap(extreme2); - out_min.x() = std::max(x_min, std::min(x_max, pre_image.x())); - - } else if (soln_number == 1) { - // the circle was tangent at the focal point - } else if (soln_number == 0) { - // the focal point was inside the circle - } - - // find the y-range - soln_number = findTangentPoints(gamma, centerLS.y(), centerLS.z(), radiusLS, xp, zp, xm, zm); - if (soln_number == 2) { - extreme.x() = centerLS.x(); - extreme.y() = xp; - extreme.z() = zp; - - // location in world space of the tangent point - extreme2 = secondMap.applyMap(extreme); - // convert back to voxel space - pre_image = frustum.applyInverseMap(extreme2); - out_max.y() = std::max(y_min, std::min(y_max, pre_image.y())); - - extreme.x() = centerLS.x(); - extreme.y() = xm; - extreme.z() = zm; - extreme2 = secondMap.applyMap(extreme); - - // convert back to voxel space - pre_image = frustum.applyInverseMap(extreme2); - out_min.y() = std::max(y_min, std::min(y_max, pre_image.y())); - - } else if (soln_number == 1) { - // the circle was tangent at the focal point - } else if (soln_number == 0) { - // the focal point was inside the circle - } - - // the near and far - // the closest point. The front of the frustum is at 0 in index space - double near_dist = std::max(centerLS.z() - radiusLS, 0.); - // the farthest point. The back of the frustum is at mDepth in index space - double far_dist = std::min(centerLS.z() + radiusLS, frustum.getDepth() ); - - Vec3d near_point(0.f, 0.f, near_dist); - Vec3d far_point(0.f, 0.f, far_dist); - - out_min.z() = std::max(z_min, frustum.applyInverseMap(secondMap.applyMap(near_point)).z()); - out_max.z() = std::min(z_max, frustum.applyInverseMap(secondMap.applyMap(far_point)).z()); - -} - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_MAPSUTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/Name.h b/openvdb_3_0_0_library/util/Name.h deleted file mode 100755 index ae62187..0000000 --- a/openvdb_3_0_0_library/util/Name.h +++ /dev/null @@ -1,72 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_UTIL_NAME_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_NAME_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -typedef std::string Name; - -inline Name -readString(std::istream& is) -{ - uint32_t size; - is.read(reinterpret_cast(&size), sizeof(uint32_t)); - std::string buffer(size, ' '); - if (size>0) is.read(&buffer[0], size); - return buffer; -} - - -inline void -writeString(std::ostream& os, const Name& name) -{ - uint32_t size = uint32_t(name.size()); - os.write(reinterpret_cast(&size), sizeof(uint32_t)); - os.write(&name[0], size); -} - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_NAME_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/NodeMasks.h b/openvdb_3_0_0_library/util/NodeMasks.h deleted file mode 100755 index f6519eb..0000000 --- a/openvdb_3_0_0_library/util/NodeMasks.h +++ /dev/null @@ -1,1297 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @author Ken Museth -/// -/// @file NodeMasks.h - -#ifndef OPENVDB_UTIL_NODEMASKS_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_NODEMASKS_HAS_BEEN_INCLUDED - -#include -#include -#include // for cout -#include -#include -//#include -//#include // for ffs - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -/// Return the number of on bits in the given 8-bit value. -inline Index32 -CountOn(Byte v) -{ - // Simple LUT: -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const Byte numBits[256] = { -# define B2(n) n, n+1, n+1, n+2 -# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2) -# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2) - B6(0), B6(1), B6(1), B6(2) - }; - return numBits[v]; - - // Sequentially clear least significant bits - //Index32 c; - //for (c = 0; v; c++) v &= v - 0x01U; - //return c; - - // This version is only fast on CPUs with fast "%" and "*" operations - //return (v * UINT64_C(0x200040008001) & UINT64_C(0x111111111111111)) % 0xF; -} -/// Return the number of off bits in the given 8-bit value. -inline Index32 CountOff(Byte v) { return CountOn(static_cast(~v)); } - -/// Return the number of on bits in the given 32-bit value. -inline Index32 -CountOn(Index32 v) -{ - v = v - ((v >> 1) & 0x55555555U); - v = (v & 0x33333333U) + ((v >> 2) & 0x33333333U); - return (((v + (v >> 4)) & 0xF0F0F0FU) * 0x1010101U) >> 24; -} - -/// Return the number of off bits in the given 32-bit value. -inline Index32 CountOff(Index32 v) { return CountOn(~v); } - -/// Return the number of on bits in the given 64-bit value. -inline Index32 -CountOn(Index64 v) -{ - v = v - ((v >> 1) & UINT64_C(0x5555555555555555)); - v = (v & UINT64_C(0x3333333333333333)) + ((v >> 2) & UINT64_C(0x3333333333333333)); - return static_cast( - (((v + (v >> 4)) & UINT64_C(0xF0F0F0F0F0F0F0F)) * UINT64_C(0x101010101010101)) >> 56); -} - -/// Return the number of off bits in the given 64-bit value. -inline Index32 CountOff(Index64 v) { return CountOn(~v); } - -/// Return the least significant on bit of the given 8-bit value. -inline Index32 -FindLowestOn(Byte v) -{ - assert(v); -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const Byte DeBruijn[8] = {0, 1, 6, 2, 7, 5, 4, 3}; - return DeBruijn[Byte((v & -v) * 0x1DU) >> 5]; -} - -/// Return the least significant on bit of the given 32-bit value. -inline Index32 -FindLowestOn(Index32 v) -{ - assert(v); - //return ffs(v); -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const Byte DeBruijn[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - return DeBruijn[Index32((v & -v) * 0x077CB531U) >> 27]; -} - -/// Return the least significant on bit of the given 64-bit value. -inline Index32 -FindLowestOn(Index64 v) -{ - assert(v); - //return ffsll(v); -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const Byte DeBruijn[64] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12, - }; - return DeBruijn[Index64((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58]; -} - -/// Return the most significant on bit of the given 32-bit value. -inline Index32 -FindHighestOn(Index32 v) -{ -#ifndef _MSC_VER // Visual C++ doesn't guarantee thread-safe initialization of local statics - static -#endif - const Byte DeBruijn[32] = { - 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 - }; - v |= v >> 1; // first round down to one less than a power of 2 - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - return DeBruijn[Index32(v * 0x07C4ACDDU) >> 27]; -} - - -//////////////////////////////////////// - - -/// Base class for the bit mask iterators -template -class BaseMaskIterator -{ -protected: - Index32 mPos;//bit position - const NodeMask* mParent;//this iterator can't change the parent_mask! -public: - BaseMaskIterator() : mPos(NodeMask::SIZE), mParent(NULL) {} - BaseMaskIterator(Index32 pos,const NodeMask *parent) : mPos(pos), mParent(parent) - { - assert( (parent==NULL && pos==0 ) || (parent!=NULL && pos<=NodeMask::SIZE) ); - } - bool operator==(const BaseMaskIterator &iter) const {return mPos == iter.mPos;} - bool operator!=(const BaseMaskIterator &iter) const {return mPos != iter.mPos;} - bool operator< (const BaseMaskIterator &iter) const {return mPos < iter.mPos;} - BaseMaskIterator& operator=(const BaseMaskIterator& iter) - { - mPos = iter.mPos; mParent = iter.mParent; return *this; - } - Index32 offset() const {return mPos;} - Index32 pos() const {return mPos;} - bool test() const - { - assert(mPos <= NodeMask::SIZE); - return (mPos != NodeMask::SIZE); - } - operator bool() const {return this->test();} -}; // class BaseMaskIterator - - -/// @note This happens to be a const-iterator! -template -class OnMaskIterator: public BaseMaskIterator -{ -private: - typedef BaseMaskIterator BaseType; - using BaseType::mPos;//bit position; - using BaseType::mParent;//this iterator can't change the parent_mask! -public: - OnMaskIterator() : BaseType() {} - OnMaskIterator(Index32 pos,const NodeMask *parent) : BaseType(pos,parent) {} - void increment() - { - assert(mParent != NULL); - mPos = mParent->findNextOn(mPos+1); - assert(mPos <= NodeMask::SIZE); - } - void increment(Index n) { while(n-- && this->next()) ; } - bool next() - { - this->increment(); - return this->test(); - } - bool operator*() const {return true;} - OnMaskIterator& operator++() - { - this->increment(); - return *this; - } -}; // class OnMaskIterator - - -template -class OffMaskIterator: public BaseMaskIterator -{ -private: - typedef BaseMaskIterator BaseType; - using BaseType::mPos;//bit position; - using BaseType::mParent;//this iterator can't change the parent_mask! -public: - OffMaskIterator() : BaseType() {} - OffMaskIterator(Index32 pos,const NodeMask *parent) : BaseType(pos,parent) {} - void increment() - { - assert(mParent != NULL); - mPos=mParent->findNextOff(mPos+1); - assert(mPos <= NodeMask::SIZE); - } - void increment(Index n) { while(n-- && this->next()) ; } - bool next() - { - this->increment(); - return this->test(); - } - bool operator*() const {return false;} - OffMaskIterator& operator++() - { - this->increment(); - return *this; - } -}; // class OffMaskIterator - - -template -class DenseMaskIterator: public BaseMaskIterator -{ -private: - typedef BaseMaskIterator BaseType; - using BaseType::mPos;//bit position; - using BaseType::mParent;//this iterator can't change the parent_mask! - -public: - DenseMaskIterator() : BaseType() {} - DenseMaskIterator(Index32 pos,const NodeMask *parent) : BaseType(pos,parent) {} - void increment() - { - assert(mParent != NULL); - mPos += 1;//careful - the increment might go beyond the end - assert(mPos<= NodeMask::SIZE); - } - void increment(Index n) { while(n-- && this->next()) ; } - bool next() - { - this->increment(); - return this->test(); - } - bool operator*() const {return mParent->isOn(mPos);} - DenseMaskIterator& operator++() - { - this->increment(); - return *this; - } -}; // class DenseMaskIterator - - -/// @brief Bit mask for the internal and leaf nodes of VDB. This -/// is a 64-bit implementation. -/// -/// @note A template specialization for Log2Dim=1 and Log2Dim=2 are -/// given below. -template -class NodeMask -{ -public: - BOOST_STATIC_ASSERT( Log2Dim>2 ); - - static const Index32 LOG2DIM = Log2Dim; - static const Index32 DIM = 1<> 6;// 2^6=64 - typedef Index64 Word; - -private: - - // The bits are represented as a linear array of Words, and the - // size of a Word is 32 or 64 bits depending on the platform. - // The BIT_MASK is defined as the number of bits in a Word - 1 - //static const Index32 BIT_MASK = sizeof(void*) == 8 ? 63 : 31; - //static const Index32 LOG2WORD = BIT_MASK == 63 ? 6 : 5; - //static const Index32 WORD_COUNT = SIZE >> LOG2WORD; - //typedef boost::mpl::if_c::type Word; - - Word mWords[WORD_COUNT];//only member data! - -public: - /// Default constructor sets all bits off - NodeMask() { this->setOff(); } - /// All bits are set to the specified state - NodeMask(bool on) { this->set(on); } - /// Copy constructor - NodeMask(const NodeMask &other) { *this = other; } - /// Destructor - ~NodeMask() {} - /// Assignment operator - NodeMask& operator=(const NodeMask& other) - { - Index32 n = WORD_COUNT; - const Word* w2 = other.mWords; - for (Word* w1 = mWords; n--; ++w1, ++w2) *w1 = *w2; - return *this; - } - - typedef OnMaskIterator OnIterator; - typedef OffMaskIterator OffIterator; - typedef DenseMaskIterator DenseIterator; - - OnIterator beginOn() const { return OnIterator(this->findFirstOn(),this); } - OnIterator endOn() const { return OnIterator(SIZE,this); } - OffIterator beginOff() const { return OffIterator(this->findFirstOff(),this); } - OffIterator endOff() const { return OffIterator(SIZE,this); } - DenseIterator beginDense() const { return DenseIterator(0,this); } - DenseIterator endDense() const { return DenseIterator(SIZE,this); } - - bool operator == (const NodeMask &other) const - { - int n = WORD_COUNT; - for (const Word *w1=mWords, *w2=other.mWords; n-- && *w1++ == *w2++;) ; - return n == -1; - } - - bool operator != (const NodeMask &other) const { return !(*this == other); } - - // - // Bitwise logical operations - // - NodeMask operator!() const { NodeMask m(*this); m.toggle(); return m; } - const NodeMask& operator&=(const NodeMask& other) - { - Index32 n = WORD_COUNT; - const Word* w2 = other.mWords; - for ( Word* w1 = mWords; n--; ++w1, ++w2) *w1 &= *w2; - return *this; - } - const NodeMask& operator|=(const NodeMask& other) - { - Index32 n = WORD_COUNT; - const Word* w2 = other.mWords; - for ( Word* w1 = mWords; n--; ++w1, ++w2) *w1 |= *w2; - return *this; - } - const NodeMask& operator^=(const NodeMask& other) - { - Index32 n = WORD_COUNT; - const Word* w2 = other.mWords; - for ( Word* w1 = mWords; n--; ++w1, ++w2) *w1 ^= *w2; - return *this; - } - NodeMask operator&(const NodeMask& other) const { NodeMask m(*this); m &= other; return m; } - NodeMask operator|(const NodeMask& other) const { NodeMask m(*this); m |= other; return m; } - NodeMask operator^(const NodeMask& other) const { NodeMask m(*this); m ^= other; return m; } - /// Return the byte size of this NodeMask - static Index32 memUsage() { return static_cast(WORD_COUNT*sizeof(Word)); } - /// Return the total number of on bits - Index32 countOn() const - { - Index32 sum = 0, n = WORD_COUNT; - for (const Word* w = mWords; n--; ++w) sum += CountOn(*w); - return sum; - } - /// Return the total number of on bits - Index32 countOff() const { return SIZE-this->countOn(); } - /// Set the nth bit on - void setOn(Index32 n) { - assert( (n >> 6) < WORD_COUNT ); - mWords[n >> 6] |= Word(1) << (n & 63); - } - /// Set the nth bit off - void setOff(Index32 n) { - assert( (n >> 6) < WORD_COUNT ); - mWords[n >> 6] &= ~(Word(1) << (n & 63)); - } - /// Set the nth bit to the specified state - void set(Index32 n, bool On) { On ? this->setOn(n) : this->setOff(n); } - /// Set all bits to the specified state - void set(bool on) - { - const Word state = on ? ~Word(0) : Word(0); - Index32 n = WORD_COUNT; - for (Word* w = mWords; n--; ++w) *w = state; - } - /// Set all bits on - void setOn() - { - Index32 n = WORD_COUNT; - for (Word* w = mWords; n--; ++w) *w = ~Word(0); - } - /// Set all bits off - void setOff() - { - Index32 n = WORD_COUNT; - for (Word* w = mWords; n--; ++w) *w = Word(0); - } - /// Toggle the state of the nth bit - void toggle(Index32 n) { - assert( (n >> 6) < WORD_COUNT ); - mWords[n >> 6] ^= Word(1) << (n & 63); - } - /// Toggle the state of all bits in the mask - void toggle() - { - Index32 n = WORD_COUNT; - for (Word* w = mWords; n--; ++w) *w = ~*w; - } - /// Set the first bit on - void setFirstOn() { this->setOn(0); } - /// Set the last bit on - void setLastOn() { this->setOn(SIZE-1); } - /// Set the first bit off - void setFirstOff() { this->setOff(0); } - /// Set the last bit off - void setLastOff() { this->setOff(SIZE-1); } - /// Return @c true if the nth bit is on - bool isOn(Index32 n) const - { - assert( (n >> 6) < WORD_COUNT ); - return 0 != (mWords[n >> 6] & (Word(1) << (n & 63))); - } - /// Return @c true if the nth bit is off - bool isOff(Index32 n) const {return !this->isOn(n); } - /// Return @c true if all the bits are on - bool isOn() const - { - int n = WORD_COUNT; - for (const Word *w = mWords; n-- && *w++ == ~Word(0);) ; - return n == -1; - } - /// Return @c true if all the bits are off - bool isOff() const - { - int n = WORD_COUNT; - for (const Word *w = mWords; n-- && *w++ == Word(0);) ; - return n == -1; - } - Index32 findFirstOn() const - { - Index32 n = 0; - const Word* w = mWords; - for (; nnth word of the bit mask, for a word of arbitrary size. - template - WordT getWord(Index n) const - { - assert(n*8*sizeof(WordT) < SIZE); - return reinterpret_cast(mWords)[n]; - } - template - WordT& getWord(Index n) - { - assert(n*8*sizeof(WordT) < SIZE); - return reinterpret_cast(mWords)[n]; - } - //@} - - void save(std::ostream& os) const - { - os.write(reinterpret_cast(mWords), this->memUsage()); - } - void load(std::istream& is) { - is.read(reinterpret_cast(mWords), this->memUsage()); - } - /// @brief simple print method for debugging - void printInfo(std::ostream& os=std::cout) const - { - os << "NodeMask: Dim=" << DIM << " Log2Dim=" << Log2Dim - << " Bit count=" << SIZE << " word count=" << WORD_COUNT << std::endl; - } - void printBits(std::ostream& os=std::cout, Index32 max_out=80u) const - { - const Index32 n=(SIZE>max_out ? max_out : SIZE); - for (Index32 i=0; i < n; ++i) { - if ( !(i & 63) ) - os << "||"; - else if ( !(i%8) ) - os << "|"; - os << this->isOn(i); - } - os << "|" << std::endl; - } - void printAll(std::ostream& os=std::cout, Index32 max_out=80u) const - { - this->printInfo(os); - this->printBits(os, max_out); - } - - Index32 findNextOn(Index32 start) const - { - Index32 n = start >> 6;//initiate - if (n >= WORD_COUNT) return SIZE; // check for out of bounds - Index32 m = start & 63; - Word b = mWords[n]; - if (b & (Word(1) << m)) return start;//simpel case: start is on - b &= ~Word(0) << m;// mask out lower bits - while(!b && ++n> 6;//initiate - if (n >= WORD_COUNT) return SIZE; // check for out of bounds - Index32 m = start & 63; - Word b = ~mWords[n]; - if (b & (Word(1) << m)) return start;//simpel case: start is on - b &= ~Word(0) << m;// mask out lower bits - while(!b && ++n -class NodeMask<1> -{ -public: - - static const Index32 LOG2DIM = 1; - static const Index32 DIM = 2; - static const Index32 SIZE = 8; - static const Index32 WORD_COUNT = 1; - typedef Byte Word; - -private: - - Byte mByte;//only member data! - -public: - /// Default constructor sets all bits off - NodeMask() : mByte(0x00U) {} - /// All bits are set to the specified state - NodeMask(bool on) : mByte(on ? 0xFFU : 0x00U) {} - /// Copy constructor - NodeMask(const NodeMask &other) : mByte(other.mByte) {} - /// Destructor - ~NodeMask() {} - /// Assignment operator - void operator = (const NodeMask &other) { mByte = other.mByte; } - - typedef OnMaskIterator OnIterator; - typedef OffMaskIterator OffIterator; - typedef DenseMaskIterator DenseIterator; - - OnIterator beginOn() const { return OnIterator(this->findFirstOn(),this); } - OnIterator endOn() const { return OnIterator(SIZE,this); } - OffIterator beginOff() const { return OffIterator(this->findFirstOff(),this); } - OffIterator endOff() const { return OffIterator(SIZE,this); } - DenseIterator beginDense() const { return DenseIterator(0,this); } - DenseIterator endDense() const { return DenseIterator(SIZE,this); } - - bool operator == (const NodeMask &other) const { return mByte == other.mByte; } - - bool operator != (const NodeMask &other) const {return mByte != other.mByte; } - - // - // Bitwise logical operations - // - NodeMask operator!() const { NodeMask m(*this); m.toggle(); return m; } - const NodeMask& operator&=(const NodeMask& other) - { - mByte &= other.mByte; - return *this; - } - const NodeMask& operator|=(const NodeMask& other) - { - mByte |= other.mByte; - return *this; - } - const NodeMask& operator^=(const NodeMask& other) - { - mByte ^= other.mByte; - return *this; - } - NodeMask operator&(const NodeMask& other) const { NodeMask m(*this); m &= other; return m; } - NodeMask operator|(const NodeMask& other) const { NodeMask m(*this); m |= other; return m; } - NodeMask operator^(const NodeMask& other) const { NodeMask m(*this); m ^= other; return m; } - /// Return the byte size of this NodeMask - static Index32 memUsage() { return 1; } - /// Return the total number of on bits - Index32 countOn() const { return CountOn(mByte); } - /// Return the total number of on bits - Index32 countOff() const { return CountOff(mByte); } - /// Set the nth bit on - void setOn(Index32 n) { - assert( n < 8 ); - mByte = mByte | static_cast(0x01U << (n & 7)); - } - /// Set the nth bit off - void setOff(Index32 n) { - assert( n < 8 ); - mByte = mByte & static_cast(~(0x01U << (n & 7))); - } - /// Set the nth bit to the specified state - void set(Index32 n, bool On) { On ? this->setOn(n) : this->setOff(n); } - /// Set all bits to the specified state - void set(bool on) { mByte = on ? 0xFFU : 0x00U; } - /// Set all bits on - void setOn() { mByte = 0xFFU; } - /// Set all bits off - void setOff() { mByte = 0x00U; } - /// Toggle the state of the nth bit - void toggle(Index32 n) { - assert( n < 8 ); - mByte = mByte ^ static_cast(0x01U << (n & 7)); - } - /// Toggle the state of all bits in the mask - void toggle() { mByte = static_cast(~mByte); } - /// Set the first bit on - void setFirstOn() { this->setOn(0); } - /// Set the last bit on - void setLastOn() { this->setOn(7); } - /// Set the first bit off - void setFirstOff() { this->setOff(0); } - /// Set the last bit off - void setLastOff() { this->setOff(7); } - /// Return true if the nth bit is on - bool isOn(Index32 n) const - { - assert( n < 8 ); - return mByte & (0x01U << (n & 7)); - } - /// Return true if the nth bit is off - bool isOff(Index32 n) const {return !this->isOn(n); } - /// Return true if all the bits are on - bool isOn() const { return mByte == 0xFFU; } - /// Return true if all the bits are off - bool isOff() const { return mByte == 0; } - Index32 findFirstOn() const { return mByte ? FindLowestOn(mByte) : 8; } - Index32 findFirstOff() const - { - const Byte b = static_cast(~mByte); - return b ? FindLowestOn(b) : 8; - } - /* - //@{ - /// Return the nth word of the bit mask, for a word of arbitrary size. - /// @note This version assumes WordT=Byte and n=0! - template - WordT getWord(Index n) const - { - BOOST_STATIC_ASSERT(sizeof(WordT) == sizeof(Byte)); - assert(n == 0); - return reinterpret_cast(mByte); - } - template - WordT& getWord(Index n) - { - BOOST_STATIC_ASSERT(sizeof(WordT) == sizeof(Byte)); - assert(n == 0); - return reinterpret_cast(mByte); - } - //@} - */ - void save(std::ostream& os) const - { - os.write(reinterpret_cast(&mByte), 1); - } - void load(std::istream& is) { is.read(reinterpret_cast(&mByte), 1); } - /// @brief simple print method for debugging - void printInfo(std::ostream& os=std::cout) const - { - os << "NodeMask: Dim=2, Log2Dim=1, Bit count=8, Word count=1"<isOn(i); - os << "||" << std::endl; - } - void printAll(std::ostream& os=std::cout) const - { - this->printInfo(os); - this->printBits(os); - } - - Index32 findNextOn(Index32 start) const - { - if (start>=8) return 8; - const Byte b = static_cast(mByte & (0xFFU << start)); - return b ? FindLowestOn(b) : 8; - } - - Index32 findNextOff(Index32 start) const - { - if (start>=8) return 8; - const Byte b = static_cast(~mByte & (0xFFU << start)); - return b ? FindLowestOn(b) : 8; - } - -};// NodeMask<1> - - -/// @brief Template specialization of NodeMask for Log2Dim=2, i.e. 4^3 nodes -template<> -class NodeMask<2> -{ -public: - - static const Index32 LOG2DIM = 2; - static const Index32 DIM = 4; - static const Index32 SIZE = 64; - static const Index32 WORD_COUNT = 1; - typedef Index64 Word; - -private: - - Word mWord;//only member data! - -public: - /// Default constructor sets all bits off - NodeMask() : mWord(UINT64_C(0x00)) {} - /// All bits are set to the specified state - NodeMask(bool on) : mWord(on ? UINT64_C(0xFFFFFFFFFFFFFFFF) : UINT64_C(0x00)) {} - /// Copy constructor - NodeMask(const NodeMask &other) : mWord(other.mWord) {} - /// Destructor - ~NodeMask() {} - /// Assignment operator - void operator = (const NodeMask &other) { mWord = other.mWord; } - - typedef OnMaskIterator OnIterator; - typedef OffMaskIterator OffIterator; - typedef DenseMaskIterator DenseIterator; - - OnIterator beginOn() const { return OnIterator(this->findFirstOn(),this); } - OnIterator endOn() const { return OnIterator(SIZE,this); } - OffIterator beginOff() const { return OffIterator(this->findFirstOff(),this); } - OffIterator endOff() const { return OffIterator(SIZE,this); } - DenseIterator beginDense() const { return DenseIterator(0,this); } - DenseIterator endDense() const { return DenseIterator(SIZE,this); } - - bool operator == (const NodeMask &other) const { return mWord == other.mWord; } - - bool operator != (const NodeMask &other) const {return mWord != other.mWord; } - - // - // Bitwise logical operations - // - NodeMask operator!() const { NodeMask m(*this); m.toggle(); return m; } - const NodeMask& operator&=(const NodeMask& other) - { - mWord &= other.mWord; - return *this; - } - const NodeMask& operator|=(const NodeMask& other) - { - mWord |= other.mWord; - return *this; - } - const NodeMask& operator^=(const NodeMask& other) - { - mWord ^= other.mWord; - return *this; - } - NodeMask operator&(const NodeMask& other) const { NodeMask m(*this); m &= other; return m; } - NodeMask operator|(const NodeMask& other) const { NodeMask m(*this); m |= other; return m; } - NodeMask operator^(const NodeMask& other) const { NodeMask m(*this); m ^= other; return m; } - /// Return the byte size of this NodeMask - static Index32 memUsage() { return 8; } - /// Return the total number of on bits - Index32 countOn() const { return CountOn(mWord); } - /// Return the total number of on bits - Index32 countOff() const { return CountOff(mWord); } - /// Set the nth bit on - void setOn(Index32 n) { - assert( n < 64 ); - mWord |= UINT64_C(0x01) << (n & 63); - } - /// Set the nth bit off - void setOff(Index32 n) { - assert( n < 64 ); - mWord &= ~(UINT64_C(0x01) << (n & 63)); - } - /// Set the nth bit to the specified state - void set(Index32 n, bool On) { On ? this->setOn(n) : this->setOff(n); } - /// Set all bits to the specified state - void set(bool on) { mWord = on ? UINT64_C(0xFFFFFFFFFFFFFFFF) : UINT64_C(0x00); } - /// Set all bits on - void setOn() { mWord = UINT64_C(0xFFFFFFFFFFFFFFFF); } - /// Set all bits off - void setOff() { mWord = UINT64_C(0x00); } - /// Toggle the state of the nth bit - void toggle(Index32 n) { - assert( n < 64 ); - mWord ^= UINT64_C(0x01) << (n & 63); - } - /// Toggle the state of all bits in the mask - void toggle() { mWord = ~mWord; } - /// Set the first bit on - void setFirstOn() { this->setOn(0); } - /// Set the last bit on - void setLastOn() { this->setOn(63); } - /// Set the first bit off - void setFirstOff() { this->setOff(0); } - /// Set the last bit off - void setLastOff() { this->setOff(63); } - /// Return true if the nth bit is on - bool isOn(Index32 n) const - { - assert( n < 64 ); - return 0 != (mWord & (UINT64_C(0x01) << (n & 63))); - } - /// Return true if the nth bit is off - bool isOff(Index32 n) const {return !this->isOn(n); } - /// Return true if all the bits are on - bool isOn() const { return mWord == UINT64_C(0xFFFFFFFFFFFFFFFF); } - /// Return true if all the bits are off - bool isOff() const { return mWord == 0; } - Index32 findFirstOn() const { return mWord ? FindLowestOn(mWord) : 64; } - Index32 findFirstOff() const - { - const Word w = ~mWord; - return w ? FindLowestOn(w) : 64; - } - //@{ - /// Return the nth word of the bit mask, for a word of arbitrary size. - template - WordT getWord(Index n) const - { - assert(n*8*sizeof(WordT) < SIZE); - return reinterpret_cast(&mWord)[n]; - } - template - WordT& getWord(Index n) - { - assert(n*8*sizeof(WordT) < SIZE); - return reinterpret_cast(mWord)[n]; - } - //@} - void save(std::ostream& os) const - { - os.write(reinterpret_cast(&mWord), 8); - } - void load(std::istream& is) { is.read(reinterpret_cast(&mWord), 8); } - /// @brief simple print method for debugging - void printInfo(std::ostream& os=std::cout) const - { - os << "NodeMask: Dim=4, Log2Dim=2, Bit count=64, Word count=1"<isOn(i); - } - os << "||" << std::endl; - } - void printAll(std::ostream& os=std::cout) const - { - this->printInfo(os); - this->printBits(os); - } - - Index32 findNextOn(Index32 start) const - { - if (start>=64) return 64; - const Word w = mWord & (UINT64_C(0xFFFFFFFFFFFFFFFF) << start); - return w ? FindLowestOn(w) : 64; - } - - Index32 findNextOff(Index32 start) const - { - if (start>=64) return 64; - const Word w = ~mWord & (UINT64_C(0xFFFFFFFFFFFFFFFF) << start); - return w ? FindLowestOn(w) : 64; - } - -};// NodeMask<2> - - -// Unlike NodeMask above this RootNodeMask has a run-time defined size. -// It is only included for backward compatibility and will likely be -// deprecated in the future! -// This class is 32-bit specefic, hence the use if Index32 vs Index! -class RootNodeMask -{ -protected: - Index32 mBitSize, mIntSize; - Index32 *mBits; - -public: - RootNodeMask(): mBitSize(0), mIntSize(0), mBits(NULL) {} - RootNodeMask(Index32 bit_size): - mBitSize(bit_size), mIntSize(((bit_size-1)>>5)+1), mBits(new Index32[mIntSize]) - { - for (Index32 i=0; i>5)+1; - delete [] mBits; - mBits = new Index32[mIntSize]; - for (Index32 i=0; igetBitSize()), mParent(parent) { - assert( pos<=mBitSize ); - } - bool operator==(const BaseIterator &iter) const {return mPos == iter.mPos;} - bool operator!=(const BaseIterator &iter) const {return mPos != iter.mPos;} - bool operator< (const BaseIterator &iter) const {return mPos < iter.mPos;} - BaseIterator& operator=(const BaseIterator& iter) { - mPos = iter.mPos; - mBitSize = iter.mBitSize; - mParent = iter.mParent; - return *this; - } - - Index32 offset() const {return mPos;} - - Index32 pos() const {return mPos;} - - bool test() const { - assert(mPos <= mBitSize); - return (mPos != mBitSize); - } - - operator bool() const {return this->test();} - }; // class BaseIterator - - /// @note This happens to be a const-iterator! - class OnIterator: public BaseIterator - { - protected: - using BaseIterator::mPos;//bit position; - using BaseIterator::mBitSize;//bit size; - using BaseIterator::mParent;//this iterator can't change the parent_mask! - public: - OnIterator() : BaseIterator() {} - OnIterator(Index32 pos,const RootNodeMask *parent) : BaseIterator(pos,parent) {} - void increment() { - assert(mParent!=NULL); - mPos=mParent->findNextOn(mPos+1); - assert(mPos <= mBitSize); - } - void increment(Index n) { - for (Index i=0; inext(); ++i) {} - } - bool next() { - this->increment(); - return this->test(); - } - bool operator*() const {return true;} - OnIterator& operator++() { - this->increment(); - return *this; - } - }; // class OnIterator - - class OffIterator: public BaseIterator - { - protected: - using BaseIterator::mPos;//bit position; - using BaseIterator::mBitSize;//bit size; - using BaseIterator::mParent;//this iterator can't change the parent_mask! - public: - OffIterator() : BaseIterator() {} - OffIterator(Index32 pos,const RootNodeMask *parent) : BaseIterator(pos,parent) {} - void increment() { - assert(mParent!=NULL); - mPos=mParent->findNextOff(mPos+1); - assert(mPos <= mBitSize); - } - void increment(Index n) { - for (Index i=0; inext(); ++i) {} - } - bool next() { - this->increment(); - return this->test(); - } - bool operator*() const {return true;} - OffIterator& operator++() { - this->increment(); - return *this; - } - }; // class OffIterator - - class DenseIterator: public BaseIterator - { - protected: - using BaseIterator::mPos;//bit position; - using BaseIterator::mBitSize;//bit size; - using BaseIterator::mParent;//this iterator can't change the parent_mask! - public: - DenseIterator() : BaseIterator() {} - DenseIterator(Index32 pos,const RootNodeMask *parent) : BaseIterator(pos,parent) {} - void increment() { - assert(mParent!=NULL); - mPos += 1;//carefull - the increament might go beyond the end - assert(mPos<= mBitSize); - } - void increment(Index n) { - for (Index i=0; inext(); ++i) {} - } - bool next() { - this->increment(); - return this->test(); - } - bool operator*() const {return mParent->isOn(mPos);} - DenseIterator& operator++() { - this->increment(); - return *this; - } - }; // class DenseIterator - - OnIterator beginOn() const { return OnIterator(this->findFirstOn(),this); } - OnIterator endOn() const { return OnIterator(mBitSize,this); } - OffIterator beginOff() const { return OffIterator(this->findFirstOff(),this); } - OffIterator endOff() const { return OffIterator(mBitSize,this); } - DenseIterator beginDense() const { return DenseIterator(0,this); } - DenseIterator endDense() const { return DenseIterator(mBitSize,this); } - - bool operator == (const RootNodeMask &B) const { - if (mBitSize != B.mBitSize) return false; - for (Index32 i=0; i(mIntSize*sizeof(Index32) + sizeof(*this)); - } - - Index32 countOn() const { - assert(mBits); - Index32 n=0; - for (Index32 i=0; i< mIntSize; ++i) n += CountOn(mBits[i]); - return n; - } - - Index32 countOff() const { return mBitSize-this->countOn(); } - - void setOn(Index32 i) { - assert(mBits); - assert( (i>>5) < mIntSize); - mBits[i>>5] |= 1<<(i&31); - } - - void setOff(Index32 i) { - assert(mBits); - assert( (i>>5) < mIntSize); - mBits[i>>5] &= ~(1<<(i&31)); - } - - void set(Index32 i, bool On) { On ? this->setOn(i) : this->setOff(i); } - - void setOn() { - assert(mBits); - for (Index32 i=0; i>5) < mIntSize); - mBits[i>>5] ^= 1<<(i&31); - } - void toggle() { - assert(mBits); - for (Index32 i=0; isetOn(0); } - void setLastOn() { this->setOn(mBitSize-1); } - void setFirstOff() { this->setOff(0); } - void setLastOff() { this->setOff(mBitSize-1); } - bool isOn(Index32 i) const { - assert(mBits); - assert( (i>>5) < mIntSize); - return ( mBits[i >> 5] & (1<<(i&31)) ); - } - bool isOff(Index32 i) const { - assert(mBits); - assert( (i>>5) < mIntSize); - return ( ~mBits[i >> 5] & (1<<(i&31)) ); - } - - bool isOn() const { - if (!mBits) return false;//undefined is off - for (Index32 i=0; iisOn(i); - } - os << "|" << std::endl; - } - - void printAll(std::ostream& os=std::cout, Index32 max_out=80u) const { - this->printInfo(os); - this->printBits(os,max_out); - } - - Index32 findNextOn(Index32 start) const { - assert(mBits); - Index32 n = start >> 5, m = start & 31;//initiate - if (n>=mIntSize) return mBitSize; // check for out of bounds - Index32 b = mBits[n]; - if (b & (1<> 5, m = start & 31;//initiate - if (n>=mIntSize) return mBitSize; // check for out of bounds - Index32 b = ~mBits[n]; - if (b & (1<(sizeof(Index32*)+(2+mIntSize)*sizeof(Index32));//in bytes - } -}; // class RootNodeMask - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_NODEMASKS_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/NullInterrupter.h b/openvdb_3_0_0_library/util/NullInterrupter.h deleted file mode 100755 index b81517c..0000000 --- a/openvdb_3_0_0_library/util/NullInterrupter.h +++ /dev/null @@ -1,90 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file NullInterrupter.h - -#ifndef OPENVDB_UTIL_NULL_INTERRUPTER_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_NULL_INTERRUPTER_HAS_BEEN_INCLUDED - -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -/// @brief Dummy NOOP interrupter class defining interface -/// -/// This shows the required interface for the @c InterrupterType template argument -/// using by several threaded applications (e.g. tools/PointAdvect.h). The host -/// application calls start() at the beginning of an interruptible operation, end() -/// at the end of the operation, and wasInterrupted() periodically during the operation. -/// If any call to wasInterrupted() returns @c true, the operation will be aborted. -/// @note This Dummy interrupter will NEVER interrupt since wasInterrupted() always -/// returns false! -struct NullInterrupter -{ - /// Default constructor - NullInterrupter () {} - /// Signal the start of an interruptible operation. - /// @param name an optional descriptive name for the operation - void start(const char* name = NULL) { (void)name; } - /// Signal the end of an interruptible operation. - void end() {} - /// Check if an interruptible operation should be aborted. - /// @param percent an optional (when >= 0) percentage indicating - /// the fraction of the operation that has been completed - /// @note this method is assumed to be thread-safe. The current - /// implementation is clearly a NOOP and should compile out during - /// optimization! - inline bool wasInterrupted(int percent = -1) { (void)percent; return false; } -}; - -/// This method allows NullInterrupter::wasInterrupted to be compiled -/// out when client code only has a pointer (vs reference) to the interrupter. -/// -/// @note This is a free-standing function since C++ doesn't allow for -/// partial template specialization (in client code of the interrupter). -template -inline bool wasInterrupted(T* i, int percent = -1) { return i && i->wasInterrupted(percent); } - -/// Specialization for NullInterrupter -template<> -inline bool wasInterrupted(util::NullInterrupter*, int) { return false; } - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_NULL_INTERRUPTER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/Util.cc b/openvdb_3_0_0_library/util/Util.cc deleted file mode 100755 index 11d16f9..0000000 --- a/openvdb_3_0_0_library/util/Util.cc +++ /dev/null @@ -1,77 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Util.h" -#include - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -const Index32 INVALID_IDX = std::numeric_limits::max(); - -const Coord COORD_OFFSETS[26] = -{ - Coord( 1, 0, 0), /// Voxel-face adjacent neghbours - Coord(-1, 0, 0), /// 0 to 5 - Coord( 0, 1, 0), - Coord( 0, -1, 0), - Coord( 0, 0, 1), - Coord( 0, 0, -1), - Coord( 1, 0, -1), /// Voxel-edge adjacent neghbours - Coord(-1, 0, -1), /// 6 to 17 - Coord( 1, 0, 1), - Coord(-1, 0, 1), - Coord( 1, 1, 0), - Coord(-1, 1, 0), - Coord( 1, -1, 0), - Coord(-1, -1, 0), - Coord( 0, -1, 1), - Coord( 0, -1, -1), - Coord( 0, 1, 1), - Coord( 0, 1, -1), - Coord(-1, -1, -1), /// Voxel-corner adjacent neghbours - Coord(-1, -1, 1), /// 18 to 25 - Coord( 1, -1, 1), - Coord( 1, -1, -1), - Coord(-1, 1, -1), - Coord(-1, 1, 1), - Coord( 1, 1, 1), - Coord( 1, 1, -1) -}; - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/Util.h b/openvdb_3_0_0_library/util/Util.h deleted file mode 100755 index 689701f..0000000 --- a/openvdb_3_0_0_library/util/Util.h +++ /dev/null @@ -1,166 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_UTIL_UTIL_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_UTIL_HAS_BEEN_INCLUDED - -#include -#include -#include -#include // for tree::pruneInactive - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { -namespace util { - -OPENVDB_API extern const Index32 INVALID_IDX; - -/// @brief coordinate offset table for neighboring voxels -OPENVDB_API extern const Coord COORD_OFFSETS[26]; - - -//////////////////////////////////////// - - -/// Return @a voxelCoord rounded to the closest integer coordinates. -inline Coord -nearestCoord(const Vec3d& voxelCoord) -{ - Coord ijk; - ijk[0] = int(std::floor(voxelCoord[0])); - ijk[1] = int(std::floor(voxelCoord[1])); - ijk[2] = int(std::floor(voxelCoord[2])); - return ijk; -} - - -//////////////////////////////////////// - - -/// @brief Functor for use with tools::foreach() to compute the boolean intersection -/// between the value masks of corresponding leaf nodes in two trees -template -class LeafTopologyIntOp -{ -public: - LeafTopologyIntOp(const TreeType2& tree): mOtherTree(&tree) {} - - inline void operator()(const typename TreeType1::LeafIter& lIter) const - { - const Coord xyz = lIter->origin(); - const typename TreeType2::LeafNodeType* leaf = mOtherTree->probeConstLeaf(xyz); - if (leaf) {//leaf node - lIter->topologyIntersection(*leaf, zeroVal()); - } else if (!mOtherTree->isValueOn(xyz)) {//inactive tile - lIter->setValuesOff(); - } - } - -private: - const TreeType2* mOtherTree; -}; - - -/// @brief Functor for use with tools::foreach() to compute the boolean difference -/// between the value masks of corresponding leaf nodes in two trees -template -class LeafTopologyDiffOp -{ -public: - LeafTopologyDiffOp(const TreeType2& tree): mOtherTree(&tree) {} - - inline void operator()(const typename TreeType1::LeafIter& lIter) const - { - const Coord xyz = lIter->origin(); - const typename TreeType2::LeafNodeType* leaf = mOtherTree->probeConstLeaf(xyz); - if (leaf) {//leaf node - lIter->topologyDifference(*leaf, zeroVal()); - } else if (mOtherTree->isValueOn(xyz)) {//active tile - lIter->setValuesOff(); - } - } - -private: - const TreeType2* mOtherTree; -}; - - -//////////////////////////////////////// - - -/// @brief Perform a boolean intersection between two leaf nodes' topology masks. -/// @return a pointer to a new, boolean-valued tree containing the overlapping voxels. -template -inline typename TreeType1::template ValueConverter::Type::Ptr -leafTopologyIntersection(const TreeType1& lhs, const TreeType2& rhs, bool threaded = true) -{ - typedef typename TreeType1::template ValueConverter::Type BoolTreeType; - - typename BoolTreeType::Ptr topologyTree(new BoolTreeType( - lhs, /*inactiveValue=*/false, /*activeValue=*/true, TopologyCopy())); - - tools::foreach(topologyTree->beginLeaf(), - LeafTopologyIntOp(rhs), threaded); - - tools::pruneInactive(*topologyTree, threaded); - return topologyTree; -} - - -/// @brief Perform a boolean difference between two leaf nodes' topology masks. -/// @return a pointer to a new, boolean-valued tree containing the non-overlapping -/// voxels from the lhs. -template -inline typename TreeType1::template ValueConverter::Type::Ptr -leafTopologyDifference(const TreeType1& lhs, const TreeType2& rhs, bool threaded = true) -{ - typedef typename TreeType1::template ValueConverter::Type BoolTreeType; - - typename BoolTreeType::Ptr topologyTree(new BoolTreeType( - lhs, /*inactiveValue=*/false, /*activeValue=*/true, TopologyCopy())); - - tools::foreach(topologyTree->beginLeaf(), - LeafTopologyDiffOp(rhs), threaded); - - tools::pruneInactive(*topologyTree, threaded); - return topologyTree; -} - -} // namespace util -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_UTIL_UTIL_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/util/logging.h b/openvdb_3_0_0_library/util/logging.h deleted file mode 100755 index b79dc2b..0000000 --- a/openvdb_3_0_0_library/util/logging.h +++ /dev/null @@ -1,83 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED -#define OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED - -#ifndef OPENVDB_USE_LOG4CPLUS - -/// Log an info message of the form 'someVar << "some text" << ...'. -#define OPENVDB_LOG_INFO(message) -/// Log a warning message of the form 'someVar << "some text" << ...'. -#define OPENVDB_LOG_WARN(message) do { std::cerr << message << std::endl; } while (0); -/// Log an error message of the form 'someVar << "some text" << ...'. -#define OPENVDB_LOG_ERROR(message) do { std::cerr << message << std::endl; } while (0); -/// Log a fatal error message of the form 'someVar << "some text" << ...'. -#define OPENVDB_LOG_FATAL(message) do { std::cerr << message << std::endl; } while (0); -/// In debug builds only, log a debugging message of the form 'someVar << "text" << ...'. -#define OPENVDB_LOG_DEBUG(message) -/// @brief Log a debugging message in both debug and optimized builds. -/// @warning Don't use this in performance-critical code. -#define OPENVDB_LOG_DEBUG_RUNTIME(message) - -#else // ifdef OPENVDB_USE_LOG4CPLUS - -#include -#include -#include - -#define OPENVDB_LOG(level, message) \ - do { \ - log4cplus::Logger _log = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main")); \ - if (_log.isEnabledFor(log4cplus::level##_LOG_LEVEL)) { \ - std::ostringstream _buf; \ - _buf << message; \ - _log.forcedLog(log4cplus::level##_LOG_LEVEL, _buf.str(), __FILE__, __LINE__); \ - } \ - } while (0); - -#define OPENVDB_LOG_INFO(message) OPENVDB_LOG(INFO, message) -#define OPENVDB_LOG_WARN(message) OPENVDB_LOG(WARN, message) -#define OPENVDB_LOG_ERROR(message) OPENVDB_LOG(ERROR, message) -#define OPENVDB_LOG_FATAL(message) OPENVDB_LOG(FATAL, message) -#ifdef DEBUG -#define OPENVDB_LOG_DEBUG(message) OPENVDB_LOG(DEBUG, message) -#else -#define OPENVDB_LOG_DEBUG(message) -#endif -#define OPENVDB_LOG_DEBUG_RUNTIME(message) OPENVDB_LOG(DEBUG, message) - -#endif // OPENVDB_USE_LOG4CPLUS - -#endif // OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/version.h b/openvdb_3_0_0_library/version.h deleted file mode 100755 index c815ba2..0000000 --- a/openvdb_3_0_0_library/version.h +++ /dev/null @@ -1,133 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_VERSION_HAS_BEEN_INCLUDED -#define OPENVDB_VERSION_HAS_BEEN_INCLUDED - -#include "Platform.h" - - -/// The version namespace name for this library version -/// -/// Fully-namespace-qualified symbols are named as follows: -/// openvdb::vX_Y_Z::Vec3i, openvdb::vX_Y_Z::io::File, openvdb::vX_Y_Z::tree::Tree, etc., -/// where X, Y and Z are OPENVDB_LIBRARY_MAJOR_VERSION, OPENVDB_LIBRARY_MINOR_VERSION -/// and OPENVDB_LIBRARY_PATCH_VERSION, respectively (defined below). -#define OPENVDB_VERSION_NAME v3_0_0 - -// Library major, minor and patch version numbers -#define OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER 3 -#define OPENVDB_LIBRARY_MINOR_VERSION_NUMBER 0 -#define OPENVDB_LIBRARY_PATCH_VERSION_NUMBER 0 - -/// @brief Library version number string of the form ".." -/// @details This is a macro rather than a static constant because we typically -/// want the compile-time version number, not the runtime version number -/// (although the two are usually the same). -#define OPENVDB_LIBRARY_VERSION_STRING "3.0.0" - -/// Library version number as a packed integer ("%02x%02x%04x", major, minor, patch) -#define OPENVDB_LIBRARY_VERSION_NUMBER \ - ((OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER << 24) | \ - ((OPENVDB_LIBRARY_MINOR_VERSION_NUMBER & 0xFF) << 16) | \ - (OPENVDB_LIBRARY_PATCH_VERSION_NUMBER & 0xFFFF)) - -/// If OPENVDB_REQUIRE_VERSION_NAME is undefined, symbols from the version -/// namespace are promoted to the top-level namespace (e.g., openvdb::v1_0_0::io::File -/// can be referred to simply as openvdb::io::File). Otherwise, symbols must be fully -/// namespace-qualified. -#ifdef OPENVDB_REQUIRE_VERSION_NAME -#define OPENVDB_USE_VERSION_NAMESPACE -#else -/// @note The empty namespace clause below ensures that -/// OPENVDB_VERSION_NAME is recognized as a namespace name. -#define OPENVDB_USE_VERSION_NAMESPACE \ - namespace OPENVDB_VERSION_NAME {} \ - using namespace OPENVDB_VERSION_NAME; -#endif - - -namespace openvdb { -OPENVDB_USE_VERSION_NAMESPACE -namespace OPENVDB_VERSION_NAME { - -/// @brief The magic number is stored in the first four bytes of every VDB file. -/// @details This can be used to quickly test whether we have a valid file or not. -const int32_t OPENVDB_MAGIC = 0x56444220; - -// Library major, minor and patch version numbers -const uint32_t - OPENVDB_LIBRARY_MAJOR_VERSION = OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER, - OPENVDB_LIBRARY_MINOR_VERSION = OPENVDB_LIBRARY_MINOR_VERSION_NUMBER, - OPENVDB_LIBRARY_PATCH_VERSION = OPENVDB_LIBRARY_PATCH_VERSION_NUMBER; -/// Library version number as a packed integer ("%02x%02x%04x", major, minor, patch) -const uint32_t OPENVDB_LIBRARY_VERSION = OPENVDB_LIBRARY_VERSION_NUMBER; - -/// @brief The current version number of the VDB file format -/// @details This can be used to enable various backwards compatability switches -/// or to reject files that cannot be read. -const uint32_t OPENVDB_FILE_VERSION = 223; - -/// Notable file format version numbers -enum { - OPENVDB_FILE_VERSION_ROOTNODE_MAP = 213, - OPENVDB_FILE_VERSION_INTERNALNODE_COMPRESSION = 214, - OPENVDB_FILE_VERSION_SIMPLIFIED_GRID_TYPENAME = 215, - OPENVDB_FILE_VERSION_GRID_INSTANCING = 216, - OPENVDB_FILE_VERSION_BOOL_LEAF_OPTIMIZATION = 217, - OPENVDB_FILE_VERSION_BOOST_UUID = 218, - OPENVDB_FILE_VERSION_NO_GRIDMAP = 219, - OPENVDB_FILE_VERSION_NEW_TRANSFORM = 219, - OPENVDB_FILE_VERSION_SELECTIVE_COMPRESSION = 220, - OPENVDB_FILE_VERSION_FLOAT_FRUSTUM_BBOX = 221, - OPENVDB_FILE_VERSION_NODE_MASK_COMPRESSION = 222, - OPENVDB_FILE_VERSION_BLOSC_COMPRESSION = 223, - OPENVDB_FILE_VERSION_POINT_INDEX_GRID = 223 -}; - - -/// Return a library version number string of the form "..". -inline const char* getLibraryVersionString() { return OPENVDB_LIBRARY_VERSION_STRING; } - - -struct VersionId { - uint32_t first, second; - VersionId(): first(0), second(0) {} - VersionId(uint32_t major, uint32_t minor): first(major), second(minor) {} -}; - -} // namespace OPENVDB_VERSION_NAME -} // namespace openvdb - -#endif // OPENVDB_VERSION_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Camera.cc b/openvdb_3_0_0_library/viewer/Camera.cc deleted file mode 100755 index 4fcdf91..0000000 --- a/openvdb_3_0_0_library/viewer/Camera.cc +++ /dev/null @@ -1,281 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Camera.h" - -#include - -#ifdef OPENVDB_USE_GLFW_3 -#define GLFW_INCLUDE_GLU -#include -#else // if !defined(OPENVDB_USE_GLFW_3) -#if defined(__APPLE__) || defined(MACOSX) -#include -#include -#else -#include -#include -#endif -#include -#endif // !defined(OPENVDB_USE_GLFW_3) - - -namespace openvdb_viewer { - -const double Camera::sDeg2rad = M_PI / 180.0; - - -Camera::Camera() - : mFov(65.0) - , mNearPlane(0.1) - , mFarPlane(10000.0) - , mTarget(openvdb::Vec3d(0.0)) - , mLookAt(mTarget) - , mUp(openvdb::Vec3d(0.0, 1.0, 0.0)) - , mForward(openvdb::Vec3d(0.0, 0.0, 1.0)) - , mRight(openvdb::Vec3d(1.0, 0.0, 0.0)) - , mEye(openvdb::Vec3d(0.0, 0.0, -1.0)) - , mTumblingSpeed(0.5) - , mZoomSpeed(0.2) - , mStrafeSpeed(0.05) - , mHead(30.0) - , mPitch(45.0) - , mTargetDistance(25.0) - , mDistance(mTargetDistance) - , mMouseDown(false) - , mStartTumbling(false) - , mZoomMode(false) - , mChanged(true) - , mNeedsDisplay(true) - , mMouseXPos(0.0) - , mMouseYPos(0.0) - , mWheelPos(0) -#if GLFW_VERSION_MAJOR >= 3 - , mWindow(NULL) -#endif -{ -} - - -void -Camera::lookAt(const openvdb::Vec3d& p, double dist) -{ - mLookAt = p; - mDistance = dist; - mNeedsDisplay = true; -} - - -void -Camera::lookAtTarget() -{ - mLookAt = mTarget; - mDistance = mTargetDistance; - mNeedsDisplay = true; -} - - -void -Camera::setSpeed(double zoomSpeed, double strafeSpeed, double tumblingSpeed) -{ - mZoomSpeed = std::max(0.0001, mDistance * zoomSpeed); - mStrafeSpeed = std::max(0.0001, mDistance * strafeSpeed); - mTumblingSpeed = std::max(0.2, mDistance * tumblingSpeed); - mTumblingSpeed = std::min(1.0, mDistance * tumblingSpeed); -} - - -void -Camera::setTarget(const openvdb::Vec3d& p, double dist) -{ - mTarget = p; - mTargetDistance = dist; -} - - -void -Camera::aim() -{ -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow == NULL) return; -#endif - - // Get the window size - int width, height; -#if GLFW_VERSION_MAJOR >= 3 - glfwGetWindowSize(mWindow, &width, &height); -#else - glfwGetWindowSize(&width, &height); -#endif - - // Make sure that height is non-zero to avoid division by zero - height = std::max(1, height); - - glViewport(0, 0, width, height); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Set up the projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Window aspect (assumes square pixels) - double aspectRatio = (double)width / (double)height; - - // Set perspective view (fov is in degrees in the y direction.) - gluPerspective(mFov, aspectRatio, mNearPlane, mFarPlane); - - if (mChanged) { - - mChanged = false; - - mEye[0] = mLookAt[0] + mDistance * std::cos(mHead * sDeg2rad) * std::cos(mPitch * sDeg2rad); - mEye[1] = mLookAt[1] + mDistance * std::sin(mHead * sDeg2rad); - mEye[2] = mLookAt[2] + mDistance * std::cos(mHead * sDeg2rad) * std::sin(mPitch * sDeg2rad); - - mForward = mLookAt - mEye; - mForward.normalize(); - - mUp[1] = std::cos(mHead * sDeg2rad) > 0 ? 1.0 : -1.0; - mRight = mForward.cross(mUp); - } - - // Set up modelview matrix - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - gluLookAt(mEye[0], mEye[1], mEye[2], - mLookAt[0], mLookAt[1], mLookAt[2], - mUp[0], mUp[1], mUp[2]); - mNeedsDisplay = false; -} - - -void -Camera::keyCallback(int key, int) -{ -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow == NULL) return; - int state = glfwGetKey(mWindow, key); -#else - int state = glfwGetKey(key); -#endif - switch (state) { - case GLFW_PRESS: - switch(key) { - case GLFW_KEY_SPACE: - mZoomMode = true; - break; - } - break; - case GLFW_RELEASE: - switch(key) { - case GLFW_KEY_SPACE: - mZoomMode = false; - break; - } - break; - } - mChanged = true; -} - - -void -Camera::mouseButtonCallback(int button, int action) -{ - if (button == GLFW_MOUSE_BUTTON_LEFT) { - if (action == GLFW_PRESS) mMouseDown = true; - else if (action == GLFW_RELEASE) mMouseDown = false; - } else if (button == GLFW_MOUSE_BUTTON_RIGHT) { - if (action == GLFW_PRESS) { - mMouseDown = true; - mZoomMode = true; - } else if (action == GLFW_RELEASE) { - mMouseDown = false; - mZoomMode = false; - } - } - if (action == GLFW_RELEASE) mMouseDown = false; - - mStartTumbling = true; - mChanged = true; -} - - -void -Camera::mousePosCallback(int x, int y) -{ - if (mStartTumbling) { - mMouseXPos = x; - mMouseYPos = y; - mStartTumbling = false; - } - - double dx, dy; - dx = x - mMouseXPos; - dy = y - mMouseYPos; - - if (mMouseDown && !mZoomMode) { - mNeedsDisplay = true; - mHead += dy * mTumblingSpeed; - mPitch += dx * mTumblingSpeed; - } else if (mMouseDown && mZoomMode) { - mNeedsDisplay = true; - mLookAt += (dy * mUp - dx * mRight) * mStrafeSpeed; - } - - mMouseXPos = x; - mMouseYPos = y; - mChanged = true; -} - - -void -Camera::mouseWheelCallback(int pos, int prevPos) -{ - double speed = std::abs(prevPos - pos); - - if (prevPos < pos) { - mDistance += speed * mZoomSpeed; - } else { - double temp = mDistance - speed * mZoomSpeed; - mDistance = std::max(0.0, temp); - } - setSpeed(); - - mChanged = true; - mNeedsDisplay = true; -} - -} // namespace openvdb_viewer - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Camera.h b/openvdb_3_0_0_library/viewer/Camera.h deleted file mode 100755 index a3ba160..0000000 --- a/openvdb_3_0_0_library/viewer/Camera.h +++ /dev/null @@ -1,98 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// -// -/// @file Camera.h -/// @brief Basic GL camera class - -#ifndef OPENVDB_VIEWER_CAMERA_HAS_BEEN_INCLUDED -#define OPENVDB_VIEWER_CAMERA_HAS_BEEN_INCLUDED - -#include - -#ifdef OPENVDB_USE_GLFW_3 -struct GLFWwindow; // forward declaration -#endif - - -namespace openvdb_viewer { - -class Camera -{ -public: - Camera(); - -#ifdef OPENVDB_USE_GLFW_3 - void setWindow(GLFWwindow* w) { mWindow = w; } -#endif - - void aim(); - - void lookAt(const openvdb::Vec3d& p, double dist = 1.0); - void lookAtTarget(); - - void setTarget(const openvdb::Vec3d& p, double dist = 1.0); - - void setNearFarPlanes(double n, double f) { mNearPlane = n; mFarPlane = f; } - void setFieldOfView(double degrees) { mFov = degrees; } - void setSpeed(double zoomSpeed = 0.1, double strafeSpeed = 0.002, double tumblingSpeed = 0.02); - - void keyCallback(int key, int action); - void mouseButtonCallback(int button, int action); - void mousePosCallback(int x, int y); - void mouseWheelCallback(int pos, int prevPos); - - bool needsDisplay() const { return mNeedsDisplay; } - -private: - // Camera parameters - double mFov, mNearPlane, mFarPlane; - openvdb::Vec3d mTarget, mLookAt, mUp, mForward, mRight, mEye; - double mTumblingSpeed, mZoomSpeed, mStrafeSpeed; - double mHead, mPitch, mTargetDistance, mDistance; - - // Input states - bool mMouseDown, mStartTumbling, mZoomMode, mChanged, mNeedsDisplay; - double mMouseXPos, mMouseYPos; - int mWheelPos; - -#ifdef OPENVDB_USE_GLFW_3 - GLFWwindow* mWindow; -#endif - - static const double sDeg2rad; -}; // class Camera - -} // namespace openvdb_viewer - -#endif // OPENVDB_VIEWER_CAMERA_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/ClipBox.cc b/openvdb_3_0_0_library/viewer/ClipBox.cc deleted file mode 100755 index 13f8ed4..0000000 --- a/openvdb_3_0_0_library/viewer/ClipBox.cc +++ /dev/null @@ -1,297 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "ClipBox.h" - - -namespace openvdb_viewer { - -ClipBox::ClipBox() - : mStepSize(1.0) - , mBBox() - , mXIsActive(false) - , mYIsActive(false) - , mZIsActive(false) - , mShiftIsDown(false) - , mCtrlIsDown(false) -{ - GLdouble front [] = { 0.0, 0.0, 1.0, 0.0}; - std::copy(front, front + 4, mFrontPlane); - - GLdouble back [] = { 0.0, 0.0,-1.0, 0.0}; - std::copy(back, back + 4, mBackPlane); - - GLdouble left [] = { 1.0, 0.0, 0.0, 0.0}; - std::copy(left, left + 4, mLeftPlane); - - GLdouble right [] = {-1.0, 0.0, 0.0, 0.0}; - std::copy(right, right + 4, mRightPlane); - - GLdouble top [] = { 0.0, 1.0, 0.0, 0.0}; - std::copy(top, top + 4, mTopPlane); - - GLdouble bottom [] = { 0.0,-1.0, 0.0, 0.0}; - std::copy(bottom, bottom + 4, mBottomPlane); -} - - -void -ClipBox::setBBox(const openvdb::BBoxd& bbox) -{ - mBBox = bbox; - reset(); -} - - -void -ClipBox::update(double steps) -{ - if (mXIsActive) { - GLdouble s = steps * mStepSize.x() * 4.0; - - if (mShiftIsDown || mCtrlIsDown) { - mLeftPlane[3] -= s; - mLeftPlane[3] = -std::min(-mLeftPlane[3], (mRightPlane[3] - mStepSize.x())); - mLeftPlane[3] = -std::max(-mLeftPlane[3], mBBox.min().x()); - } - - if (!mShiftIsDown || mCtrlIsDown) { - mRightPlane[3] += s; - mRightPlane[3] = std::min(mRightPlane[3], mBBox.max().x()); - mRightPlane[3] = std::max(mRightPlane[3], (-mLeftPlane[3] + mStepSize.x())); - } - } - - if (mYIsActive) { - GLdouble s = steps * mStepSize.y() * 4.0; - - if (mShiftIsDown || mCtrlIsDown) { - mTopPlane[3] -= s; - mTopPlane[3] = -std::min(-mTopPlane[3], (mBottomPlane[3] - mStepSize.y())); - mTopPlane[3] = -std::max(-mTopPlane[3], mBBox.min().y()); - } - - if (!mShiftIsDown || mCtrlIsDown) { - mBottomPlane[3] += s; - mBottomPlane[3] = std::min(mBottomPlane[3], mBBox.max().y()); - mBottomPlane[3] = std::max(mBottomPlane[3], (-mTopPlane[3] + mStepSize.y())); - } - } - - if (mZIsActive) { - GLdouble s = steps * mStepSize.z() * 4.0; - - if (mShiftIsDown || mCtrlIsDown) { - mFrontPlane[3] -= s; - mFrontPlane[3] = -std::min(-mFrontPlane[3], (mBackPlane[3] - mStepSize.z())); - mFrontPlane[3] = -std::max(-mFrontPlane[3], mBBox.min().z()); - } - - if (!mShiftIsDown || mCtrlIsDown) { - mBackPlane[3] += s; - mBackPlane[3] = std::min(mBackPlane[3], mBBox.max().z()); - mBackPlane[3] = std::max(mBackPlane[3], (-mFrontPlane[3] + mStepSize.z())); - } - } -} - - -void -ClipBox::reset() -{ - mFrontPlane[3] = std::abs(mBBox.min().z()); - mBackPlane[3] = mBBox.max().z(); - - mLeftPlane[3] = std::abs(mBBox.min().x()); - mRightPlane[3] = mBBox.max().x(); - - mTopPlane[3] = std::abs(mBBox.min().y()); - mBottomPlane[3] = mBBox.max().y(); -} - - -void -ClipBox::update() const -{ - glClipPlane(GL_CLIP_PLANE0, mFrontPlane); - glClipPlane(GL_CLIP_PLANE1, mBackPlane); - glClipPlane(GL_CLIP_PLANE2, mLeftPlane); - glClipPlane(GL_CLIP_PLANE3, mRightPlane); - glClipPlane(GL_CLIP_PLANE4, mTopPlane); - glClipPlane(GL_CLIP_PLANE5, mBottomPlane); -} - - -void -ClipBox::enableClipping() const -{ - update(); - if (-mFrontPlane[3] > mBBox.min().z()) glEnable(GL_CLIP_PLANE0); - if (mBackPlane[3] < mBBox.max().z()) glEnable(GL_CLIP_PLANE1); - if (-mLeftPlane[3] > mBBox.min().x()) glEnable(GL_CLIP_PLANE2); - if (mRightPlane[3] < mBBox.max().x()) glEnable(GL_CLIP_PLANE3); - if (-mTopPlane[3] > mBBox.min().y()) glEnable(GL_CLIP_PLANE4); - if (mBottomPlane[3] < mBBox.max().y()) glEnable(GL_CLIP_PLANE5); -} - - -void -ClipBox::disableClipping() const -{ - glDisable(GL_CLIP_PLANE0); - glDisable(GL_CLIP_PLANE1); - glDisable(GL_CLIP_PLANE2); - glDisable(GL_CLIP_PLANE3); - glDisable(GL_CLIP_PLANE4); - glDisable(GL_CLIP_PLANE5); -} - - -void -ClipBox::render() -{ - bool drawBbox = false; - - const GLenum geoMode = GL_LINE_LOOP; - - glColor3d(0.1, 0.1, 0.9); - if (-mFrontPlane[3] > mBBox.min().z()) { - glBegin(geoMode); - glVertex3d(mBBox.min().x(), mBBox.min().y(), -mFrontPlane[3]); - glVertex3d(mBBox.min().x(), mBBox.max().y(), -mFrontPlane[3]); - glVertex3d(mBBox.max().x(), mBBox.max().y(), -mFrontPlane[3]); - glVertex3d(mBBox.max().x(), mBBox.min().y(), -mFrontPlane[3]); - glEnd(); - drawBbox = true; - } - - if (mBackPlane[3] < mBBox.max().z()) { - glBegin(geoMode); - glVertex3d(mBBox.min().x(), mBBox.min().y(), mBackPlane[3]); - glVertex3d(mBBox.min().x(), mBBox.max().y(), mBackPlane[3]); - glVertex3d(mBBox.max().x(), mBBox.max().y(), mBackPlane[3]); - glVertex3d(mBBox.max().x(), mBBox.min().y(), mBackPlane[3]); - glEnd(); - drawBbox = true; - } - - glColor3d(0.9, 0.1, 0.1); - if (-mLeftPlane[3] > mBBox.min().x()) { - glBegin(geoMode); - glVertex3d(-mLeftPlane[3], mBBox.min().y(), mBBox.min().z()); - glVertex3d(-mLeftPlane[3], mBBox.max().y(), mBBox.min().z()); - glVertex3d(-mLeftPlane[3], mBBox.max().y(), mBBox.max().z()); - glVertex3d(-mLeftPlane[3], mBBox.min().y(), mBBox.max().z()); - glEnd(); - drawBbox = true; - } - - if (mRightPlane[3] < mBBox.max().x()) { - glBegin(geoMode); - glVertex3d(mRightPlane[3], mBBox.min().y(), mBBox.min().z()); - glVertex3d(mRightPlane[3], mBBox.max().y(), mBBox.min().z()); - glVertex3d(mRightPlane[3], mBBox.max().y(), mBBox.max().z()); - glVertex3d(mRightPlane[3], mBBox.min().y(), mBBox.max().z()); - glEnd(); - drawBbox = true; - } - - glColor3d(0.1, 0.9, 0.1); - if (-mTopPlane[3] > mBBox.min().y()) { - glBegin(geoMode); - glVertex3d(mBBox.min().x(), -mTopPlane[3], mBBox.min().z()); - glVertex3d(mBBox.min().x(), -mTopPlane[3], mBBox.max().z()); - glVertex3d(mBBox.max().x(), -mTopPlane[3], mBBox.max().z()); - glVertex3d(mBBox.max().x(), -mTopPlane[3], mBBox.min().z()); - glEnd(); - drawBbox = true; - } - - if (mBottomPlane[3] < mBBox.max().y()) { - glBegin(geoMode); - glVertex3d(mBBox.min().x(), mBottomPlane[3], mBBox.min().z()); - glVertex3d(mBBox.min().x(), mBottomPlane[3], mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBottomPlane[3], mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBottomPlane[3], mBBox.min().z()); - glEnd(); - drawBbox = true; - } - - if (drawBbox) { - glColor3d(0.5, 0.5, 0.5); - glBegin(GL_LINE_LOOP); - glVertex3d(mBBox.min().x(), mBBox.min().y(), mBBox.min().z()); - glVertex3d(mBBox.min().x(), mBBox.min().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.min().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.min().y(), mBBox.min().z()); - glEnd(); - - glBegin(GL_LINE_LOOP); - glVertex3d(mBBox.min().x(), mBBox.max().y(), mBBox.min().z()); - glVertex3d(mBBox.min().x(), mBBox.max().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.max().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.max().y(), mBBox.min().z()); - glEnd(); - - glBegin(GL_LINES); - glVertex3d(mBBox.min().x(), mBBox.min().y(), mBBox.min().z()); - glVertex3d(mBBox.min().x(), mBBox.max().y(), mBBox.min().z()); - glVertex3d(mBBox.min().x(), mBBox.min().y(), mBBox.max().z()); - glVertex3d(mBBox.min().x(), mBBox.max().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.min().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.max().y(), mBBox.max().z()); - glVertex3d(mBBox.max().x(), mBBox.min().y(), mBBox.min().z()); - glVertex3d(mBBox.max().x(), mBBox.max().y(), mBBox.min().z()); - glEnd(); - } -} - - -//////////////////////////////////////// - - -bool -ClipBox::mouseButtonCallback(int /*button*/, int /*action*/) -{ - return false; // unhandled -} - - -bool -ClipBox::mousePosCallback(int /*x*/, int /*y*/) -{ - return false; // unhandled -} - -} // namespace openvdb_viewer - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/ClipBox.h b/openvdb_3_0_0_library/viewer/ClipBox.h deleted file mode 100755 index e235af9..0000000 --- a/openvdb_3_0_0_library/viewer/ClipBox.h +++ /dev/null @@ -1,92 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_VIEWER_CLIPBOX_HAS_BEEN_INCLUDED -#define OPENVDB_VIEWER_CLIPBOX_HAS_BEEN_INCLUDED - -#include - -#if defined(__APPLE__) || defined(MACOSX) -#include -#include -#else -#include -#include -#endif - - -namespace openvdb_viewer { - -class ClipBox -{ -public: - ClipBox(); - - void enableClipping() const; - void disableClipping() const; - - void setBBox(const openvdb::BBoxd&); - void setStepSize(const openvdb::Vec3d& s) { mStepSize = s; } - - void render(); - - void update(double steps); - void reset(); - - bool isActive() const { return (mXIsActive || mYIsActive ||mZIsActive); } - - bool& activateXPlanes() { return mXIsActive; } - bool& activateYPlanes() { return mYIsActive; } - bool& activateZPlanes() { return mZIsActive; } - - bool& shiftIsDown() { return mShiftIsDown; } - bool& ctrlIsDown() { return mCtrlIsDown; } - - bool mouseButtonCallback(int button, int action); - bool mousePosCallback(int x, int y); - -private: - void update() const; - - openvdb::Vec3d mStepSize; - openvdb::BBoxd mBBox; - bool mXIsActive, mYIsActive, mZIsActive, mShiftIsDown, mCtrlIsDown; - GLdouble mFrontPlane[4], mBackPlane[4], mLeftPlane[4], mRightPlane[4], - mTopPlane[4], mBottomPlane[4]; - double mMouseXPos, mMouseYPos; -}; // class ClipBox - -} // namespace openvdb_viewer - -#endif // OPENVDB_VIEWER_CLIPBOX_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Font.cc b/openvdb_3_0_0_library/viewer/Font.cc deleted file mode 100755 index c1479dc..0000000 --- a/openvdb_3_0_0_library/viewer/Font.cc +++ /dev/null @@ -1,200 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Font.h" - -#include // for OPENVDB_START_THREADSAFE_STATIC_WRITE - - -namespace openvdb_viewer { - -GLuint BitmapFont13::sOffset = 0; - -GLubyte BitmapFont13::sCharacters[95][13] = { - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36 }, - { 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x66, 0x00, 0x00 }, - { 0x00, 0x00, 0x18, 0x7E, 0xFF, 0x1B, 0x1F, 0x7E, 0xF8, 0xD8, 0xFF, 0x7E, 0x18 }, - { 0x00, 0x00, 0x0E, 0x1B, 0xDB, 0x6E, 0x30, 0x18, 0x0C, 0x76, 0xDB, 0xD8, 0x70 }, - { 0x00, 0x00, 0x7F, 0xC6, 0xCF, 0xD8, 0x70, 0x70, 0xD8, 0xCC, 0xCC, 0x6C, 0x38 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1C, 0x0C, 0x0E }, - { 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C }, - { 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30 }, - { 0x00, 0x00, 0x00, 0x00, 0x99, 0x5A, 0x3C, 0xFF, 0x3C, 0x5A, 0x99, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x00, 0x00 }, - { 0x00, 0x00, 0x30, 0x18, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0x03 }, - { 0x00, 0x00, 0x3C, 0x66, 0xC3, 0xE3, 0xF3, 0xDB, 0xCF, 0xC7, 0xC3, 0x66, 0x3C }, - { 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18 }, - { 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xE7, 0x7E }, - { 0x00, 0x00, 0x7E, 0xE7, 0x03, 0x03, 0x07, 0x7E, 0x07, 0x03, 0x03, 0xE7, 0x7E }, - { 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xFF, 0xCC, 0x6C, 0x3C, 0x1C, 0x0C }, - { 0x00, 0x00, 0x7E, 0xE7, 0x03, 0x03, 0x07, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC3, 0xC3, 0xC7, 0xFE, 0xC0, 0xC0, 0xC0, 0xE7, 0x7E }, - { 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x03, 0x03, 0xFF }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E }, - { 0x00, 0x00, 0x7E, 0xE7, 0x03, 0x03, 0x03, 0x7F, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E }, - { 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x30, 0x18, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06 }, - { 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60 }, - { 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x06, 0x03, 0xC3, 0xC3, 0x7E }, - { 0x00, 0x00, 0x3F, 0x60, 0xCF, 0xDB, 0xD3, 0xDD, 0xC3, 0x7E, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, 0x18 }, - { 0x00, 0x00, 0xFE, 0xC7, 0xC3, 0xC3, 0xC7, 0xFE, 0xC7, 0xC3, 0xC3, 0xC7, 0xFE }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE7, 0x7E }, - { 0x00, 0x00, 0xFC, 0xCE, 0xC7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0xCE, 0xFC }, - { 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF }, - { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0xC0, 0xC0, 0xC0, 0xFF }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC3, 0xC3, 0xCF, 0xC0, 0xC0, 0xC0, 0xC0, 0xE7, 0x7E }, - { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 }, - { 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E }, - { 0x00, 0x00, 0x7C, 0xEE, 0xC6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 }, - { 0x00, 0x00, 0xC3, 0xC6, 0xCC, 0xD8, 0xF0, 0xE0, 0xF0, 0xD8, 0xCC, 0xC6, 0xC3 }, - { 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 }, - { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xDB, 0xFF, 0xFF, 0xE7, 0xC3 }, - { 0x00, 0x00, 0xC7, 0xC7, 0xCF, 0xCF, 0xDF, 0xDB, 0xFB, 0xF3, 0xF3, 0xE3, 0xE3 }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E }, - { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC7, 0xC3, 0xC3, 0xC7, 0xFE }, - { 0x00, 0x00, 0x3F, 0x6E, 0xDF, 0xDB, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C }, - { 0x00, 0x00, 0xC3, 0xC6, 0xCC, 0xD8, 0xF0, 0xFE, 0xC7, 0xC3, 0xC3, 0xC7, 0xFE }, - { 0x00, 0x00, 0x7E, 0xE7, 0x03, 0x03, 0x07, 0x7E, 0xE0, 0xC0, 0xC0, 0xE7, 0x7E }, - { 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF }, - { 0x00, 0x00, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 }, - { 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 }, - { 0x00, 0x00, 0xC3, 0xE7, 0xFF, 0xFF, 0xDB, 0xDB, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 }, - { 0x00, 0x00, 0xC3, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0xC3 }, - { 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0xC3 }, - { 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0x60, 0x30, 0x7E, 0x0C, 0x06, 0x03, 0x03, 0xFF }, - { 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C }, - { 0x00, 0x03, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60 }, - { 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18 }, - { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70 }, - { 0x00, 0x00, 0x7F, 0xC3, 0xC3, 0x7F, 0x03, 0xC3, 0x7E, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 }, - { 0x00, 0x00, 0x7E, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0x7E, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x7F, 0xC3, 0xC3, 0xC3, 0xC3, 0x7F, 0x03, 0x03, 0x03, 0x03, 0x03 }, - { 0x00, 0x00, 0x7F, 0xC0, 0xC0, 0xFE, 0xC3, 0xC3, 0x7E, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x33, 0x1E }, - { 0x7E, 0xC3, 0x03, 0x03, 0x7F, 0xC3, 0xC3, 0xC3, 0x7E, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0 }, - { 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00 }, - { 0x38, 0x6C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x00 }, - { 0x00, 0x00, 0xC6, 0xCC, 0xF8, 0xF0, 0xD8, 0xCC, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0 }, - { 0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78 }, - { 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFE, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFC, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 }, - { 0xC0, 0xC0, 0xC0, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, 0x00, 0x00, 0x00, 0x00 }, - { 0x03, 0x03, 0x03, 0x7F, 0xC3, 0xC3, 0xC3, 0xC3, 0x7F, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xFE, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xFE, 0x03, 0x03, 0x7E, 0xC0, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x1C, 0x36, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x00 }, - { 0x00, 0x00, 0x7E, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC3, 0xE7, 0xFF, 0xDB, 0xC3, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x00, 0x00, 0x00, 0x00 }, - { 0xC0, 0x60, 0x60, 0x30, 0x18, 0x3C, 0x66, 0x66, 0xC3, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0xFF, 0x60, 0x30, 0x18, 0x0C, 0x06, 0xFF, 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x0F, 0x18, 0x18, 0x18, 0x38, 0xF0, 0x38, 0x18, 0x18, 0x18, 0x0F }, - { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }, - { 0x00, 0x00, 0xF0, 0x18, 0x18, 0x18, 0x1C, 0x0F, 0x1C, 0x18, 0x18, 0x18, 0xF0 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8F, 0xF1, 0x60, 0x00, 0x00, 0x00 } -}; // sCharacters - - -void -BitmapFont13::initialize() -{ - OPENVDB_START_THREADSAFE_STATIC_WRITE - - glShadeModel(GL_FLAT); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - BitmapFont13::sOffset = glGenLists(128); - - for (GLuint c = 32; c < 127; ++c) { - glNewList(c + BitmapFont13::sOffset, GL_COMPILE); - glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, BitmapFont13::sCharacters[c-32]); - glEndList(); - } - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE -} - - -void -BitmapFont13::enableFontRendering() -{ - glPushMatrix(); - GLint vp[4] = { 0, 0, 0, 0 }; - glGetIntegerv(GL_VIEWPORT, vp); - const int width = vp[2], height = std::max(1, vp[3]); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, 0, height, -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - //glShadeModel(GL_FLAT); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -} - - -void -BitmapFont13::disableFontRendering() -{ - glFlush(); - glPopMatrix(); -} - - -void -BitmapFont13::print(GLint px, GLint py, const std::string& str) -{ - glRasterPos2i(px, py); - glPushAttrib(GL_LIST_BIT); - glListBase(BitmapFont13::sOffset); - glCallLists(GLsizei(str.length()), GL_UNSIGNED_BYTE, - reinterpret_cast(str.c_str())); - glPopAttrib(); -} - -} // namespace openvdb_viewer - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Font.h b/openvdb_3_0_0_library/viewer/Font.h deleted file mode 100755 index c4c8f59..0000000 --- a/openvdb_3_0_0_library/viewer/Font.h +++ /dev/null @@ -1,70 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_VIEWER_FONT_HAS_BEEN_INCLUDED -#define OPENVDB_VIEWER_FONT_HAS_BEEN_INCLUDED - -#include - -#if defined(__APPLE__) || defined(MACOSX) -#include -#include -#else -#include -#include -#endif - - -namespace openvdb_viewer { - -class BitmapFont13 -{ -public: - BitmapFont13() {} - - static void initialize(); - - static void enableFontRendering(); - static void disableFontRendering(); - - static void print(GLint px, GLint py, const std::string&); - -private: - static GLuint sOffset; - static GLubyte sCharacters[95][13]; -}; - -} // namespace openvdb_viewer - -#endif // OPENVDB_VIEWER_FONT_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/RenderModules.cc b/openvdb_3_0_0_library/viewer/RenderModules.cc deleted file mode 100755 index 6f58447..0000000 --- a/openvdb_3_0_0_library/viewer/RenderModules.cc +++ /dev/null @@ -1,1480 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "RenderModules.h" -#include -#include -#include - - -namespace openvdb_viewer { - -namespace util { - -/// Helper class used internally by processTypedGrid() -template -struct GridProcessor { - static inline void call(OpType& op, openvdb::GridBase::Ptr grid) { -#ifdef _MSC_VER - op.operator()(openvdb::gridPtrCast(grid)); -#else - op.template operator()(openvdb::gridPtrCast(grid)); -#endif - } -}; - -/// Helper class used internally by processTypedGrid() -template -struct GridProcessor { - static inline void call(OpType& op, openvdb::GridBase::ConstPtr grid) { -#ifdef _MSC_VER - op.operator()(openvdb::gridConstPtrCast(grid)); -#else - op.template operator()(openvdb::gridConstPtrCast(grid)); -#endif - } -}; - - -/// Helper function used internally by processTypedGrid() -template -inline void -doProcessTypedGrid(GridPtrType grid, OpType& op) -{ - GridProcessor::value>::call(op, grid); -} - - -//////////////////////////////////////// - - -/// @brief Utility function that, given a generic grid pointer, -/// calls a functor on the fully-resolved grid -/// -/// Usage: -/// @code -/// struct PruneOp { -/// template -/// void operator()(typename GridT::Ptr grid) const { grid->tree()->prune(); } -/// }; -/// -/// processTypedGrid(myGridPtr, PruneOp()); -/// @endcode -/// -/// @return @c false if the grid type is unknown or unhandled. -template -bool -processTypedGrid(GridPtrType grid, OpType& op) -{ - using namespace openvdb; - if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else return false; - return true; -} - - -/// @brief Utility function that, given a generic grid pointer, calls -/// a functor on the fully-resolved grid, provided that the grid's -/// voxel values are scalars -/// -/// Usage: -/// @code -/// struct PruneOp { -/// template -/// void operator()(typename GridT::Ptr grid) const { grid->tree()->prune(); } -/// }; -/// -/// processTypedScalarGrid(myGridPtr, PruneOp()); -/// @endcode -/// -/// @return @c false if the grid type is unknown or non-scalar. -template -bool -processTypedScalarGrid(GridPtrType grid, OpType& op) -{ - using namespace openvdb; - if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else return false; - return true; -} - - -/// @brief Utility function that, given a generic grid pointer, calls -/// a functor on the fully-resolved grid, provided that the grid's -/// voxel values are vectors -template -bool -processTypedVectorGrid(GridPtrType grid, OpType& op) -{ - using namespace openvdb; - if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else if (grid->template isType()) doProcessTypedGrid(grid, op); - else return false; - return true; -} - -} // namespace util - - -//////////////////////////////////////// - - -// BufferObject - -BufferObject::BufferObject(): - mVertexBuffer(0), - mNormalBuffer(0), - mIndexBuffer(0), - mColorBuffer(0), - mPrimType(GL_POINTS), - mPrimNum(0) -{ -} - -BufferObject::~BufferObject() { clear(); } - -void -BufferObject::render() const -{ - if (mPrimNum == 0 || !glIsBuffer(mIndexBuffer) || !glIsBuffer(mVertexBuffer)) { - OPENVDB_LOG_DEBUG_RUNTIME("request to render empty or uninitialized buffer"); - return; - } - - const bool usesColorBuffer = glIsBuffer(mColorBuffer); - const bool usesNormalBuffer = glIsBuffer(mNormalBuffer); - - glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, 0); - - if (usesColorBuffer) { - glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_FLOAT, 0, 0); - } - - if (usesNormalBuffer) { - glEnableClientState(GL_NORMAL_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, mNormalBuffer); - glNormalPointer(GL_FLOAT, 0, 0); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); - glDrawElements(mPrimType, mPrimNum, GL_UNSIGNED_INT, 0); - - // disable client-side capabilities - if (usesColorBuffer) glDisableClientState(GL_COLOR_ARRAY); - if (usesNormalBuffer) glDisableClientState(GL_NORMAL_ARRAY); - - // release vbo's - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void -BufferObject::genIndexBuffer(const std::vector& v, GLenum primType) -{ - // clear old buffer - if (glIsBuffer(mIndexBuffer) == GL_TRUE) glDeleteBuffers(1, &mIndexBuffer); - - // gen new buffer - glGenBuffers(1, &mIndexBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); - if (glIsBuffer(mIndexBuffer) == GL_FALSE) throw "Error: Unable to create index buffer"; - - // upload data - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - sizeof(GLuint) * v.size(), &v[0], GL_STATIC_DRAW); // upload data - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to upload index buffer data"; - - // release buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - mPrimNum = GLsizei(v.size()); - mPrimType = primType; -} - -void -BufferObject::genVertexBuffer(const std::vector& v) -{ - if (glIsBuffer(mVertexBuffer) == GL_TRUE) glDeleteBuffers(1, &mVertexBuffer); - - glGenBuffers(1, &mVertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); - if (glIsBuffer(mVertexBuffer) == GL_FALSE) throw "Error: Unable to create vertex buffer"; - - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * v.size(), &v[0], GL_STATIC_DRAW); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to upload vertex buffer data"; - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void -BufferObject::genNormalBuffer(const std::vector& v) -{ - if (glIsBuffer(mNormalBuffer) == GL_TRUE) glDeleteBuffers(1, &mNormalBuffer); - - glGenBuffers(1, &mNormalBuffer); - glBindBuffer(GL_ARRAY_BUFFER, mNormalBuffer); - if (glIsBuffer(mNormalBuffer) == GL_FALSE) throw "Error: Unable to create normal buffer"; - - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * v.size(), &v[0], GL_STATIC_DRAW); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to upload normal buffer data"; - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void -BufferObject::genColorBuffer(const std::vector& v) -{ - if (glIsBuffer(mColorBuffer) == GL_TRUE) glDeleteBuffers(1, &mColorBuffer); - - glGenBuffers(1, &mColorBuffer); - glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer); - if (glIsBuffer(mColorBuffer) == GL_FALSE) throw "Error: Unable to create color buffer"; - - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * v.size(), &v[0], GL_STATIC_DRAW); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to upload color buffer data"; - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void -BufferObject::clear() -{ - if (glIsBuffer(mIndexBuffer) == GL_TRUE) glDeleteBuffers(1, &mIndexBuffer); - if (glIsBuffer(mVertexBuffer) == GL_TRUE) glDeleteBuffers(1, &mVertexBuffer); - if (glIsBuffer(mColorBuffer) == GL_TRUE) glDeleteBuffers(1, &mColorBuffer); - if (glIsBuffer(mNormalBuffer) == GL_TRUE) glDeleteBuffers(1, &mNormalBuffer); - - mPrimType = GL_POINTS; - mPrimNum = 0; -} - - -//////////////////////////////////////// - - -ShaderProgram::ShaderProgram(): - mProgram(0), - mVertShader(0), - mFragShader(0) -{ -} - -ShaderProgram::~ShaderProgram() { clear(); } - -void -ShaderProgram::setVertShader(const std::string& s) -{ - mVertShader = glCreateShader(GL_VERTEX_SHADER); - if (glIsShader(mVertShader) == GL_FALSE) throw "Error: Unable to create shader program."; - - GLint length = GLint(s.length()); - const char *str = s.c_str(); - glShaderSource(mVertShader, 1, &str, &length); - - glCompileShader(mVertShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to compile vertex shader."; -} - -void -ShaderProgram::setFragShader(const std::string& s) -{ - mFragShader = glCreateShader(GL_FRAGMENT_SHADER); - if (glIsShader(mFragShader) == GL_FALSE) throw "Error: Unable to create shader program."; - - GLint length = GLint(s.length()); - const char *str = s.c_str(); - glShaderSource(mFragShader, 1, &str, &length); - - glCompileShader(mFragShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to compile fragment shader."; -} - -void -ShaderProgram::build() -{ - mProgram = glCreateProgram(); - if (glIsProgram(mProgram) == GL_FALSE) throw "Error: Unable to create shader program."; - - if (glIsShader(mVertShader) == GL_TRUE) glAttachShader(mProgram, mVertShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to attach vertex shader."; - - if (glIsShader(mFragShader) == GL_TRUE) glAttachShader(mProgram, mFragShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to attach fragment shader."; - - - glLinkProgram(mProgram); - - GLint linked = 0; - glGetProgramiv(mProgram, GL_LINK_STATUS, &linked); - - if (!linked) throw "Error: Unable to link shader program."; -} - -void -ShaderProgram::build(const std::vector& attributes) -{ - mProgram = glCreateProgram(); - if (glIsProgram(mProgram) == GL_FALSE) throw "Error: Unable to create shader program."; - - for (GLuint n = 0, N = GLuint(attributes.size()); n < N; ++n) { - glBindAttribLocation(mProgram, n, attributes[n]); - } - - if (glIsShader(mVertShader) == GL_TRUE) glAttachShader(mProgram, mVertShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to attach vertex shader."; - - if (glIsShader(mFragShader) == GL_TRUE) glAttachShader(mProgram, mFragShader); - if (GL_NO_ERROR != glGetError()) throw "Error: Unable to attach fragment shader."; - - glLinkProgram(mProgram); - - GLint linked; - glGetProgramiv(mProgram, GL_LINK_STATUS, &linked); - - if (!linked) throw "Error: Unable to link shader program."; -} - -void -ShaderProgram::startShading() const -{ - if (glIsProgram(mProgram) == GL_FALSE) { - throw "Error: called startShading() on uncompiled shader program."; - } - glUseProgram(mProgram); -} - -void -ShaderProgram::stopShading() const -{ - glUseProgram(0); -} - -void -ShaderProgram::clear() -{ - GLsizei numShaders = 0; - GLuint shaders[2] = { 0, 0 }; - - glGetAttachedShaders(mProgram, 2, &numShaders, shaders); - - // detach and remove shaders - for (GLsizei n = 0; n < numShaders; ++n) { - - glDetachShader(mProgram, shaders[n]); - - if (glIsShader(shaders[n]) == GL_TRUE) glDeleteShader(shaders[n]); - } - - // remove program - if (glIsProgram(mProgram)) glDeleteProgram(mProgram); -} - - -//////////////////////////////////////// - -// ViewportModule - -ViewportModule::ViewportModule(): - mAxisGnomonScale(1.5), - mGroundPlaneScale(8.0) -{ -} - - -void -ViewportModule::render() -{ - if (!mIsVisible) return; - - /// @todo use VBO's - - // Ground plane - glPushMatrix(); - glScalef(mGroundPlaneScale, mGroundPlaneScale, mGroundPlaneScale); - glColor3d(0.6, 0.6, 0.6); - - OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN - - float step = 0.125; - for (float x = -1; x < 1.125; x+=step) { - - if (fabs(x) == 0.5 || fabs(x) == 0.0) { - glLineWidth(1.5); - } else { - glLineWidth(1.0); - } - - glBegin( GL_LINES ); - glVertex3f(x, 0, 1); - glVertex3f(x, 0, -1); - glVertex3f(1, 0, x); - glVertex3f(-1, 0, x); - glEnd(); - } - - OPENVDB_NO_FP_EQUALITY_WARNING_END - - - glPopMatrix(); - - // Axis gnomon - GLfloat modelview[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, &modelview[0]); - - // Stash current viewport settigs. - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, &viewport[0]); - - GLint width = viewport[2] / 20; - GLint height = viewport[3] / 20; - glViewport(0, 0, width, height); - - - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - - GLfloat campos[3] = { modelview[2], modelview[6], modelview[10] }; - GLfloat up[3] = { modelview[1], modelview[5], modelview[9] }; - - gluLookAt(campos[0], campos[1], campos[2], 0.0, 0.0, 0.0, up[0], up[1], up[2]); - - glScalef(mAxisGnomonScale, mAxisGnomonScale, mAxisGnomonScale); - - glLineWidth(1.0); - - glBegin(GL_LINES); - glColor3f(1.0f, 0.0f, 0.0f); - glVertex3f(0, 0, 0); - glVertex3f(1, 0, 0); - - glColor3f(0.0f, 1.0f, 0.0f ); - glVertex3f(0, 0, 0); - glVertex3f(0, 1, 0); - - glColor3f(0.0f, 0.0f, 1.0f); - glVertex3f(0, 0, 0); - glVertex3f(0, 0, 1); - glEnd(); - - glLineWidth(1.0); - - // reset viewport - glPopMatrix(); - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - -} - - -//////////////////////////////////////// - - -class TreeTopologyOp -{ -public: - TreeTopologyOp(BufferObject& buffer) : mBuffer(&buffer) {} - - template - void operator()(typename GridType::ConstPtr grid) - { - using openvdb::Index64; - - Index64 nodeCount = grid->tree().leafCount() + grid->tree().nonLeafCount(); - const Index64 N = nodeCount * 8 * 3; - - std::vector points(N); - std::vector colors(N); - std::vector indices(N); - - - openvdb::Vec3d ptn; - openvdb::Vec3s color; - openvdb::CoordBBox bbox; - Index64 pOffset = 0, iOffset = 0, cOffset = 0, idx = 0; - - for (typename GridType::TreeType::NodeCIter iter = grid->tree().cbeginNode(); iter; ++iter) - { - iter.getBoundingBox(bbox); - - // Nodes are rendered as cell-centered - const openvdb::Vec3d min(bbox.min().x()-0.5, bbox.min().y()-0.5, bbox.min().z()-0.5); - const openvdb::Vec3d max(bbox.max().x()+0.5, bbox.max().y()+0.5, bbox.max().z()+0.5); - - // corner 1 - ptn = grid->indexToWorld(min); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 2 - ptn = openvdb::Vec3d(min.x(), min.y(), max.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 3 - ptn = openvdb::Vec3d(max.x(), min.y(), max.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 4 - ptn = openvdb::Vec3d(max.x(), min.y(), min.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 5 - ptn = openvdb::Vec3d(min.x(), max.y(), min.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 6 - ptn = openvdb::Vec3d(min.x(), max.y(), max.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 7 - ptn = grid->indexToWorld(max); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - // corner 8 - ptn = openvdb::Vec3d(max.x(), max.y(), min.z()); - ptn = grid->indexToWorld(ptn); - points[pOffset++] = static_cast(ptn[0]); - points[pOffset++] = static_cast(ptn[1]); - points[pOffset++] = static_cast(ptn[2]); - - - // edge 1 - indices[iOffset++] = GLuint(idx); - indices[iOffset++] = GLuint(idx + 1); - // edge 2 - indices[iOffset++] = GLuint(idx + 1); - indices[iOffset++] = GLuint(idx + 2); - // edge 3 - indices[iOffset++] = GLuint(idx + 2); - indices[iOffset++] = GLuint(idx + 3); - // edge 4 - indices[iOffset++] = GLuint(idx + 3); - indices[iOffset++] = GLuint(idx); - // edge 5 - indices[iOffset++] = GLuint(idx + 4); - indices[iOffset++] = GLuint(idx + 5); - // edge 6 - indices[iOffset++] = GLuint(idx + 5); - indices[iOffset++] = GLuint(idx + 6); - // edge 7 - indices[iOffset++] = GLuint(idx + 6); - indices[iOffset++] = GLuint(idx + 7); - // edge 8 - indices[iOffset++] = GLuint(idx + 7); - indices[iOffset++] = GLuint(idx + 4); - // edge 9 - indices[iOffset++] = GLuint(idx); - indices[iOffset++] = GLuint(idx + 4); - // edge 10 - indices[iOffset++] = GLuint(idx + 1); - indices[iOffset++] = GLuint(idx + 5); - // edge 11 - indices[iOffset++] = GLuint(idx + 2); - indices[iOffset++] = GLuint(idx + 6); - // edge 12 - indices[iOffset++] = GLuint(idx + 3); - indices[iOffset++] = GLuint(idx + 7); - - // node vertex color - const int level = iter.getLevel(); - color = sNodeColors[(level == 0) ? 3 : (level == 1) ? 2 : 1]; - - for (Index64 n = 0; n < 8; ++n) { - colors[cOffset++] = color[0]; - colors[cOffset++] = color[1]; - colors[cOffset++] = color[2]; - } - - idx += 8; - } // end node iteration - - // gen buffers and upload data to GPU - mBuffer->genVertexBuffer(points); - mBuffer->genColorBuffer(colors); - mBuffer->genIndexBuffer(indices, GL_LINES); - } - -private: - BufferObject *mBuffer; - - static openvdb::Vec3s sNodeColors[]; -}; // TreeTopologyOp - - -openvdb::Vec3s TreeTopologyOp::sNodeColors[] = { - openvdb::Vec3s(0.045f, 0.045f, 0.045f), // root - openvdb::Vec3s(0.0432f, 0.33f, 0.0411023f), // first internal node level - openvdb::Vec3s(0.871f, 0.394f, 0.01916f), // intermediate internal node levels - openvdb::Vec3s(0.00608299f, 0.279541f, 0.625f) // leaf nodes -}; - - -//////////////////////////////////////// - -// Tree topology render module - -TreeTopologyModule::TreeTopologyModule(const openvdb::GridBase::ConstPtr& grid): - mGrid(grid), - mIsInitialized(false) -{ - mShader.setVertShader( - "#version 120\n" - "void main() {\n" - "gl_FrontColor = gl_Color;\n" - "gl_Position = ftransform();\n" - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" - "}\n"); - - mShader.setFragShader( - "#version 120\n" - "void main() {\n" - "gl_FragColor = gl_Color;}\n"); - - mShader.build(); -} - - -void -TreeTopologyModule::init() -{ - mIsInitialized = true; - - // extract grid topology - TreeTopologyOp drawTopology(mBufferObject); - - if (!util::processTypedGrid(mGrid, drawTopology)) { - OPENVDB_LOG_INFO("Ignoring unrecognized grid type" - " during tree topology module initialization."); - } -} - - -void -TreeTopologyModule::render() -{ - if (!mIsVisible) return; - if (!mIsInitialized) init(); - - mShader.startShading(); - - mBufferObject.render(); - - mShader.stopShading(); -} - - -//////////////////////////////////////// - - -template -class PointGenerator -{ -public: - typedef openvdb::tree::LeafManager LeafManagerType; - - PointGenerator( - std::vector& points, - std::vector& indices, - LeafManagerType& leafs, - std::vector& indexMap, - const openvdb::math::Transform& transform, - openvdb::Index64 voxelsPerLeaf = TreeType::LeafNodeType::NUM_VOXELS) - : mPoints(points) - , mIndices(indices) - , mLeafs(leafs) - , mIndexMap(indexMap) - , mTransform(transform) - , mVoxelsPerLeaf(voxelsPerLeaf) - { - } - - void runParallel() - { - tbb::parallel_for(mLeafs.getRange(), *this); - } - - - inline void operator()(const typename LeafManagerType::RangeType& range) const - { - using openvdb::Index64; - - typedef typename TreeType::LeafNodeType::ValueOnCIter ValueOnCIter; - - openvdb::Vec3d pos; - size_t index = 0; - Index64 activeVoxels = 0; - - for (size_t n = range.begin(); n < range.end(); ++n) { - - index = mIndexMap[n]; - ValueOnCIter it = mLeafs.leaf(n).cbeginValueOn(); - - activeVoxels = mLeafs.leaf(n).onVoxelCount(); - - if (activeVoxels <= mVoxelsPerLeaf) { - - for ( ; it; ++it) { - pos = mTransform.indexToWorld(it.getCoord()); - insertPoint(pos, index); - ++index; - } - - } else if (1 == mVoxelsPerLeaf) { - - pos = mTransform.indexToWorld(it.getCoord()); - insertPoint(pos, index); - - } else { - - std::vector coords; - coords.reserve(static_cast(activeVoxels)); - for ( ; it; ++it) { coords.push_back(it.getCoord()); } - - pos = mTransform.indexToWorld(coords[0]); - insertPoint(pos, index); - ++index; - - pos = mTransform.indexToWorld(coords[static_cast(activeVoxels-1)]); - insertPoint(pos, index); - ++index; - - Index64 r = Index64(std::floor(double(mVoxelsPerLeaf) / activeVoxels)); - for (Index64 i = 1, I = mVoxelsPerLeaf - 2; i < I; ++i) { - pos = mTransform.indexToWorld(coords[static_cast(i * r)]); - insertPoint(pos, index); - ++index; - } - } - } - } - -private: - void insertPoint(const openvdb::Vec3d& pos, size_t index) const - { - mIndices[index] = GLuint(index); - const size_t element = index * 3; - mPoints[element ] = static_cast(pos[0]); - mPoints[element + 1] = static_cast(pos[1]); - mPoints[element + 2] = static_cast(pos[2]); - } - - std::vector& mPoints; - std::vector& mIndices; - LeafManagerType& mLeafs; - std::vector& mIndexMap; - const openvdb::math::Transform& mTransform; - const openvdb::Index64 mVoxelsPerLeaf; -}; // PointGenerator - - -template -class PointAttributeGenerator -{ -public: - typedef typename GridType::ValueType ValueType; - - PointAttributeGenerator( - std::vector& points, - std::vector& colors, - const GridType& grid, - ValueType minValue, - ValueType maxValue, - openvdb::Vec3s (&colorMap)[4], - bool isLevelSet = false) - : mPoints(points) - , mColors(colors) - , mNormals(NULL) - , mGrid(grid) - , mAccessor(grid.tree()) - , mMinValue(minValue) - , mMaxValue(maxValue) - , mColorMap(colorMap) - , mIsLevelSet(isLevelSet) - , mZeroValue(openvdb::zeroVal()) - { - init(); - } - - PointAttributeGenerator( - std::vector& points, - std::vector& colors, - std::vector& normals, - const GridType& grid, - ValueType minValue, - ValueType maxValue, - openvdb::Vec3s (&colorMap)[4], - bool isLevelSet = false) - : mPoints(points) - , mColors(colors) - , mNormals(&normals) - , mGrid(grid) - , mAccessor(grid.tree()) - , mMinValue(minValue) - , mMaxValue(maxValue) - , mColorMap(colorMap) - , mIsLevelSet(isLevelSet) - , mZeroValue(openvdb::zeroVal()) - { - init(); - } - - void runParallel() - { - tbb::parallel_for(tbb::blocked_range(0, (mPoints.size() / 3)), *this); - } - - inline void operator()(const tbb::blocked_range& range) const - { - openvdb::Coord ijk; - openvdb::Vec3d pos, tmpNormal, normal(0.0, -1.0, 0.0); - openvdb::Vec3s color(0.9f, 0.3f, 0.3f); - float w = 0.0; - - size_t e1, e2, e3, voxelNum = 0; - for (size_t n = range.begin(); n < range.end(); ++n) { - e1 = 3 * n; - e2 = e1 + 1; - e3 = e2 + 1; - - pos[0] = mPoints[e1]; - pos[1] = mPoints[e2]; - pos[2] = mPoints[e3]; - - pos = mGrid.worldToIndex(pos); - ijk[0] = int(pos[0]); - ijk[1] = int(pos[1]); - ijk[2] = int(pos[2]); - - const ValueType& value = mAccessor.getValue(ijk); - - if (value < mZeroValue) { // is negative - if (mIsLevelSet) { - color = mColorMap[1]; - } else { - w = (float(value) - mOffset[1]) * mScale[1]; - color = openvdb::Vec3s(w * mColorMap[0] + (1.0 - w) * mColorMap[1]); - } - } else { - if (mIsLevelSet) { - color = mColorMap[2]; - } else { - w = (float(value) - mOffset[0]) * mScale[0]; - color = openvdb::Vec3s(w * mColorMap[2] + (1.0 - w) * mColorMap[3]); - } - } - - mColors[e1] = color[0]; - mColors[e2] = color[1]; - mColors[e3] = color[2]; - - if (mNormals) { - - if ((voxelNum % 2) == 0) { - tmpNormal = openvdb::Vec3d(openvdb::math::ISGradient< - openvdb::math::CD_2ND>::result(mAccessor, ijk)); - - double length = tmpNormal.length(); - if (length > 1.0e-7) { - tmpNormal *= 1.0 / length; - normal = tmpNormal; - } - } - ++voxelNum; - - (*mNormals)[e1] = static_cast(normal[0]); - (*mNormals)[e2] = static_cast(normal[1]); - (*mNormals)[e3] = static_cast(normal[2]); - } - } - } - -private: - - void init() - { - mOffset[0] = static_cast(std::min(mZeroValue, mMinValue)); - mScale[0] = static_cast( - 1.0 / (std::abs(std::max(mZeroValue, mMaxValue) - mOffset[0]))); - mOffset[1] = static_cast(std::min(mZeroValue, mMinValue)); - mScale[1] = static_cast( - 1.0 / (std::abs(std::max(mZeroValue, mMaxValue) - mOffset[1]))); - } - - std::vector& mPoints; - std::vector& mColors; - std::vector* mNormals; - - const GridType& mGrid; - openvdb::tree::ValueAccessor mAccessor; - - ValueType mMinValue, mMaxValue; - openvdb::Vec3s (&mColorMap)[4]; - const bool mIsLevelSet; - - ValueType mZeroValue; - float mOffset[2], mScale[2]; -}; // PointAttributeGenerator - - -//////////////////////////////////////// - - -class ActiveScalarValuesOp -{ -public: - ActiveScalarValuesOp( - BufferObject& interiorBuffer, BufferObject& surfaceBuffer) - : mInteriorBuffer(&interiorBuffer) - , mSurfaceBuffer(&surfaceBuffer) - { - } - - template - void operator()(typename GridType::ConstPtr grid) - { - using openvdb::Index64; - - const Index64 maxVoxelPoints = 26000000; - - openvdb::Vec3s colorMap[4]; - colorMap[0] = openvdb::Vec3s(0.3, 0.9, 0.3); // green - colorMap[1] = openvdb::Vec3s(0.9, 0.3, 0.3); // red - colorMap[2] = openvdb::Vec3s(0.9, 0.9, 0.3); // yellow - colorMap[3] = openvdb::Vec3s(0.3, 0.3, 0.9); // blue - - ////////// - - typedef typename GridType::ValueType ValueType; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::template ValueConverter::Type BoolTreeT; - - const TreeType& tree = grid->tree(); - const bool isLevelSetGrid = grid->getGridClass() == openvdb::GRID_LEVEL_SET; - - ValueType minValue, maxValue; - openvdb::tree::LeafManager leafs(tree); - - { - openvdb::tools::MinMaxVoxel minmax(leafs); - minmax.runParallel(); - minValue = minmax.minVoxel(); - maxValue = minmax.maxVoxel(); - } - - openvdb::Index64 voxelsPerLeaf = TreeType::LeafNodeType::NUM_VOXELS; - - if (!isLevelSetGrid) { - - typename BoolTreeT::Ptr interiorMask(new BoolTreeT(false)); - - { // Generate Interior Points - interiorMask->topologyUnion(tree); - interiorMask->voxelizeActiveTiles(); - - if (interiorMask->activeLeafVoxelCount() > maxVoxelPoints) { - voxelsPerLeaf = std::max(1, - (maxVoxelPoints / interiorMask->leafCount())); - } - - openvdb::tools::erodeVoxels(*interiorMask, 2); - - openvdb::tree::LeafManager maskleafs(*interiorMask); - std::vector indexMap(maskleafs.leafCount()); - size_t voxelCount = 0; - for (Index64 l = 0, L = maskleafs.leafCount(); l < L; ++l) { - indexMap[l] = voxelCount; - voxelCount += std::min(maskleafs.leaf(l).onVoxelCount(), voxelsPerLeaf); - } - - std::vector points(voxelCount * 3), colors(voxelCount * 3); - std::vector indices(voxelCount); - - PointGenerator pointGen( - points, indices, maskleafs, indexMap, grid->transform(), voxelsPerLeaf); - pointGen.runParallel(); - - - PointAttributeGenerator attributeGen( - points, colors, *grid, minValue, maxValue, colorMap); - attributeGen.runParallel(); - - - // gen buffers and upload data to GPU - mInteriorBuffer->genVertexBuffer(points); - mInteriorBuffer->genColorBuffer(colors); - mInteriorBuffer->genIndexBuffer(indices, GL_POINTS); - } - - { // Generate Surface Points - typename BoolTreeT::Ptr surfaceMask(new BoolTreeT(false)); - surfaceMask->topologyUnion(tree); - surfaceMask->voxelizeActiveTiles(); - - openvdb::tree::ValueAccessor interiorAcc(*interiorMask); - for (typename BoolTreeT::LeafIter leafIt = surfaceMask->beginLeaf(); - leafIt; ++leafIt) - { - const typename BoolTreeT::LeafNodeType* leaf = - interiorAcc.probeConstLeaf(leafIt->origin()); - if (leaf) leafIt->topologyDifference(*leaf, false); - } - openvdb::tools::pruneInactive(*surfaceMask); - - openvdb::tree::LeafManager maskleafs(*surfaceMask); - std::vector indexMap(maskleafs.leafCount()); - size_t voxelCount = 0; - for (Index64 l = 0, L = maskleafs.leafCount(); l < L; ++l) { - indexMap[l] = voxelCount; - voxelCount += std::min(maskleafs.leaf(l).onVoxelCount(), voxelsPerLeaf); - } - - std::vector - points(voxelCount * 3), - colors(voxelCount * 3), - normals(voxelCount * 3); - std::vector indices(voxelCount); - - PointGenerator pointGen( - points, indices, maskleafs, indexMap, grid->transform(), voxelsPerLeaf); - pointGen.runParallel(); - - PointAttributeGenerator attributeGen( - points, colors, normals, *grid, minValue, maxValue, colorMap); - attributeGen.runParallel(); - - mSurfaceBuffer->genVertexBuffer(points); - mSurfaceBuffer->genColorBuffer(colors); - mSurfaceBuffer->genNormalBuffer(normals); - mSurfaceBuffer->genIndexBuffer(indices, GL_POINTS); - } - - return; - } - - // Level set rendering - if (tree.activeLeafVoxelCount() > maxVoxelPoints) { - voxelsPerLeaf = std::max(1, (maxVoxelPoints / tree.leafCount())); - } - - std::vector indexMap(leafs.leafCount()); - size_t voxelCount = 0; - for (Index64 l = 0, L = leafs.leafCount(); l < L; ++l) { - indexMap[l] = voxelCount; - voxelCount += std::min(leafs.leaf(l).onVoxelCount(), voxelsPerLeaf); - } - - std::vector - points(voxelCount * 3), - colors(voxelCount * 3), - normals(voxelCount * 3); - std::vector indices(voxelCount); - - PointGenerator pointGen( - points, indices, leafs, indexMap, grid->transform(), voxelsPerLeaf); - pointGen.runParallel(); - - PointAttributeGenerator attributeGen( - points, colors, normals, *grid, minValue, maxValue, colorMap, isLevelSetGrid); - attributeGen.runParallel(); - - mSurfaceBuffer->genVertexBuffer(points); - mSurfaceBuffer->genColorBuffer(colors); - mSurfaceBuffer->genNormalBuffer(normals); - mSurfaceBuffer->genIndexBuffer(indices, GL_POINTS); - } - -private: - BufferObject *mInteriorBuffer; - BufferObject *mSurfaceBuffer; -}; // ActiveScalarValuesOp - - -class ActiveVectorValuesOp -{ -public: - ActiveVectorValuesOp(BufferObject& vectorBuffer) - : mVectorBuffer(&vectorBuffer) - { - } - - template - void operator()(typename GridType::ConstPtr grid) - { - using openvdb::Index64; - - typedef typename GridType::ValueType ValueType; - typedef typename GridType::TreeType TreeType; - typedef typename TreeType::template ValueConverter::Type BoolTreeT; - - - const TreeType& tree = grid->tree(); - - double length = 0.0; - { - ValueType minVal, maxVal; - tree.evalMinMax(minVal, maxVal); - length = maxVal.length(); - } - - typename BoolTreeT::Ptr mask(new BoolTreeT(false)); - mask->topologyUnion(tree); - mask->voxelizeActiveTiles(); - - ///@todo thread and restructure. - - const Index64 voxelCount = mask->activeLeafVoxelCount(); - - const Index64 pointCount = voxelCount * 2; - std::vector points(pointCount*3), colors(pointCount*3); - std::vector indices(pointCount); - - openvdb::Coord ijk; - openvdb::Vec3d pos, color, normal; - openvdb::tree::LeafManager leafs(*mask); - - openvdb::tree::ValueAccessor acc(tree); - - Index64 idx = 0, pt = 0, cc = 0; - for (Index64 l = 0, L = leafs.leafCount(); l < L; ++l) { - typename BoolTreeT::LeafNodeType::ValueOnIter iter = leafs.leaf(l).beginValueOn(); - for (; iter; ++iter) { - ijk = iter.getCoord(); - ValueType vec = acc.getValue(ijk); - - pos = grid->indexToWorld(ijk); - - points[idx++] = static_cast(pos[0]); - points[idx++] = static_cast(pos[1]); - points[idx++] = static_cast(pos[2]); - - indices[pt] = GLuint(pt); - ++pt; - indices[pt] = GLuint(pt); - - ++pt; - double w = vec.length() / length; - vec.normalize(); - pos += grid->voxelSize()[0] * 0.9 * vec; - - points[idx++] = static_cast(pos[0]); - points[idx++] = static_cast(pos[1]); - points[idx++] = static_cast(pos[2]); - - - color = w * openvdb::Vec3d(0.9, 0.3, 0.3) - + (1.0 - w) * openvdb::Vec3d(0.3, 0.3, 0.9); - - colors[cc++] = static_cast(color[0] * 0.3); - colors[cc++] = static_cast(color[1] * 0.3); - colors[cc++] = static_cast(color[2] * 0.3); - - colors[cc++] = static_cast(color[0]); - colors[cc++] = static_cast(color[1]); - colors[cc++] = static_cast(color[2]); - } - } - - mVectorBuffer->genVertexBuffer(points); - mVectorBuffer->genColorBuffer(colors); - mVectorBuffer->genIndexBuffer(indices, GL_LINES); - } - -private: - BufferObject *mVectorBuffer; - -}; // ActiveVectorValuesOp - - -//////////////////////////////////////// - -// Active value render module - -ActiveValueModule::ActiveValueModule(const openvdb::GridBase::ConstPtr& grid): - mGrid(grid), - mIsInitialized(false) -{ - mFlatShader.setVertShader( - "#version 120\n" - "void main() {\n" - "gl_FrontColor = gl_Color;\n" - "gl_Position = ftransform();\n" - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" - "}\n"); - - mFlatShader.setFragShader( - "#version 120\n" - "void main() {\n" - "gl_FragColor = gl_Color;}\n"); - - mFlatShader.build(); - - mSurfaceShader.setVertShader( - "#version 120\n" - "varying vec3 normal;\n" - "void main() {\n" - "gl_FrontColor = gl_Color;\n" - "normal = normalize(gl_NormalMatrix * gl_Normal);\n" - "gl_Position = ftransform();\n" - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" - "}\n"); - - - mSurfaceShader.setFragShader( - "#version 120\n" - "varying vec3 normal;\n" - "void main() {\n" - "vec3 normalized_normal = normalize(normal);\n" - "float w = 0.5 * (1.0 + dot(normalized_normal, vec3(0.0, 1.0, 0.0)));\n" - "vec4 diffuseColor = w * gl_Color + (1.0 - w) * (gl_Color * 0.3);\n" - "gl_FragColor = diffuseColor;\n" - "}\n"); - - mSurfaceShader.build(); -} - - -void -ActiveValueModule::init() -{ - mIsInitialized = true; - - ActiveScalarValuesOp drawScalars(mInteriorBuffer, mSurfaceBuffer); - - if (!util::processTypedScalarGrid(mGrid, drawScalars)) { - - ActiveVectorValuesOp drawVectors(mVectorBuffer); - - if(!util::processTypedVectorGrid(mGrid, drawVectors)) { - OPENVDB_LOG_INFO("Ignoring unrecognized grid type" - " during active value module initialization."); - } - } -} - - -void -ActiveValueModule::render() -{ - if (!mIsVisible) return; - if (!mIsInitialized) init(); - - mFlatShader.startShading(); - mInteriorBuffer.render(); - mVectorBuffer.render(); - mFlatShader.stopShading(); - - mSurfaceShader.startShading(); - mSurfaceBuffer.render(); - mSurfaceShader.stopShading(); -} - - -//////////////////////////////////////// - - -class MeshOp -{ -public: - MeshOp(BufferObject& buffer) : mBuffer(&buffer) {} - - template - void operator()(typename GridType::ConstPtr grid) - { - using openvdb::Index64; - - openvdb::tools::VolumeToMesh mesher( - grid->getGridClass() == openvdb::GRID_LEVEL_SET ? 0.0 : 0.01); - mesher(*grid); - - // Copy points and generate point normals. - std::vector points(mesher.pointListSize() * 3); - std::vector normals(mesher.pointListSize() * 3); - - openvdb::tree::ValueAccessor acc(grid->tree()); - openvdb::math::GenericMap map(grid->transform()); - openvdb::Coord ijk; - - for (Index64 n = 0, i = 0, N = mesher.pointListSize(); n < N; ++n) { - const openvdb::Vec3s& p = mesher.pointList()[n]; - points[i++] = p[0]; - points[i++] = p[1]; - points[i++] = p[2]; - } - - // Copy primitives - openvdb::tools::PolygonPoolList& polygonPoolList = mesher.polygonPoolList(); - Index64 numQuads = 0; - for (Index64 n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) { - numQuads += polygonPoolList[n].numQuads(); - } - - std::vector indices; - indices.reserve(numQuads * 4); - openvdb::Vec3d normal, e1, e2; - - for (Index64 n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) { - const openvdb::tools::PolygonPool& polygons = polygonPoolList[n]; - for (Index64 i = 0, I = polygons.numQuads(); i < I; ++i) { - const openvdb::Vec4I& quad = polygons.quad(i); - indices.push_back(quad[0]); - indices.push_back(quad[1]); - indices.push_back(quad[2]); - indices.push_back(quad[3]); - - e1 = mesher.pointList()[quad[1]]; - e1 -= mesher.pointList()[quad[0]]; - e2 = mesher.pointList()[quad[2]]; - e2 -= mesher.pointList()[quad[1]]; - normal = e1.cross(e2); - - const double length = normal.length(); - if (length > 1.0e-7) normal *= (1.0 / length); - - for (Index64 v = 0; v < 4; ++v) { - normals[quad[v]*3] = static_cast(-normal[0]); - normals[quad[v]*3+1] = static_cast(-normal[1]); - normals[quad[v]*3+2] = static_cast(-normal[2]); - } - } - } - - // Construct and transfer GPU buffers. - mBuffer->genVertexBuffer(points); - mBuffer->genNormalBuffer(normals); - mBuffer->genIndexBuffer(indices, GL_QUADS); - } - -private: - BufferObject *mBuffer; - - static openvdb::Vec3s sNodeColors[]; - -}; // MeshOp - - -//////////////////////////////////////// - -// Meshing module - -MeshModule::MeshModule(const openvdb::GridBase::ConstPtr& grid): - mGrid(grid), - mIsInitialized(false) -{ - mShader.setVertShader( - "#version 120\n" - "varying vec3 normal;\n" - "void main() {\n" - "normal = normalize(gl_NormalMatrix * gl_Normal);\n" - "gl_Position = ftransform();\n" - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" - "}\n"); - - mShader.setFragShader( - "#version 120\n" - "varying vec3 normal;\n" - "const vec4 skyColor = vec4(0.9, 0.9, 1.0, 1.0);\n" - "const vec4 groundColor = vec4(0.3, 0.3, 0.2, 1.0);\n" - "void main() {\n" - "vec3 normalized_normal = normalize(normal);\n" - "float w = 0.5 * (1.0 + dot(normalized_normal, vec3(0.0, 1.0, 0.0)));\n" - "vec4 diffuseColor = w * skyColor + (1.0 - w) * groundColor;\n" - "gl_FragColor = diffuseColor;\n" - "}\n"); - - mShader.build(); -} - - -void -MeshModule::init() -{ - mIsInitialized = true; - - MeshOp drawMesh(mBufferObject); - - if (!util::processTypedScalarGrid(mGrid, drawMesh)) { - OPENVDB_LOG_INFO( - "Ignoring non-scalar grid type during mesh module initialization."); - } -} - - -void -MeshModule::render() -{ - if (!mIsVisible) return; - if (!mIsInitialized) init(); - - mShader.startShading(); - - mBufferObject.render(); - - mShader.stopShading(); -} - -} // namespace openvdb_viewer - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/RenderModules.h b/openvdb_3_0_0_library/viewer/RenderModules.h deleted file mode 100755 index 39e26e1..0000000 --- a/openvdb_3_0_0_library/viewer/RenderModules.h +++ /dev/null @@ -1,214 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_VIEWER_RENDERMODULES_HAS_BEEN_INCLUDED -#define OPENVDB_VIEWER_RENDERMODULES_HAS_BEEN_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(__APPLE__) || defined(MACOSX) -#include -#include -#else -#include -#include -#endif - - -namespace openvdb_viewer { - -// OpenGL helper objects - -class BufferObject -{ -public: - BufferObject(); - ~BufferObject(); - - void render() const; - - /// @note accepted @c primType: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, - /// GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, - /// GL_QUAD_STRIP, GL_QUADS and GL_POLYGON - void genIndexBuffer(const std::vector&, GLenum primType); - - void genVertexBuffer(const std::vector&); - void genNormalBuffer(const std::vector&); - void genColorBuffer(const std::vector&); - - void clear(); - -private: - GLuint mVertexBuffer, mNormalBuffer, mIndexBuffer, mColorBuffer; - GLenum mPrimType; - GLsizei mPrimNum; -}; - - -class ShaderProgram -{ -public: - ShaderProgram(); - ~ShaderProgram(); - - void setVertShader(const std::string&); - void setFragShader(const std::string&); - - void build(); - void build(const std::vector& attributes); - - void startShading() const; - void stopShading() const; - - void clear(); - -private: - GLuint mProgram, mVertShader, mFragShader; -}; - - -//////////////////////////////////////// - - -/// @brief interface class -class RenderModule -{ -public: - virtual ~RenderModule() {} - - virtual void render() = 0; - - bool visible() { return mIsVisible; } - void setVisible(bool b) { mIsVisible = b; } - -protected: - RenderModule(): mIsVisible(true) {} - - bool mIsVisible; -}; - - -//////////////////////////////////////// - - -/// @brief Basic render module, axis gnomon and ground plane. -class ViewportModule: public RenderModule -{ -public: - ViewportModule(); - virtual ~ViewportModule() {} - - virtual void render(); - -private: - float mAxisGnomonScale, mGroundPlaneScale; -}; - - -//////////////////////////////////////// - - -/// @brief Tree topology render module -class TreeTopologyModule: public RenderModule -{ -public: - TreeTopologyModule(const openvdb::GridBase::ConstPtr&); - virtual ~TreeTopologyModule() {} - - virtual void render(); - -private: - void init(); - - const openvdb::GridBase::ConstPtr& mGrid; - BufferObject mBufferObject; - bool mIsInitialized; - ShaderProgram mShader; -}; - - -//////////////////////////////////////// - - -/// @brief Tree topology render module -class ActiveValueModule: public RenderModule -{ -public: - ActiveValueModule(const openvdb::GridBase::ConstPtr&); - virtual ~ActiveValueModule() {} - - virtual void render(); - -private: - void init(); - - const openvdb::GridBase::ConstPtr& mGrid; - BufferObject mInteriorBuffer, mSurfaceBuffer, mVectorBuffer; - bool mIsInitialized; - ShaderProgram mFlatShader, mSurfaceShader; -}; - - -//////////////////////////////////////// - - -/// @brief Surfacing render module -class MeshModule: public RenderModule -{ -public: - MeshModule(const openvdb::GridBase::ConstPtr&); - virtual ~MeshModule() {} - - virtual void render(); - -private: - void init(); - - const openvdb::GridBase::ConstPtr& mGrid; - BufferObject mBufferObject; - bool mIsInitialized; - ShaderProgram mShader; -}; - -} // namespace openvdb_viewer - -#endif // OPENVDB_VIEWER_RENDERMODULES_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Viewer.cc b/openvdb_3_0_0_library/viewer/Viewer.cc deleted file mode 100755 index a67847e..0000000 --- a/openvdb_3_0_0_library/viewer/Viewer.cc +++ /dev/null @@ -1,1231 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#include "Viewer.h" - -#include "Camera.h" -#include "ClipBox.h" -#include "Font.h" -#include "RenderModules.h" -#include // for formattedInt() -#include -#include // for OPENVDB_LIBRARY_MAJOR_VERSION, etc. -#include -#include -#include // for fabs() -#include // for std::setprecision() -#include -#include -#include -#include -#include -#include // for nanosleep() - -#ifdef OPENVDB_USE_GLFW_3 -//#define GLFW_INCLUDE_GLU -#include -#else // if !defined(OPENVDB_USE_GLFW_3) -#if defined(__APPLE__) || defined(MACOSX) -#include -#include -#else -#include -#include -#endif -#include -#endif // !defined(OPENVDB_USE_GLFW_3) - - -namespace openvdb_viewer { - -class ViewerImpl -{ -public: - typedef boost::shared_ptr CameraPtr; - typedef boost::shared_ptr ClipBoxPtr; - typedef boost::shared_ptr RenderModulePtr; - - ViewerImpl(); - - void init(const std::string& progName); - - std::string getVersionString() const; - - bool isOpen() const; - bool open(int width = 900, int height = 800); - void view(const openvdb::GridCPtrVec&); - void handleEvents(); - void close(); - - void resize(int width, int height); - - void showPrevGrid(); - void showNextGrid(); - - bool needsDisplay(); - void setNeedsDisplay(); - - void toggleRenderModule(size_t n); - void toggleInfoText(); - - // Internal - void render(); - void interrupt(); - void setWindowTitle(double fps = 0.0); - void showNthGrid(size_t n); - void updateCutPlanes(int wheelPos); - void swapBuffers(); - - void keyCallback(int key, int action); - void mouseButtonCallback(int button, int action); - void mousePosCallback(int x, int y); - void mouseWheelCallback(int pos); - void windowSizeCallback(int width, int height); - void windowRefreshCallback(); - - static openvdb::BBoxd worldSpaceBBox(const openvdb::math::Transform&, - const openvdb::CoordBBox&); - static void sleep(double seconds); - -private: - bool mDidInit; - CameraPtr mCamera; - ClipBoxPtr mClipBox; - RenderModulePtr mViewportModule; - std::vector mRenderModules; - openvdb::GridCPtrVec mGrids; - size_t mGridIdx, mUpdates; - std::string mGridName, mProgName, mGridInfo, mTransformInfo, mTreeInfo; - int mWheelPos; - bool mShiftIsDown, mCtrlIsDown, mShowInfo; - bool mInterrupt; - int mWinWidth, mWinHeight; -#if GLFW_VERSION_MAJOR >= 3 - GLFWwindow* mWindow; -#endif -}; // class ViewerImpl - - -class ThreadManager -{ -public: - ThreadManager(); - - void view(const openvdb::GridCPtrVec& gridList); - void close(); - void resize(int width, int height); - -private: - void doView(); - static void* doViewTask(void* arg); - - tbb::atomic mRedisplay; - bool mClose, mHasThread; - boost::thread mThread; - openvdb::GridCPtrVec mGrids; -}; - - -//////////////////////////////////////// - - -namespace { - -ViewerImpl* sViewer = NULL; -ThreadManager* sThreadMgr = NULL; -tbb::mutex sLock; - - -#if GLFW_VERSION_MAJOR >= 3 -void -keyCB(GLFWwindow*, int key, int /*scancode*/, int action, int /*modifiers*/) -#else -void -keyCB(int key, int action) -#endif -{ - if (sViewer) sViewer->keyCallback(key, action); -} - - -#if GLFW_VERSION_MAJOR >= 3 -void -mouseButtonCB(GLFWwindow*, int button, int action, int /*modifiers*/) -#else -void -mouseButtonCB(int button, int action) -#endif -{ - if (sViewer) sViewer->mouseButtonCallback(button, action); -} - - -#if GLFW_VERSION_MAJOR >= 3 -void -mousePosCB(GLFWwindow*, double x, double y) -{ - if (sViewer) sViewer->mousePosCallback(int(x), int(y)); -} -#else -void -mousePosCB(int x, int y) -{ - if (sViewer) sViewer->mousePosCallback(x, y); -} -#endif - - -#if GLFW_VERSION_MAJOR >= 3 -void -mouseWheelCB(GLFWwindow*, double /*xoffset*/, double yoffset) -{ - if (sViewer) sViewer->mouseWheelCallback(int(yoffset)); -} -#else -void -mouseWheelCB(int pos) -{ - if (sViewer) sViewer->mouseWheelCallback(pos); -} -#endif - - -#if GLFW_VERSION_MAJOR >= 3 -void -windowSizeCB(GLFWwindow*, int width, int height) -#else -void -windowSizeCB(int width, int height) -#endif -{ - if (sViewer) sViewer->windowSizeCallback(width, height); -} - - -#if GLFW_VERSION_MAJOR >= 3 -void -windowRefreshCB(GLFWwindow*) -#else -void -windowRefreshCB() -#endif -{ - if (sViewer) sViewer->windowRefreshCallback(); -} - -} // unnamed namespace - - -//////////////////////////////////////// - - -Viewer -init(const std::string& progName, bool background) -{ - if (sViewer == NULL) { - tbb::mutex::scoped_lock lock(sLock); - if (sViewer == NULL) { - OPENVDB_START_THREADSAFE_STATIC_WRITE - sViewer = new ViewerImpl; - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - } - } - sViewer->init(progName); - - if (background) { - if (sThreadMgr == NULL) { - tbb::mutex::scoped_lock lock(sLock); - if (sThreadMgr == NULL) { - OPENVDB_START_THREADSAFE_STATIC_WRITE - sThreadMgr = new ThreadManager; - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - } - } - } else { - if (sThreadMgr != NULL) { - tbb::mutex::scoped_lock lock(sLock); - delete sThreadMgr; - OPENVDB_START_THREADSAFE_STATIC_WRITE - sThreadMgr = NULL; - OPENVDB_FINISH_THREADSAFE_STATIC_WRITE - } - } - - return Viewer(); -} - - -void -exit() -{ -#if GLFW_VERSION_MAJOR >= 3 - // Prior to GLFW 3, glfwTerminate() was called automatically from - // an atexit() function installed by glfwInit(), so this was not needed. - // But GLFW 3 does not register an atexit() function. - glfwTerminate(); -#endif -} - - -//////////////////////////////////////// - - -Viewer::Viewer() -{ - OPENVDB_LOG_DEBUG_RUNTIME("constructed Viewer from thread " << boost::this_thread::get_id()); -} - - -void -Viewer::open(int width, int height) -{ - if (sViewer) sViewer->open(width, height); -} - - -void -Viewer::view(const openvdb::GridCPtrVec& grids) -{ - if (sThreadMgr) { - sThreadMgr->view(grids); - } else if (sViewer) { - sViewer->view(grids); - } -} - - -void -Viewer::handleEvents() -{ - if (sViewer) sViewer->handleEvents(); -} - - -void -Viewer::close() -{ - if (sThreadMgr) sThreadMgr->close(); - else if (sViewer) sViewer->close(); -} - - -void -Viewer::resize(int width, int height) -{ - if (sViewer) sViewer->resize(width, height); -} - - -std::string -Viewer::getVersionString() const -{ - std::string version; - if (sViewer) version = sViewer->getVersionString(); - return version; -} - - -//////////////////////////////////////// - - -ThreadManager::ThreadManager() - : mClose(false) - , mHasThread(false) -{ - mRedisplay = false; -} - - -void -ThreadManager::view(const openvdb::GridCPtrVec& gridList) -{ - if (!sViewer) return; - - mGrids = gridList; - mClose = false; - mRedisplay = true; - - if (!mHasThread) { - mThread = boost::thread(doViewTask, this); - mHasThread = true; - } -} - - -void -ThreadManager::close() -{ - if (!sViewer) return; - - // Tell the viewer thread to exit. - mRedisplay = false; - mClose = true; - // Tell the viewer to terminate its event loop. - sViewer->interrupt(); - - if (mHasThread) { - mThread.join(); - mHasThread = false; - } - - // Tell the viewer to close its window. - sViewer->close(); -} - - -void -ThreadManager::doView() -{ - // This function runs in its own thread. - // The mClose and mRedisplay flags are set from the main thread. - while (!mClose) { - if (mRedisplay.compare_and_swap(/*set to*/false, /*if*/true)) { - if (sViewer) sViewer->view(mGrids); - } - sViewer->sleep(0.5/*sec*/); - } -} - - -//static -void* -ThreadManager::doViewTask(void* arg) -{ - if (ThreadManager* self = static_cast(arg)) { - self->doView(); - } - return NULL; -} - - -//////////////////////////////////////// - - -ViewerImpl::ViewerImpl() - : mDidInit(false) - , mCamera(new Camera) - , mClipBox(new ClipBox) - , mGridIdx(0) - , mUpdates(0) - , mWheelPos(0) - , mShiftIsDown(false) - , mCtrlIsDown(false) - , mShowInfo(true) - , mInterrupt(false) -#if GLFW_VERSION_MAJOR >= 3 - , mWindow(NULL) -#endif -{ -} - - -void -ViewerImpl::init(const std::string& progName) -{ - mProgName = progName; - - if (!mDidInit) { -#if GLFW_VERSION_MAJOR >= 3 - struct Local { - static void errorCB(int error, const char* descr) { - OPENVDB_LOG_ERROR("GLFW Error " << error << ": " << descr); - } - }; - glfwSetErrorCallback(Local::errorCB); -#endif - if (glfwInit() == GL_TRUE) { - OPENVDB_LOG_DEBUG_RUNTIME("initialized GLFW from thread " - << boost::this_thread::get_id()); - mDidInit = true; - } else { - OPENVDB_LOG_ERROR("GLFW initialization failed"); - } - } - mViewportModule.reset(new ViewportModule); -} - - -std::string -ViewerImpl::getVersionString() const -{ - std::ostringstream ostr; - - ostr << "OpenVDB: " << - openvdb::OPENVDB_LIBRARY_MAJOR_VERSION << "." << - openvdb::OPENVDB_LIBRARY_MINOR_VERSION << "." << - openvdb::OPENVDB_LIBRARY_PATCH_VERSION; - - int major, minor, rev; - glfwGetVersion(&major, &minor, &rev); - ostr << ", " << "GLFW: " << major << "." << minor << "." << rev; - - if (mDidInit) { - ostr << ", " << "OpenGL: "; -#if GLFW_VERSION_MAJOR >= 3 - boost::shared_ptr wPtr; - GLFWwindow* w = mWindow; - if (!w) { - wPtr.reset(glfwCreateWindow(100, 100, "", NULL, NULL), &glfwDestroyWindow); - w = wPtr.get(); - } - if (w) { - ostr << glfwGetWindowAttrib(w, GLFW_CONTEXT_VERSION_MAJOR) << "." - << glfwGetWindowAttrib(w, GLFW_CONTEXT_VERSION_MINOR) << "." - << glfwGetWindowAttrib(w, GLFW_CONTEXT_REVISION); - } -#else - if (!glfwGetWindowParam(GLFW_OPENED)) { - if (glfwOpenWindow(100, 100, 8, 8, 8, 8, 24, 0, GLFW_WINDOW)) { - ostr << glGetString(GL_VERSION); - glfwCloseWindow(); - } - } else { - ostr << glGetString(GL_VERSION); - } -#endif - } - return ostr.str(); -} - - -#if GLFW_VERSION_MAJOR >= 3 -bool -ViewerImpl::open(int width, int height) -{ - if (mWindow == NULL) { - glfwWindowHint(GLFW_RED_BITS, 8); - glfwWindowHint(GLFW_GREEN_BITS, 8); - glfwWindowHint(GLFW_BLUE_BITS, 8); - glfwWindowHint(GLFW_ALPHA_BITS, 8); - glfwWindowHint(GLFW_DEPTH_BITS, 32); - glfwWindowHint(GLFW_STENCIL_BITS, 0); - - mWindow = glfwCreateWindow( - width, height, mProgName.c_str(), /*monitor=*/NULL, /*share=*/NULL); - - OPENVDB_LOG_DEBUG_RUNTIME("created window " << std::hex << mWindow << std::dec - << " from thread " << boost::this_thread::get_id()); - - if (mWindow != NULL) { - // Temporarily make the new window the current context, then create a font. - boost::shared_ptr curWindow( - glfwGetCurrentContext(), glfwMakeContextCurrent); - glfwMakeContextCurrent(mWindow); - BitmapFont13::initialize(); - } - } - mCamera->setWindow(mWindow); - - if (mWindow != NULL) { - glfwSetKeyCallback(mWindow, keyCB); - glfwSetMouseButtonCallback(mWindow, mouseButtonCB); - glfwSetCursorPosCallback(mWindow, mousePosCB); - glfwSetScrollCallback(mWindow, mouseWheelCB); - glfwSetWindowSizeCallback(mWindow, windowSizeCB); - glfwSetWindowRefreshCallback(mWindow, windowRefreshCB); - } - return (mWindow != NULL); -} -#else // if GLFW_VERSION_MAJOR <= 2 -bool -ViewerImpl::open(int width, int height) -{ - if (!glfwGetWindowParam(GLFW_OPENED)) { - if (!glfwOpenWindow(width, height, - 8, 8, 8, 8, // # of R,G,B, & A bits - 32, 0, // # of depth & stencil buffer bits - GLFW_WINDOW)) // either GLFW_WINDOW or GLFW_FULLSCREEN - { - return false; - } - } - glfwSetWindowTitle(mProgName.c_str()); - - BitmapFont13::initialize(); - - glfwSetKeyCallback(keyCB); - glfwSetMouseButtonCallback(mouseButtonCB); - glfwSetMousePosCallback(mousePosCB); - glfwSetMouseWheelCallback(mouseWheelCB); - glfwSetWindowSizeCallback(windowSizeCB); - glfwSetWindowRefreshCallback(windowRefreshCB); - - return true; -} -#endif - - -bool -ViewerImpl::isOpen() const -{ -#if GLFW_VERSION_MAJOR >= 3 - return (mWindow != NULL); -#else - return glfwGetWindowParam(GLFW_OPENED); -#endif -} - - -// Set a flag so as to break out of the event loop on the next iteration. -// (Useful only if the event loop is running in a separate thread.) -void -ViewerImpl::interrupt() -{ - mInterrupt = true; -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow) glfwSetWindowShouldClose(mWindow, true); -#endif -} - - -void -ViewerImpl::handleEvents() -{ -#if GLFW_VERSION_MAJOR >= 3 - glfwPollEvents(); -#endif -} - - -void -ViewerImpl::close() -{ -#if GLFW_VERSION_MAJOR >= 3 - OPENVDB_LOG_DEBUG_RUNTIME("about to close window " << std::hex << mWindow << std::dec - << " from thread " << boost::this_thread::get_id()); -#else - OPENVDB_LOG_DEBUG_RUNTIME("about to close window from thread " - << boost::this_thread::get_id()); -#endif - - mViewportModule.reset(); - mRenderModules.clear(); -#if GLFW_VERSION_MAJOR >= 3 - mCamera->setWindow(NULL); - GLFWwindow* win = mWindow; - mWindow = NULL; - glfwDestroyWindow(win); - OPENVDB_LOG_DEBUG_RUNTIME("destroyed window " << std::hex << win << std::dec - << " from thread " << boost::this_thread::get_id()); -#else - glfwCloseWindow(); -#endif -} - - -//////////////////////////////////////// - - -void -ViewerImpl::view(const openvdb::GridCPtrVec& gridList) -{ - if (!isOpen()) return; - - mGrids = gridList; - mGridIdx = size_t(-1); - mGridName.clear(); - - // Compute the combined bounding box of all the grids. - openvdb::BBoxd bbox(openvdb::Vec3d(0.0), openvdb::Vec3d(0.0)); - if (!gridList.empty()) { - bbox = worldSpaceBBox( - gridList[0]->transform(), gridList[0]->evalActiveVoxelBoundingBox()); - openvdb::Vec3d voxelSize = gridList[0]->voxelSize(); - - for (size_t n = 1; n < gridList.size(); ++n) { - bbox.expand(worldSpaceBBox(gridList[n]->transform(), - gridList[n]->evalActiveVoxelBoundingBox())); - - voxelSize = minComponent(voxelSize, gridList[n]->voxelSize()); - } - mClipBox->setStepSize(voxelSize); - } - mClipBox->setBBox(bbox); - -#if GLFW_VERSION_MAJOR >= 3 - // Prepare window for rendering. - glfwMakeContextCurrent(mWindow); -#endif - - { - // set up camera - openvdb::Vec3d extents = bbox.extents(); - double maxExtent = std::max(extents[0], std::max(extents[1], extents[2])); - mCamera->setTarget(bbox.getCenter(), maxExtent); - mCamera->lookAtTarget(); - mCamera->setSpeed(); - } - - swapBuffers(); - setNeedsDisplay(); - - - ////////// - - // Screen color - glClearColor(0.85f, 0.85f, 0.85f, 0.0f); - - glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_TEST); - glShadeModel(GL_SMOOTH); - - glPointSize(4); - glLineWidth(2); - ////////// - - // construct render modules - showNthGrid(/*n=*/0); - - - // main loop - - size_t frame = 0; - double time = glfwGetTime(); - - glfwSwapInterval(1); - -#if GLFW_VERSION_MAJOR >= 3 - OPENVDB_LOG_DEBUG_RUNTIME("starting to render in window " << std::hex << mWindow << std::dec - << " from thread " << boost::this_thread::get_id()); -#else - OPENVDB_LOG_DEBUG_RUNTIME("starting to render from thread " << boost::this_thread::get_id()); -#endif - - mInterrupt = false; - for (bool stop = false; !stop; ) { - if (needsDisplay()) render(); - - // eval fps - ++frame; - double elapsed = glfwGetTime() - time; - if (elapsed > 1.0) { - time = glfwGetTime(); - setWindowTitle(/*fps=*/double(frame) / elapsed); - frame = 0; - } - - // Swap front and back buffers - swapBuffers(); - - sleep(0.01/*sec*/); - - // Exit if the Esc key is pressed or the window is closed. -#if GLFW_VERSION_MAJOR >= 3 - handleEvents(); - stop = (mInterrupt || glfwWindowShouldClose(mWindow)); -#else - stop = (mInterrupt || glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)); -#endif - } - -#if GLFW_VERSION_MAJOR >= 3 - if (glfwGetCurrentContext() == mWindow) { ///< @todo not thread-safe - // Detach this viewer's GL context. - glfwMakeContextCurrent(NULL); - OPENVDB_LOG_DEBUG_RUNTIME("detached window " << std::hex << mWindow << std::dec - << " from thread " << boost::this_thread::get_id()); - } -#endif - -#if GLFW_VERSION_MAJOR >= 3 - OPENVDB_LOG_DEBUG_RUNTIME("finished rendering in window " << std::hex << mWindow << std::dec - << " from thread " << boost::this_thread::get_id()); -#else - OPENVDB_LOG_DEBUG_RUNTIME("finished rendering from thread " << boost::this_thread::get_id()); -#endif -} - - -//////////////////////////////////////// - - -void -ViewerImpl::resize(int width, int height) -{ -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow) glfwSetWindowSize(mWindow, width, height); -#else - glfwSetWindowSize(width, height); -#endif -} - - -//////////////////////////////////////// - - -void -ViewerImpl::render() -{ -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow == NULL) return; - - // Prepare window for rendering. - glfwMakeContextCurrent(mWindow); -#endif - - mCamera->aim(); - - // draw scene - mViewportModule->render(); // ground plane. - - mClipBox->render(); - mClipBox->enableClipping(); - - for (size_t n = 0, N = mRenderModules.size(); n < N; ++n) { - mRenderModules[n]->render(); - } - - mClipBox->disableClipping(); - - // Render text - - if (mShowInfo) { - BitmapFont13::enableFontRendering(); - - glColor3d(0.2, 0.2, 0.2); - - int width, height; -#if GLFW_VERSION_MAJOR >= 3 - glfwGetWindowSize(mWindow, &width, &height); -#else - glfwGetWindowSize(&width, &height); -#endif - - BitmapFont13::print(10, height - 13 - 10, mGridInfo); - BitmapFont13::print(10, height - 13 - 30, mTransformInfo); - BitmapFont13::print(10, height - 13 - 50, mTreeInfo); - - BitmapFont13::disableFontRendering(); - } -} - - -//////////////////////////////////////// - - -//static -void -ViewerImpl::sleep(double secs) -{ - secs = fabs(secs); - int isecs = int(secs); - struct timespec sleepTime = { isecs /*sec*/, int(1.0e9 * (secs - isecs)) /*nsec*/ }; - nanosleep(&sleepTime, /*remainingTime=*/NULL); -} - - -//////////////////////////////////////// - - -//static -openvdb::BBoxd -ViewerImpl::worldSpaceBBox(const openvdb::math::Transform& xform, const openvdb::CoordBBox& bbox) -{ - openvdb::Vec3d pMin = openvdb::Vec3d(std::numeric_limits::max()); - openvdb::Vec3d pMax = -pMin; - - const openvdb::Coord& min = bbox.min(); - const openvdb::Coord& max = bbox.max(); - openvdb::Coord ijk; - - // corner 1 - openvdb::Vec3d ptn = xform.indexToWorld(min); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 2 - ijk[0] = min.x(); - ijk[1] = min.y(); - ijk[2] = max.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 3 - ijk[0] = max.x(); - ijk[1] = min.y(); - ijk[2] = max.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 4 - ijk[0] = max.x(); - ijk[1] = min.y(); - ijk[2] = min.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 5 - ijk[0] = min.x(); - ijk[1] = max.y(); - ijk[2] = min.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 6 - ijk[0] = min.x(); - ijk[1] = max.y(); - ijk[2] = max.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - - // corner 7 - ptn = xform.indexToWorld(max); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - // corner 8 - ijk[0] = max.x(); - ijk[1] = max.y(); - ijk[2] = min.z(); - ptn = xform.indexToWorld(ijk); - for (int i = 0; i < 3; ++i) { - if (ptn[i] < pMin[i]) pMin[i] = ptn[i]; - if (ptn[i] > pMax[i]) pMax[i] = ptn[i]; - } - - return openvdb::BBoxd(pMin, pMax); -} - - -//////////////////////////////////////// - - -void -ViewerImpl::updateCutPlanes(int wheelPos) -{ - double speed = std::abs(mWheelPos - wheelPos); - if (mWheelPos < wheelPos) mClipBox->update(speed); - else mClipBox->update(-speed); - setNeedsDisplay(); -} - - -//////////////////////////////////////// - - -void -ViewerImpl::swapBuffers() -{ -#if GLFW_VERSION_MAJOR >= 3 - glfwSwapBuffers(mWindow); -#else - glfwSwapBuffers(); -#endif -} - - -//////////////////////////////////////// - - -void -ViewerImpl::setWindowTitle(double fps) -{ - std::ostringstream ss; - ss << mProgName << ": " - << (mGridName.empty() ? std::string("OpenVDB") : mGridName) - << " (" << (mGridIdx + 1) << " of " << mGrids.size() << ") @ " - << std::setprecision(1) << std::fixed << fps << " fps"; -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow) glfwSetWindowTitle(mWindow, ss.str().c_str()); -#else - glfwSetWindowTitle(ss.str().c_str()); -#endif -} - - -//////////////////////////////////////// - - -void -ViewerImpl::showPrevGrid() -{ - if (const size_t numGrids = mGrids.size()) { - size_t idx = ((numGrids + mGridIdx) - 1) % numGrids; - showNthGrid(idx); - } -} - - -void -ViewerImpl::showNextGrid() -{ - if (const size_t numGrids = mGrids.size()) { - size_t idx = (mGridIdx + 1) % numGrids; - showNthGrid(idx); - } -} - - -void -ViewerImpl::showNthGrid(size_t n) -{ - if (mGrids.empty()) return; - n = n % mGrids.size(); - if (n == mGridIdx) return; - - mGridName = mGrids[n]->getName(); - mGridIdx = n; - - // save render settings - std::vector active(mRenderModules.size()); - for (size_t i = 0, I = active.size(); i < I; ++i) { - active[i] = mRenderModules[i]->visible(); - } - - mRenderModules.clear(); - mRenderModules.push_back(RenderModulePtr(new TreeTopologyModule(mGrids[n]))); - mRenderModules.push_back(RenderModulePtr(new MeshModule(mGrids[n]))); - mRenderModules.push_back(RenderModulePtr(new ActiveValueModule(mGrids[n]))); - - if (active.empty()) { - for (size_t i = 1, I = mRenderModules.size(); i < I; ++i) { - mRenderModules[i]->setVisible(false); - } - } else { - for (size_t i = 0, I = active.size(); i < I; ++i) { - mRenderModules[i]->setVisible(active[i]); - } - } - - // Collect info - { - std::ostringstream ostrm; - std::string s = mGrids[n]->getName(); - const openvdb::GridClass cls = mGrids[n]->getGridClass(); - if (!s.empty()) ostrm << s << " / "; - ostrm << mGrids[n]->valueType() << " / "; - if (cls == openvdb::GRID_UNKNOWN) ostrm << " class unknown"; - else ostrm << " " << openvdb::GridBase::gridClassToString(cls); - mGridInfo = ostrm.str(); - } - { - openvdb::Coord dim = mGrids[n]->evalActiveVoxelDim(); - std::ostringstream ostrm; - ostrm << dim[0] << " x " << dim[1] << " x " << dim[2] - << " / voxel size " << std::setprecision(4) << mGrids[n]->voxelSize()[0] - << " (" << mGrids[n]->transform().mapType() << ")"; - mTransformInfo = ostrm.str(); - } - { - std::ostringstream ostrm; - const openvdb::Index64 count = mGrids[n]->activeVoxelCount(); - ostrm << openvdb::util::formattedInt(count) - << " active voxel" << (count == 1 ? "" : "s"); - mTreeInfo = ostrm.str(); - } - - setWindowTitle(); -} - - -//////////////////////////////////////// - - -void -ViewerImpl::keyCallback(int key, int action) -{ - mCamera->keyCallback(key, action); - -#if GLFW_VERSION_MAJOR >= 3 - if (mWindow == NULL) return; - const bool keyPress = (glfwGetKey(mWindow, key) == GLFW_PRESS); - /// @todo Should use "modifiers" argument to keyCB(). - mShiftIsDown = glfwGetKey(mWindow, GLFW_KEY_LEFT_SHIFT); - mCtrlIsDown = glfwGetKey(mWindow, GLFW_KEY_LEFT_CONTROL); -#else - const bool keyPress = glfwGetKey(key) == GLFW_PRESS; - mShiftIsDown = glfwGetKey(GLFW_KEY_LSHIFT); - mCtrlIsDown = glfwGetKey(GLFW_KEY_LCTRL); -#endif - - if (keyPress) { - switch (key) { - case '1': - toggleRenderModule(0); - break; - case '2': - toggleRenderModule(1); - break; - case '3': - toggleRenderModule(2); - break; - case 'c': case 'C': - mClipBox->reset(); - break; - case 'h': case 'H': // center home - mCamera->lookAt(openvdb::Vec3d(0.0), 10.0); - break; - case 'g': case 'G': // center geometry - mCamera->lookAtTarget(); - break; - case 'i': case 'I': - toggleInfoText(); - break; - case GLFW_KEY_LEFT: - showPrevGrid(); - break; - case GLFW_KEY_RIGHT: - showNextGrid(); - break; -#if GLFW_VERSION_MAJOR >= 3 - case GLFW_KEY_ESCAPE: - glfwSetWindowShouldClose(mWindow, true); - break; -#endif - } - } - - switch (key) { - case 'x': case 'X': - mClipBox->activateXPlanes() = keyPress; - break; - case 'y': case 'Y': - mClipBox->activateYPlanes() = keyPress; - break; - case 'z': case 'Z': - mClipBox->activateZPlanes() = keyPress; - break; - } - - mClipBox->shiftIsDown() = mShiftIsDown; - mClipBox->ctrlIsDown() = mCtrlIsDown; - - setNeedsDisplay(); -} - - -void -ViewerImpl::mouseButtonCallback(int button, int action) -{ - mCamera->mouseButtonCallback(button, action); - mClipBox->mouseButtonCallback(button, action); - if (mCamera->needsDisplay()) setNeedsDisplay(); -} - - -void -ViewerImpl::mousePosCallback(int x, int y) -{ - bool handled = mClipBox->mousePosCallback(x, y); - if (!handled) mCamera->mousePosCallback(x, y); - if (mCamera->needsDisplay()) setNeedsDisplay(); -} - - -void -ViewerImpl::mouseWheelCallback(int pos) -{ -#if GLFW_VERSION_MAJOR >= 3 - pos += mWheelPos; -#endif - if (mClipBox->isActive()) { - updateCutPlanes(pos); - } else { - mCamera->mouseWheelCallback(pos, mWheelPos); - if (mCamera->needsDisplay()) setNeedsDisplay(); - } - - mWheelPos = pos; -} - - -void -ViewerImpl::windowSizeCallback(int, int) -{ - setNeedsDisplay(); -} - - -void -ViewerImpl::windowRefreshCallback() -{ - setNeedsDisplay(); -} - - -//////////////////////////////////////// - - -bool -ViewerImpl::needsDisplay() -{ - if (mUpdates < 2) { - mUpdates += 1; - return true; - } - return false; -} - - -void -ViewerImpl::setNeedsDisplay() -{ - mUpdates = 0; -} - - -void -ViewerImpl::toggleRenderModule(size_t n) -{ - mRenderModules[n]->setVisible(!mRenderModules[n]->visible()); -} - - -void -ViewerImpl::toggleInfoText() -{ - mShowInfo = !mShowInfo; -} - -} // namespace openvdb_viewer - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) diff --git a/openvdb_3_0_0_library/viewer/Viewer.h b/openvdb_3_0_0_library/viewer/Viewer.h deleted file mode 100755 index f272adb..0000000 --- a/openvdb_3_0_0_library/viewer/Viewer.h +++ /dev/null @@ -1,93 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -// -// Redistributions of source code must retain the above copyright -// and license notice and the following restrictions and disclaimer. -// -// * Neither the name of DreamWorks Animation nor the names of -// its contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE -// LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef OPENVDB_VIEWER_VIEWER_HAS_BEEN_INCLUDED -#define OPENVDB_VIEWER_VIEWER_HAS_BEEN_INCLUDED - -#include -#include - - -namespace openvdb_viewer { - -class Viewer; - -enum { DEFAULT_WIDTH = 900, DEFAULT_HEIGHT = 800 }; - - -/// @brief Initialize and return a viewer. -/// @param progName the name of the calling program (for use in info displays) -/// @param background if true, run the viewer in a separate thread -/// @note Currently, the viewer window is a singleton (but that might change -/// in the future), so although this function returns a new Viewer instance -/// on each call, all instances are associated with the same window. -Viewer init(const std::string& progName, bool background); - -/// @brief Destroy all viewer windows and release resources. -/// @details This should be called from the main thread before your program exits. -void exit(); - - -/// Manager for a window that displays OpenVDB grids -class Viewer -{ -public: - /// Set the size of and open the window associated with this viewer. - void open(int width = DEFAULT_WIDTH, int height = DEFAULT_HEIGHT); - - /// Display the given grids. - void view(const openvdb::GridCPtrVec&); - - /// @brief Process any pending user input (keyboard, mouse, etc.) - /// in the window associated with this viewer. - void handleEvents(); - - /// @brief Close the window associated with this viewer. - /// @warning The window associated with this viewer might be shared with other viewers. - void close(); - - /// Resize the window associated with this viewer. - void resize(int width, int height); - - /// Return a string with version number information. - std::string getVersionString() const; - -private: - friend Viewer init(const std::string&, bool); - Viewer(); -}; - -} // namespace openvdb_viewer - -#endif // OPENVDB_VIEWER_VIEWER_HAS_BEEN_INCLUDED - -// Copyright (c) 2012-2014 DreamWorks Animation LLC -// All rights reserved. This software is distributed under the -// Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )