| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | |||
| 4 | /// @file points/IndexFilter.h | ||
| 5 | /// | ||
| 6 | /// @author Dan Bailey | ||
| 7 | /// | ||
| 8 | /// @brief Index filters primarily designed to be used with a FilterIndexIter. | ||
| 9 | /// | ||
| 10 | /// Filters must adhere to the interface described in the example below: | ||
| 11 | /// @code | ||
| 12 | /// struct MyFilter | ||
| 13 | /// { | ||
| 14 | /// // Return true when the filter has been initialized for first use | ||
| 15 | /// bool initialized() { return true; } | ||
| 16 | /// | ||
| 17 | /// // Return index::ALL if all points are valid, index::NONE if no points are valid | ||
| 18 | /// // and index::PARTIAL if some points are valid | ||
| 19 | /// index::State state() { return index::PARTIAL; } | ||
| 20 | /// | ||
| 21 | /// // Return index::ALL if all points in this leaf are valid, index::NONE if no points | ||
| 22 | /// // in this leaf are valid and index::PARTIAL if some points in this leaf are valid | ||
| 23 | /// template <typename LeafT> | ||
| 24 | /// index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 25 | /// | ||
| 26 | /// // Resets the filter to refer to the specified leaf, all subsequent valid() calls | ||
| 27 | /// // will be relative to this leaf until reset() is called with a different leaf. | ||
| 28 | /// // Although a required method, many filters will provide an empty implementation if | ||
| 29 | /// // there is no leaf-specific logic needed. | ||
| 30 | /// template <typename LeafT> void reset(const LeafT&) { } | ||
| 31 | /// | ||
| 32 | /// // Returns true if the filter is valid for the supplied iterator | ||
| 33 | /// template <typename IterT> bool valid(const IterT&) { return true; } | ||
| 34 | /// }; | ||
| 35 | /// @endcode | ||
| 36 | |||
| 37 | #ifndef OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED | ||
| 38 | #define OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED | ||
| 39 | |||
| 40 | #include <openvdb/version.h> | ||
| 41 | #include <openvdb/Types.h> | ||
| 42 | |||
| 43 | #include <openvdb/math/Transform.h> | ||
| 44 | #include <openvdb/tools/Interpolation.h> | ||
| 45 | |||
| 46 | #include "IndexIterator.h" | ||
| 47 | #include "AttributeArray.h" | ||
| 48 | #include "AttributeGroup.h" | ||
| 49 | #include "AttributeSet.h" | ||
| 50 | |||
| 51 | #include <random> // std::mt19937 | ||
| 52 | #include <numeric> // std::iota | ||
| 53 | #include <unordered_map> | ||
| 54 | |||
| 55 | |||
| 56 | class TestIndexFilter; | ||
| 57 | |||
| 58 | namespace openvdb { | ||
| 59 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 60 | namespace OPENVDB_VERSION_NAME { | ||
| 61 | namespace points { | ||
| 62 | |||
| 63 | |||
| 64 | //////////////////////////////////////// | ||
| 65 | |||
| 66 | /// @cond OPENVDB_DOCS_INTERNAL | ||
| 67 | |||
| 68 | namespace index_filter_internal { | ||
| 69 | |||
| 70 | |||
| 71 | // generate a random subset of n indices from the range [0:m] | ||
| 72 | template <typename RandGenT, typename IntType> | ||
| 73 | std::vector<IntType> | ||
| 74 | 30 | generateRandomSubset(const unsigned int seed, const IntType n, const IntType m) | |
| 75 | { | ||
| 76 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
|
30 | if (n <= 0) return std::vector<IntType>(); |
| 77 | |||
| 78 | // fill vector with ascending indices | ||
| 79 | 28 | std::vector<IntType> values(m); | |
| 80 | 28 | std::iota(values.begin(), values.end(), 0); | |
| 81 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
|
28 | if (n >= m) return values; |
| 82 | |||
| 83 | // shuffle indices using random generator | ||
| 84 | |||
| 85 | 22 | RandGenT randGen(seed); | |
| 86 | 22 | std::shuffle(values.begin(), values.end(), randGen); | |
| 87 | |||
| 88 | // resize the container to n elements | ||
| 89 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
22 | values.resize(n); |
| 90 | |||
| 91 | // sort the subset of the indices vector that will be used | ||
| 92 | 22 | std::sort(values.begin(), values.end()); | |
| 93 | |||
| 94 | return values; | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | } // namespace index_filter_internal | ||
| 99 | |||
| 100 | /// @endcond | ||
| 101 | |||
| 102 | |||
| 103 | /// Index filtering on active / inactive state of host voxel | ||
| 104 | template <bool On> | ||
| 105 | class ValueMaskFilter | ||
| 106 | { | ||
| 107 | public: | ||
| 108 | static bool initialized() { return true; } | ||
| 109 | static index::State state() { return index::PARTIAL; } | ||
| 110 | template <typename LeafT> | ||
| 111 | 64 | static index::State state(const LeafT& leaf) | |
| 112 | { | ||
| 113 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
|
64 | if (leaf.isDense()) return On ? index::ALL : index::NONE; |
| 114 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
|
52 | else if (leaf.isEmpty()) return On ? index::NONE : index::ALL; |
| 115 | return index::PARTIAL; | ||
| 116 | } | ||
| 117 | |||
| 118 | template <typename LeafT> | ||
| 119 | void reset(const LeafT&) { } | ||
| 120 | |||
| 121 | template <typename IterT> | ||
| 122 | bool valid(const IterT& iter) const | ||
| 123 | { | ||
| 124 |
18/36✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
|
2112 | const bool valueOn = iter.isValueOn(); |
| 125 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
2 | return On ? valueOn : !valueOn; |
| 126 | } | ||
| 127 | }; | ||
| 128 | |||
| 129 | |||
| 130 | using ActiveFilter = ValueMaskFilter<true>; | ||
| 131 | using InactiveFilter = ValueMaskFilter<false>; | ||
| 132 | |||
| 133 | |||
| 134 | /// Index filtering on multiple group membership for inclusion and exclusion | ||
| 135 | /// | ||
| 136 | /// @note include filters are applied first, then exclude filters | ||
| 137 | class MultiGroupFilter | ||
| 138 | { | ||
| 139 | public: | ||
| 140 | using NameVector = std::vector<Name>; | ||
| 141 | using IndexVector = std::vector<AttributeSet::Descriptor::GroupIndex>; | ||
| 142 | using HandleVector = std::vector<GroupHandle>; | ||
| 143 | |||
| 144 | private: | ||
| 145 | 122 | static IndexVector namesToIndices(const AttributeSet& attributeSet, const NameVector& names) { | |
| 146 | IndexVector indices; | ||
| 147 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 122 times.
|
187 | for (const auto& name : names) { |
| 148 | try { | ||
| 149 |
4/6✓ Branch 1 taken 64 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
65 | indices.emplace_back(attributeSet.groupIndex(name)); |
| 150 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | } catch (LookupError&) { |
| 151 | // silently drop group names that don't exist | ||
| 152 | } | ||
| 153 | } | ||
| 154 | 122 | return indices; | |
| 155 | } | ||
| 156 | |||
| 157 | public: | ||
| 158 | 61 | MultiGroupFilter( const NameVector& include, | |
| 159 | const NameVector& exclude, | ||
| 160 | const AttributeSet& attributeSet) | ||
| 161 | 61 | : mInclude(MultiGroupFilter::namesToIndices(attributeSet, include)) | |
| 162 |
1/2✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
|
61 | , mExclude(MultiGroupFilter::namesToIndices(attributeSet, exclude)) { } |
| 163 | |||
| 164 | MultiGroupFilter( const IndexVector& include, | ||
| 165 | const IndexVector& exclude) | ||
| 166 | : mInclude(include) | ||
| 167 | , mExclude(exclude) { } | ||
| 168 | |||
| 169 | 59046 | MultiGroupFilter( const MultiGroupFilter& filter) | |
| 170 | 59046 | : mInclude(filter.mInclude) | |
| 171 | 59046 | , mExclude(filter.mExclude) | |
| 172 | 59046 | , mIncludeHandles(filter.mIncludeHandles) | |
| 173 | 59046 | , mExcludeHandles(filter.mExcludeHandles) | |
| 174 |
3/6✓ Branch 2 taken 59046 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 59046 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 59046 times.
✗ Branch 9 not taken.
|
59046 | , mInitialized(filter.mInitialized) { } |
| 175 | |||
| 176 |
5/10✗ Branch 0 not taken.
✓ Branch 1 taken 18226 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10866 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5837 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
|
34931 | inline bool initialized() const { return mInitialized; } |
| 177 | |||
| 178 | inline index::State state() const | ||
| 179 | { | ||
| 180 |
50/240✓ Branch 0 taken 2905 times.
✓ Branch 1 taken 2902 times.
✓ Branch 2 taken 2901 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2902 times.
✓ Branch 5 taken 2903 times.
✓ Branch 6 taken 2901 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2902 times.
✓ Branch 9 taken 2904 times.
✓ Branch 10 taken 2900 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2901 times.
✓ Branch 13 taken 2901 times.
✓ Branch 14 taken 2900 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 2900 times.
✓ Branch 17 taken 2901 times.
✓ Branch 18 taken 2900 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 32 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✓ Branch 64 taken 2 times.
✓ Branch 65 taken 1 times.
✓ Branch 66 taken 1 times.
✓ Branch 67 taken 1 times.
✓ Branch 68 taken 1 times.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✓ Branch 71 taken 1 times.
✓ Branch 72 taken 1 times.
✗ Branch 73 not taken.
✓ Branch 74 taken 1 times.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
✓ Branch 132 taken 12 times.
✓ Branch 133 taken 6 times.
✓ Branch 134 taken 6 times.
✓ Branch 135 taken 6 times.
✓ Branch 136 taken 6 times.
✓ Branch 137 taken 12 times.
✗ Branch 138 not taken.
✓ Branch 139 taken 6 times.
✓ Branch 140 taken 2 times.
✓ Branch 141 taken 1 times.
✓ Branch 142 taken 1 times.
✓ Branch 143 taken 1 times.
✓ Branch 144 taken 2 times.
✓ Branch 145 taken 1 times.
✓ Branch 146 taken 1 times.
✓ Branch 147 taken 1 times.
✗ Branch 148 not taken.
✓ Branch 149 taken 1 times.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✓ Branch 152 taken 1 times.
✓ Branch 153 taken 1 times.
✓ Branch 154 taken 1 times.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 164 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 167 not taken.
✗ Branch 168 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 171 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 180 not taken.
✗ Branch 181 not taken.
✗ Branch 182 not taken.
✗ Branch 183 not taken.
✗ Branch 184 not taken.
✗ Branch 185 not taken.
✗ Branch 186 not taken.
✗ Branch 187 not taken.
✗ Branch 188 not taken.
✗ Branch 189 not taken.
✗ Branch 190 not taken.
✗ Branch 191 not taken.
✗ Branch 192 not taken.
✗ Branch 193 not taken.
✗ Branch 194 not taken.
✗ Branch 195 not taken.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 198 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 201 not taken.
✗ Branch 202 not taken.
✗ Branch 203 not taken.
✗ Branch 204 not taken.
✗ Branch 205 not taken.
✗ Branch 206 not taken.
✗ Branch 207 not taken.
✗ Branch 208 not taken.
✗ Branch 209 not taken.
✗ Branch 210 not taken.
✗ Branch 211 not taken.
✗ Branch 212 not taken.
✗ Branch 213 not taken.
✗ Branch 214 not taken.
✗ Branch 215 not taken.
✗ Branch 216 not taken.
✗ Branch 217 not taken.
✗ Branch 218 not taken.
✗ Branch 219 not taken.
✗ Branch 220 not taken.
✗ Branch 221 not taken.
✗ Branch 222 not taken.
✗ Branch 223 not taken.
✗ Branch 224 not taken.
✗ Branch 225 not taken.
✗ Branch 226 not taken.
✗ Branch 227 not taken.
✗ Branch 228 not taken.
✗ Branch 229 not taken.
✗ Branch 230 not taken.
✗ Branch 231 not taken.
✗ Branch 232 not taken.
✗ Branch 233 not taken.
✗ Branch 234 not taken.
✗ Branch 235 not taken.
✗ Branch 236 not taken.
✗ Branch 237 not taken.
✗ Branch 238 not taken.
✗ Branch 239 not taken.
|
29094 | return (mInclude.empty() && mExclude.empty()) ? index::ALL : index::PARTIAL; |
| 181 | } | ||
| 182 | |||
| 183 | template <typename LeafT> | ||
| 184 | static index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 185 | |||
| 186 | template <typename LeafT> | ||
| 187 | 24092 | void reset(const LeafT& leaf) { | |
| 188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24092 times.
|
24092 | mIncludeHandles.clear(); |
| 189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24092 times.
|
24092 | mExcludeHandles.clear(); |
| 190 |
2/2✓ Branch 0 taken 19576 times.
✓ Branch 1 taken 24092 times.
|
43668 | for (const auto& i : mInclude) { |
| 191 | 19576 | mIncludeHandles.emplace_back(leaf.groupHandle(i)); | |
| 192 | } | ||
| 193 |
2/2✓ Branch 0 taken 6738 times.
✓ Branch 1 taken 24092 times.
|
30830 | for (const auto& i : mExclude) { |
| 194 | 6738 | mExcludeHandles.emplace_back(leaf.groupHandle(i)); | |
| 195 | } | ||
| 196 | 24092 | mInitialized = true; | |
| 197 | 24092 | } | |
| 198 | |||
| 199 | template <typename IterT> | ||
| 200 | 11025523 | bool valid(const IterT& iter) const { | |
| 201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4015319 times.
|
11025523 | assert(mInitialized); |
| 202 | // accept no include filters as valid | ||
| 203 | bool includeValid = mIncludeHandles.empty(); | ||
| 204 |
2/2✓ Branch 0 taken 4015246 times.
✓ Branch 1 taken 2007362 times.
|
16037892 | for (const GroupHandle& handle : mIncludeHandles) { |
| 205 |
3/3✓ Branch 1 taken 31 times.
✓ Branch 2 taken 2007295 times.
✓ Branch 3 taken 2007920 times.
|
10025362 | if (handle.getUnsafe(*iter)) { |
| 206 | includeValid = true; | ||
| 207 | break; | ||
| 208 | } | ||
| 209 | } | ||
| 210 |
2/2✓ Branch 0 taken 2008038 times.
✓ Branch 1 taken 2007281 times.
|
11025523 | if (!includeValid) return false; |
| 211 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 2007997 times.
|
6013284 | for (const GroupHandle& handle : mExcludeHandles) { |
| 212 |
3/3✓ Branch 1 taken 29 times.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 29 times.
|
192 | if (handle.getUnsafe(*iter)) return false; |
| 213 | } | ||
| 214 | 6013092 | return true; | |
| 215 | } | ||
| 216 | |||
| 217 | private: | ||
| 218 | IndexVector mInclude; | ||
| 219 | IndexVector mExclude; | ||
| 220 | HandleVector mIncludeHandles; | ||
| 221 | HandleVector mExcludeHandles; | ||
| 222 | bool mInitialized = false; | ||
| 223 | }; // class MultiGroupFilter | ||
| 224 | |||
| 225 | |||
| 226 | // Random index filtering per leaf | ||
| 227 | template <typename PointDataTreeT, typename RandGenT> | ||
| 228 | class RandomLeafFilter | ||
| 229 | { | ||
| 230 | public: | ||
| 231 | using SeedCountPair = std::pair<Index, Index>; | ||
| 232 | using LeafMap = std::unordered_map<openvdb::Coord, SeedCountPair>; | ||
| 233 | |||
| 234 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | RandomLeafFilter( const PointDataTreeT& tree, |
| 235 | const Index64 targetPoints, | ||
| 236 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | const unsigned int seed = 0) { |
| 237 | Index64 currentPoints = 0; | ||
| 238 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | for (auto iter = tree.cbeginLeaf(); iter; ++iter) { |
| 239 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | currentPoints += iter->pointCount(); |
| 240 | } | ||
| 241 | |||
| 242 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const float factor = targetPoints > currentPoints ? 1.0f : float(targetPoints) / float(currentPoints); |
| 243 | |||
| 244 | 3 | std::mt19937 generator(seed); | |
| 245 | std::uniform_int_distribution<unsigned int> dist(0, std::numeric_limits<unsigned int>::max() - 1); | ||
| 246 | |||
| 247 | Index32 leafCounter = 0; | ||
| 248 | float totalPointsFloat = 0.0f; | ||
| 249 | int totalPoints = 0; | ||
| 250 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | for (auto iter = tree.cbeginLeaf(); iter; ++iter) { |
| 251 | // for the last leaf - use the remaining points to reach the target points | ||
| 252 |
3/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
|
6 | if (leafCounter + 1 == tree.leafCount()) { |
| 253 | 2 | const int leafPoints = static_cast<int>(targetPoints) - totalPoints; | |
| 254 | mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints); | ||
| 255 | break; | ||
| 256 | } | ||
| 257 | 4 | totalPointsFloat += factor * static_cast<float>(iter->pointCount()); | |
| 258 | const auto leafPoints = static_cast<int>(math::Floor(totalPointsFloat)); | ||
| 259 | 4 | totalPointsFloat -= static_cast<float>(leafPoints); | |
| 260 | 4 | totalPoints += leafPoints; | |
| 261 | |||
| 262 | mLeafMap[iter->origin()] = SeedCountPair(dist(generator), leafPoints); | ||
| 263 | |||
| 264 | leafCounter++; | ||
| 265 | } | ||
| 266 | 3 | } | |
| 267 | |||
| 268 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
10 | inline bool initialized() const { return mNextIndex == -1; } |
| 269 | |||
| 270 | static index::State state() { return index::PARTIAL; } | ||
| 271 | template <typename LeafT> | ||
| 272 | static index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 273 | |||
| 274 | template <typename LeafT> | ||
| 275 | 9 | void reset(const LeafT& leaf) { | |
| 276 | using index_filter_internal::generateRandomSubset; | ||
| 277 | |||
| 278 |
2/3✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
|
9 | auto it = mLeafMap.find(leaf.origin()); |
| 279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (it == mLeafMap.end()) { |
| 280 | ✗ | OPENVDB_THROW(openvdb::KeyError, | |
| 281 | "Cannot find leaf origin in map for random filter - " << leaf.origin()); | ||
| 282 | } | ||
| 283 | |||
| 284 | const SeedCountPair& value = it->second; | ||
| 285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
9 | const unsigned int seed = static_cast<unsigned int>(value.first); |
| 286 | 9 | const auto total = static_cast<Index>(leaf.pointCount()); | |
| 287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | mCount = std::min(value.second, total); |
| 288 | |||
| 289 | 9 | mIndices = generateRandomSubset<RandGenT, int>(seed, mCount, total); | |
| 290 | |||
| 291 | 9 | mSubsetOffset = -1; | |
| 292 | 9 | mNextIndex = -1; | |
| 293 | 9 | } | |
| 294 | |||
| 295 | inline void next() const { | ||
| 296 | 2067 | mSubsetOffset++; | |
| 297 |
4/4✓ Branch 0 taken 2011 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 1 times.
|
2067 | mNextIndex = mSubsetOffset >= mCount ? |
| 298 | std::numeric_limits<int>::max() : | ||
| 299 | mIndices[mSubsetOffset]; | ||
| 300 | 2067 | } | |
| 301 | |||
| 302 | template <typename IterT> | ||
| 303 | 6000 | bool valid(const IterT& iter) const { | |
| 304 | 6000 | const int index = *iter; | |
| 305 |
4/4✓ Branch 0 taken 2016 times.
✓ Branch 1 taken 6100 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 100 times.
|
8267 | while (mNextIndex < index) this->next(); |
| 306 | 6000 | return mNextIndex == index; | |
| 307 | } | ||
| 308 | |||
| 309 | protected: | ||
| 310 | friend class ::TestIndexFilter; | ||
| 311 | |||
| 312 | private: | ||
| 313 | LeafMap mLeafMap; | ||
| 314 | std::vector<int> mIndices; | ||
| 315 | int mCount = 0; | ||
| 316 | mutable int mSubsetOffset = -1; | ||
| 317 | mutable int mNextIndex = -1; | ||
| 318 | }; // class RandomLeafFilter | ||
| 319 | |||
| 320 | |||
| 321 | // Hash attribute value for deterministic, but approximate filtering | ||
| 322 | template <typename RandGenT, typename IntType> | ||
| 323 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | class AttributeHashFilter |
| 324 | { | ||
| 325 | public: | ||
| 326 | using Handle = AttributeHandle<IntType>; | ||
| 327 | |||
| 328 | 5 | AttributeHashFilter(const size_t index, | |
| 329 | const double percentage, | ||
| 330 | const unsigned int seed = 0) | ||
| 331 | : mIndex(index) | ||
| 332 | , mFactor(percentage / 100.0) | ||
| 333 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
5 | , mSeed(seed) { } |
| 334 | |||
| 335 | 2 | AttributeHashFilter(const AttributeHashFilter& filter) | |
| 336 | 2 | : mIndex(filter.mIndex) | |
| 337 | 2 | , mFactor(filter.mFactor) | |
| 338 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | , mSeed(filter.mSeed) |
| 339 | { | ||
| 340 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | if (filter.mIdHandle) mIdHandle.reset(new Handle(*filter.mIdHandle)); |
| 341 | 2 | } | |
| 342 | |||
| 343 | inline bool initialized() const { return bool(mIdHandle); } | ||
| 344 | |||
| 345 | static index::State state() { return index::PARTIAL; } | ||
| 346 | template <typename LeafT> | ||
| 347 | static index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 348 | |||
| 349 | template <typename LeafT> | ||
| 350 | 9 | void reset(const LeafT& leaf) { | |
| 351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(leaf.hasAttribute(mIndex)); |
| 352 |
1/2✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | mIdHandle.reset(new Handle(leaf.constAttributeArray(mIndex))); |
| 353 | 9 | } | |
| 354 | |||
| 355 | template <typename IterT> | ||
| 356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | bool valid(const IterT& iter) const { |
| 357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | assert(mIdHandle); |
| 358 | 16 | const IntType id = mIdHandle->get(*iter); | |
| 359 | 16 | const unsigned int seed = mSeed + static_cast<unsigned int>(id); | |
| 360 | 16 | RandGenT generator(seed); | |
| 361 | std::uniform_real_distribution<double> dist(0.0, 1.0); | ||
| 362 | 16 | return dist(generator) < mFactor; | |
| 363 | } | ||
| 364 | |||
| 365 | private: | ||
| 366 | const size_t mIndex; | ||
| 367 | const double mFactor; | ||
| 368 | const unsigned int mSeed; | ||
| 369 | typename Handle::UniquePtr mIdHandle; | ||
| 370 | }; // class AttributeHashFilter | ||
| 371 | |||
| 372 | |||
| 373 | template <typename LevelSetGridT> | ||
| 374 | class LevelSetFilter | ||
| 375 | { | ||
| 376 | public: | ||
| 377 | using ValueT = typename LevelSetGridT::ValueType; | ||
| 378 | using Handle = AttributeHandle<openvdb::Vec3f>; | ||
| 379 | |||
| 380 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
5 | LevelSetFilter( const LevelSetGridT& grid, |
| 381 | const math::Transform& transform, | ||
| 382 | const ValueT min, | ||
| 383 | const ValueT max) | ||
| 384 | : mAccessor(grid.getConstAccessor()) | ||
| 385 | , mLevelSetTransform(grid.transform()) | ||
| 386 | , mTransform(transform) | ||
| 387 | , mMin(min) | ||
| 388 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
5 | , mMax(max) { } |
| 389 | |||
| 390 | 2 | LevelSetFilter(const LevelSetFilter& filter) | |
| 391 | : mAccessor(filter.mAccessor) | ||
| 392 | 2 | , mLevelSetTransform(filter.mLevelSetTransform) | |
| 393 | 2 | , mTransform(filter.mTransform) | |
| 394 | 2 | , mMin(filter.mMin) | |
| 395 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | , mMax(filter.mMax) |
| 396 | { | ||
| 397 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
2 | if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle)); |
| 398 | 2 | } | |
| 399 | |||
| 400 | inline bool initialized() const { return bool(mPositionHandle); } | ||
| 401 | |||
| 402 | static index::State state() { return index::PARTIAL; } | ||
| 403 | template <typename LeafT> | ||
| 404 | static index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 405 | |||
| 406 | template <typename LeafT> | ||
| 407 | 10 | void reset(const LeafT& leaf) { | |
| 408 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
|
20 | mPositionHandle.reset(new Handle(leaf.constAttributeArray("P"))); |
| 409 | 10 | } | |
| 410 | |||
| 411 | template <typename IterT> | ||
| 412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | bool valid(const IterT& iter) const { |
| 413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | assert(mPositionHandle); |
| 414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | assert(iter); |
| 415 | |||
| 416 | 12 | const openvdb::Coord ijk = iter.getCoord(); | |
| 417 | const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d(); | ||
| 418 | |||
| 419 | // Retrieve point position in voxel space | ||
| 420 | 12 | const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter); | |
| 421 | |||
| 422 | // Compute point position in index space | ||
| 423 | 12 | const openvdb::Vec3f pointWorldSpace = mTransform.indexToWorld(pointVoxelSpace + voxelIndexSpace); | |
| 424 | 12 | const openvdb::Vec3f pointIndexSpace = mLevelSetTransform.worldToIndex(pointWorldSpace); | |
| 425 | |||
| 426 | // Perform level-set sampling | ||
| 427 | 12 | const typename LevelSetGridT::ValueType value = tools::BoxSampler::sample(mAccessor, pointIndexSpace); | |
| 428 | |||
| 429 | // if min is greater than max, we invert so that values are valid outside of the range (not inside) | ||
| 430 | 12 | const bool invert = mMin > mMax; | |
| 431 | |||
| 432 |
8/10✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
|
12 | return invert ? (value < mMax || value > mMin) : (value < mMax && value > mMin); |
| 433 | } | ||
| 434 | |||
| 435 | private: | ||
| 436 | // not a reference to ensure const-accessor is unique per-thread | ||
| 437 | const typename LevelSetGridT::ConstAccessor mAccessor; | ||
| 438 | const math::Transform& mLevelSetTransform; | ||
| 439 | const math::Transform& mTransform; | ||
| 440 | const ValueT mMin; | ||
| 441 | const ValueT mMax; | ||
| 442 | Handle::UniquePtr mPositionHandle; | ||
| 443 | }; // class LevelSetFilter | ||
| 444 | |||
| 445 | |||
| 446 | // BBox index filtering | ||
| 447 |
6/10✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
9 | class BBoxFilter |
| 448 | { | ||
| 449 | public: | ||
| 450 | using Handle = AttributeHandle<openvdb::Vec3f>; | ||
| 451 | |||
| 452 | BBoxFilter(const openvdb::math::Transform& transform, | ||
| 453 | const openvdb::BBoxd& bboxWS) | ||
| 454 | 6 | : mTransform(transform) | |
| 455 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
3 | , mBbox(transform.worldToIndex(bboxWS)) { } |
| 456 | |||
| 457 | 11 | BBoxFilter(const BBoxFilter& filter) | |
| 458 | 11 | : mTransform(filter.mTransform) | |
| 459 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | , mBbox(filter.mBbox) |
| 460 | { | ||
| 461 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
11 | if (filter.mPositionHandle) mPositionHandle.reset(new Handle(*filter.mPositionHandle)); |
| 462 | 11 | } | |
| 463 | |||
| 464 | inline bool initialized() const { return bool(mPositionHandle); } | ||
| 465 | |||
| 466 | inline index::State state() const | ||
| 467 | { | ||
| 468 | return mBbox.empty() ? index::NONE : index::PARTIAL; | ||
| 469 | } | ||
| 470 | template <typename LeafT> | ||
| 471 | static index::State state(const LeafT&) { return index::PARTIAL; } | ||
| 472 | |||
| 473 | template <typename LeafT> | ||
| 474 | 17 | void reset(const LeafT& leaf) { | |
| 475 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
|
34 | mPositionHandle.reset(new Handle(leaf.constAttributeArray("P"))); |
| 476 | 17 | } | |
| 477 | |||
| 478 | template <typename IterT> | ||
| 479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
28 | bool valid(const IterT& iter) const { |
| 480 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
28 | assert(mPositionHandle); |
| 481 | |||
| 482 | 28 | const openvdb::Coord ijk = iter.getCoord(); | |
| 483 | const openvdb::Vec3f voxelIndexSpace = ijk.asVec3d(); | ||
| 484 | |||
| 485 | // Retrieve point position in voxel space | ||
| 486 | 28 | const openvdb::Vec3f& pointVoxelSpace = mPositionHandle->get(*iter); | |
| 487 | |||
| 488 | // Compute point position in index space | ||
| 489 | const openvdb::Vec3f pointIndexSpace = pointVoxelSpace + voxelIndexSpace; | ||
| 490 | |||
| 491 | 28 | return mBbox.isInside(pointIndexSpace); | |
| 492 | } | ||
| 493 | |||
| 494 | private: | ||
| 495 | const openvdb::math::Transform& mTransform; | ||
| 496 | const openvdb::BBoxd mBbox; | ||
| 497 | Handle::UniquePtr mPositionHandle; | ||
| 498 | }; // class BBoxFilter | ||
| 499 | |||
| 500 | |||
| 501 | // Index filtering based on evaluating both sub-filters | ||
| 502 | template <typename T1, typename T2, bool And = true> | ||
| 503 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
55 | class BinaryFilter |
| 504 | { | ||
| 505 | public: | ||
| 506 | 21 | BinaryFilter( const T1& filter1, | |
| 507 | const T2& filter2) | ||
| 508 | : mFilter1(filter1) | ||
| 509 |
7/12✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
|
11 | , mFilter2(filter2) { } |
| 510 | |||
| 511 |
6/8✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
32 | inline bool initialized() const { return mFilter1.initialized() && mFilter2.initialized(); } |
| 512 | |||
| 513 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6 times.
|
28 | inline index::State state() const |
| 514 | { | ||
| 515 | 28 | return this->computeState(mFilter1.state(), mFilter2.state()); | |
| 516 | } | ||
| 517 | template <typename LeafT> | ||
| 518 | inline index::State state(const LeafT& leaf) const | ||
| 519 | { | ||
| 520 | 8 | return this->computeState(mFilter1.state(leaf), mFilter2.state(leaf)); | |
| 521 | } | ||
| 522 | |||
| 523 | template <typename LeafT> | ||
| 524 | void reset(const LeafT& leaf) { | ||
| 525 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
17 | mFilter1.reset(leaf); |
| 526 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | mFilter2.reset(leaf); |
| 527 | 19 | } | |
| 528 | |||
| 529 | template <typename IterT> | ||
| 530 | 82 | bool valid(const IterT& iter) const { | |
| 531 |
6/6✓ Branch 0 taken 57 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 55 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 3 times.
|
214 | if (And) return mFilter1.valid(iter) && mFilter2.valid(iter); |
| 532 |
4/4✓ Branch 0 taken 95 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 91 times.
|
100 | return mFilter1.valid(iter) || mFilter2.valid(iter); |
| 533 | } | ||
| 534 | |||
| 535 | private: | ||
| 536 | inline index::State computeState( index::State state1, | ||
| 537 | index::State state2) const | ||
| 538 | { | ||
| 539 | if (And) { | ||
| 540 |
3/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
29 | if (state1 == index::NONE || state2 == index::NONE) return index::NONE; |
| 541 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
|
20 | else if (state1 == index::ALL && state2 == index::ALL) return index::ALL; |
| 542 | } else { | ||
| 543 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (state1 == index::NONE && state2 == index::NONE) return index::NONE; |
| 544 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | else if (state1 == index::ALL && state2 == index::ALL) return index::ALL; |
| 545 | } | ||
| 546 | return index::PARTIAL; | ||
| 547 | } | ||
| 548 | |||
| 549 | T1 mFilter1; | ||
| 550 | T2 mFilter2; | ||
| 551 | }; // class BinaryFilter | ||
| 552 | |||
| 553 | |||
| 554 | //////////////////////////////////////// | ||
| 555 | |||
| 556 | |||
| 557 | template<typename T> | ||
| 558 | struct FilterTraits { | ||
| 559 | static const bool RequiresCoord = false; | ||
| 560 | }; | ||
| 561 | template<> | ||
| 562 | struct FilterTraits<BBoxFilter> { | ||
| 563 | static const bool RequiresCoord = true; | ||
| 564 | }; | ||
| 565 | template <typename T> | ||
| 566 | struct FilterTraits<LevelSetFilter<T>> { | ||
| 567 | static const bool RequiresCoord = true; | ||
| 568 | }; | ||
| 569 | template <typename T0, typename T1, bool And> | ||
| 570 | struct FilterTraits<BinaryFilter<T0, T1, And>> { | ||
| 571 | static const bool RequiresCoord = FilterTraits<T0>::RequiresCoord || | ||
| 572 | FilterTraits<T1>::RequiresCoord; | ||
| 573 | }; | ||
| 574 | |||
| 575 | |||
| 576 | //////////////////////////////////////// | ||
| 577 | |||
| 578 | |||
| 579 | } // namespace points | ||
| 580 | } // namespace OPENVDB_VERSION_NAME | ||
| 581 | } // namespace openvdb | ||
| 582 | |||
| 583 | #endif // OPENVDB_POINTS_INDEX_FILTER_HAS_BEEN_INCLUDED | ||
| 584 |