OpenVDB  12.1.0
PrincipalComponentAnalysis.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @author Richard Jones, Nick Avramoussis
5 ///
6 /// @file PrincipalComponentAnalysis.h
7 ///
8 /// @brief Provides methods to perform principal component analysis (PCA) over
9 /// a point set to compute rotational and affine transformations for each
10 /// point that represent a their neighborhoods anisotropy. The techniques
11 /// and algorithms used here are described in:
12 /// [Reconstructing Surfaces of Particle-Based Fluids Using Anisotropic
13 /// Kernel - Yu Turk 2010].
14 /// The parameters and results of these methods can be combines with the
15 /// ellipsoidal surfacing technique found in PointRasterizeSDF.h.
16 
17 #ifndef OPENVDB_POINTS_POINT_PRINCIPAL_COMPONENT_ANALYSIS_HAS_BEEN_INCLUDED
18 #define OPENVDB_POINTS_POINT_PRINCIPAL_COMPONENT_ANALYSIS_HAS_BEEN_INCLUDED
19 
20 #include <openvdb/openvdb.h>
21 #include <openvdb/Grid.h>
22 #include <openvdb/Types.h>
23 #include <openvdb/math/Coord.h>
24 #include <openvdb/thread/Threading.h>
26 #include <openvdb/util/Assert.h>
31 
32 #include <string>
33 #include <vector>
34 #include <memory>
35 #include <limits>
36 #include <cmath> // std::cbrt
37 
38 namespace openvdb {
40 namespace OPENVDB_VERSION_NAME {
41 namespace points {
42 
43 struct PcaSettings;
44 struct PcaAttributes;
45 
46 /// @brief Calculate ellipsoid transformations from the local point
47 /// distributions as described in Yu and Turk's 'Reconstructing Fluid Surfaces
48 /// with Anisotropic Kernels'. The results are stored on the attributes
49 /// pointed to by the PcaAttributes. See the PcaSettings and PcaAttributes
50 /// structs for more details.
51 /// @warning This method will throw if the 'strech', 'rotation' or 'pws'
52 /// attributes already exist on this input point set.
53 /// @param points The point data grid to analyses
54 /// @param settings The PCA settings for controlling the behavior of the
55 /// neighborhood searches and the resulting ellipsoidal values
56 /// @param attrs The PCA attributes to create
57 template <typename PointDataGridT>
58 inline void
59 pca(PointDataGridT& points,
60  const PcaSettings& settings,
61  const PcaAttributes& attrs);
62 
63 
64 /// @brief Various settings for the neighborhood analysis of point
65 /// distributions.
67 {
68  /// @param searchRadius the world space search radius of the neighborhood
69  /// around each point. Increasing this value will result in points
70  /// including more of their neighbors into their ellipsoidal calculations.
71  /// This may or may not be desirable depending on the point set's
72  /// distribution and can be tweaked as necessary. Note however that large
73  /// values will cause the PCA calculation to become exponentially more
74  /// expensive and should be used in conjunction with the max point per
75  /// voxel settings below.
76  /// @warning Valid range is [0, inf). Behaviour is undefined when outside
77  /// this range.
78  float searchRadius = 1.0f;
79  /// @param allowedAnisotropyRatio the maximum allowed ratio between the
80  /// components in each ellipse' stretch coefficients such that:
81  /// @code
82  /// const auto s = stretch.sorted();
83  /// assert(s[0]/s[2] >= allowedAnisotropyRatio);
84  /// @endcode
85  /// This parameter effectively clamps the allowed anisotropy, with a
86  /// value of 1.0f resulting in uniform stretch values (representing a
87  /// sphere). Values tending towards zero will allow for greater
88  /// anisotropy i.e. much more exaggerated stretches along the computed
89  /// principal axis and corresponding squashes along the others to
90  /// compensate.
91  /// @note Very small values may cause very thing ellipses to be produced,
92  /// so a reasonable minimum should be set. Valid range is (0, 1].
93  /// Behaviour is undefined when outside this range.
94  float allowedAnisotropyRatio = 0.25f;
95  /// @param nonAnisotropicStretch The stretch coefficient that should be
96  /// used for points which have no anisotropic neighbourhood (due to
97  /// being isolated or not having enough neighbours to reach the
98  /// specified @sa neighbourThreshold).
99  float nonAnisotropicStretch = 1.0;
100  /// @param neighbourThreshold number of points in a given neighbourhood
101  /// that target points must have to be classified as having an elliptical
102  /// distribution. Points with less neighbours than this will end up with
103  /// uniform stretch values of nonAnisotropicStretch and an identity
104  /// rotation matrix.
105  /// @note This number can include the target point itself.
106  /// @warning Changing this value does not change the size or number of
107  /// point neighborhood lookups. As such, increasing this value only
108  /// speeds up the number of calculated covariance matrices. Valid range
109  /// is [0, inf], where 0 effectively disables all covariance calculations
110  /// and 1 enables them for every point.
111  size_t neighbourThreshold = 20;
112  /// @param The maximum number of source points to gather for contributions
113  /// to each target point, per voxel. When a voxel contains more points
114  /// than this value, source point are trivially stepped over, with the
115  /// step size calculated as max(1, ppv / neighbourThreshold).
116  /// @note There is no prioritisation of nearest points; for example, voxels
117  /// which partially overlap the search radius may end up selecting point
118  /// ids which all lie outside. This is rarely an issue in practice and
119  /// choosing an appropriate value for this setting can significantly
120  /// increase performance without a large impact to the results.
121  /// @warning Valid range is [1, inf). Behaviour is undefined if this value
122  /// is set to zero.
123  size_t maxSourcePointsPerVoxel = 8;
124  /// @param The maximum number of target points to write anisotropy values
125  /// to. When a voxel contains more points than this value, target point
126  /// are trivially stepped over, with the step size calculated as:
127  /// max(1, ppv / maxTargetPointsPerVoxel).
128  /// default behaviour is to compute for all points. Any points skipped
129  /// will be treated as being isolated and receive an identity rotation
130  /// and nonAnisotropicStretch.
131  /// @note When using in conjuction with rasterizeSdf for ellipsoids,
132  /// consider choosing a lower value (e.g. same value as
133  /// maxSourcePointsPerVoxel) to speed up iterations and only
134  /// increase if necessary.
135  /// @warning Valid range is [1, inf). Behaviour is undefined if this value
136  /// is set to zero.
137  size_t maxTargetPointsPerVoxel = std::numeric_limits<size_t>::max();
138  /// @param averagePositions the amount (between 0 and 1) to average out
139  /// positions. All points, whether they end up as ellipses or not,
140  /// can have their positions smoothed to account for their neighbourhood
141  /// distribution. This will have no effect for points with no neighbours.
142  /// @warning This options does NOT modify the P attribute - instead, a
143  /// world space position attribute "pws" (default) is created and stores
144  /// the smoothed position.
145  /// @warning Valid range is [0, 1]. Behaviour is undefined when outside
146  /// this range.
147  float averagePositions = 1.0f;
148  /// @param interrupter optional interrupter
149  util::NullInterrupter* interrupter = nullptr;
150 };
151 
152 /// @brief The persistent attributes created by the PCA methods.
153 /// @note These can be passed to points::rasterizeSdf with the
154 /// EllipsoidSettings to perform ellipsoidal surface construction.
156 {
157  /// @brief Settings for the "stretch" attribute, a floating point vector
158  /// attribute which represents the scaling components of each points
159  /// ellipse or (1.0,1.0,1.0) for isolated points.
161  std::string stretch = "stretch";
162 
163  /// @brief Settings for the "rotation" attribute, a floating point matrix
164  /// attribute which represents the orthogonal rotation of each points
165  /// ellipse or the identity matrix for isolated points.
167  std::string rotation = "rotation";
168 
169  /// @brief Settings for the world space position of every point. This may
170  /// end up being different to their actual position if the
171  /// PcaSettings::averagePositions value is not exactly 0. This attribute
172  /// is used in place of the point's actual position when calling
173  /// points::rasterizeSdf.
174  /// @note This should always be at least at double precision
176  std::string positionWS = "pws";
177 
178  /// @brief A point group to create that represents points which have valid
179  /// ellipsoidal neighborhood. Points outside of this group will have
180  /// their stretch and rotation attributes set to describe a canonical
181  /// sphere. Note however that all points, regardless of this groups
182  /// membership flag, will still contribute to their neighbours and may
183  /// have their world space position deformed in relation to their
184  /// neighboring points.
185  std::string ellipses = "ellipsoids";
186 };
187 
188 }
189 }
190 }
191 
193 
194 #endif // OPENVDB_POINTS_POINT_PRINCIPAL_COMPONENT_ANALYSIS_HAS_BEEN_INCLUDED
Framework methods for rasterizing PointDataGrid data to Trees.
Point attribute manipulation in a VDB Point Grid.
Point group manipulation in a VDB Point Grid.
Base class for interrupters.
Definition: NullInterrupter.h:25
void pca(PointDataGridT &points, const PcaSettings &settings, const PcaAttributes &attrs)
Calculate ellipsoid transformations from the local point distributions as described in Yu and Turk&#39;s ...
Definition: PrincipalComponentAnalysisImpl.h:548
Various settings for the neighborhood analysis of point distributions.
Definition: PrincipalComponentAnalysis.h:66
Definition: Exceptions.h:13
Definition: Mat.h:165
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
The persistent attributes created by the PCA methods.
Definition: PrincipalComponentAnalysis.h:155
MatType rotation(const Quat< typename MatType::value_type > &q, typename MatType::value_type eps=static_cast< typename MatType::value_type >(1.0e-8))
Return the rotation matrix specified by the given quaternion.
Definition: Mat.h:172
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
3x3 matrix class.
Definition: Mat3.h:28
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218