Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file points/PointCount.h | ||
5 | /// | ||
6 | /// @author Dan Bailey | ||
7 | /// | ||
8 | /// @brief Methods for counting points in VDB Point grids. | ||
9 | |||
10 | #ifndef OPENVDB_POINTS_POINT_COUNT_HAS_BEEN_INCLUDED | ||
11 | #define OPENVDB_POINTS_POINT_COUNT_HAS_BEEN_INCLUDED | ||
12 | |||
13 | #include <openvdb/openvdb.h> | ||
14 | |||
15 | #include "PointDataGrid.h" | ||
16 | #include "PointMask.h" | ||
17 | #include "IndexFilter.h" | ||
18 | |||
19 | #include <tbb/parallel_reduce.h> | ||
20 | |||
21 | #include <vector> | ||
22 | |||
23 | |||
24 | namespace openvdb { | ||
25 | OPENVDB_USE_VERSION_NAMESPACE | ||
26 | namespace OPENVDB_VERSION_NAME { | ||
27 | namespace points { | ||
28 | |||
29 | |||
30 | /// @brief Count the total number of points in a PointDataTree | ||
31 | /// @param tree the PointDataTree in which to count the points | ||
32 | /// @param filter an optional index filter | ||
33 | /// @param inCoreOnly if true, points in out-of-core leaf nodes are not counted | ||
34 | /// @param threaded enable or disable threading (threading is enabled by default) | ||
35 | template <typename PointDataTreeT, typename FilterT = NullFilter> | ||
36 | inline Index64 pointCount( const PointDataTreeT& tree, | ||
37 | const FilterT& filter = NullFilter(), | ||
38 | const bool inCoreOnly = false, | ||
39 | const bool threaded = true); | ||
40 | |||
41 | |||
42 | /// @brief Populate an array of cumulative point offsets per leaf node. | ||
43 | /// @param pointOffsets array of offsets to be populated | ||
44 | /// @param tree the PointDataTree from which to populate the offsets | ||
45 | /// @param filter an optional index filter | ||
46 | /// @param inCoreOnly if true, points in out-of-core leaf nodes are ignored | ||
47 | /// @param threaded enable or disable threading (threading is enabled by default) | ||
48 | /// @return The final cumulative point offset. | ||
49 | template <typename PointDataTreeT, typename FilterT = NullFilter> | ||
50 | inline Index64 pointOffsets(std::vector<Index64>& pointOffsets, | ||
51 | const PointDataTreeT& tree, | ||
52 | const FilterT& filter = NullFilter(), | ||
53 | const bool inCoreOnly = false, | ||
54 | const bool threaded = true); | ||
55 | |||
56 | |||
57 | /// @brief Generate a new grid with voxel values to store the number of points per voxel | ||
58 | /// @param grid the PointDataGrid to use to compute the count grid | ||
59 | /// @param filter an optional index filter | ||
60 | /// @note The return type of the grid must be an integer or floating-point scalar grid. | ||
61 | template <typename PointDataGridT, | ||
62 | typename GridT = typename PointDataGridT::template ValueConverter<Int32>::Type, | ||
63 | typename FilterT = NullFilter> | ||
64 | inline typename GridT::Ptr | ||
65 | pointCountGrid( const PointDataGridT& grid, | ||
66 | const FilterT& filter = NullFilter()); | ||
67 | |||
68 | |||
69 | /// @brief Generate a new grid that uses the supplied transform with voxel values to store the | ||
70 | /// number of points per voxel. | ||
71 | /// @param grid the PointDataGrid to use to compute the count grid | ||
72 | /// @param transform the transform to use to compute the count grid | ||
73 | /// @param filter an optional index filter | ||
74 | /// @note The return type of the grid must be an integer or floating-point scalar grid. | ||
75 | template <typename PointDataGridT, | ||
76 | typename GridT = typename PointDataGridT::template ValueConverter<Int32>::Type, | ||
77 | typename FilterT = NullFilter> | ||
78 | inline typename GridT::Ptr | ||
79 | pointCountGrid( const PointDataGridT& grid, | ||
80 | const openvdb::math::Transform& transform, | ||
81 | const FilterT& filter = NullFilter()); | ||
82 | |||
83 | |||
84 | //////////////////////////////////////// | ||
85 | |||
86 | |||
87 | template <typename PointDataTreeT, typename FilterT> | ||
88 | 205 | Index64 pointCount(const PointDataTreeT& tree, | |
89 | const FilterT& filter, | ||
90 | const bool inCoreOnly, | ||
91 | const bool threaded) | ||
92 | { | ||
93 | using LeafManagerT = tree::LeafManager<const PointDataTreeT>; | ||
94 | using LeafRangeT = typename LeafManagerT::LeafRange; | ||
95 | |||
96 | 205 | auto countLambda = | |
97 | 11282 | [&filter, &inCoreOnly] (const LeafRangeT& range, Index64 sum) -> Index64 { | |
98 | 11356 | for (const auto& leaf : range) { | |
99 |
15/24✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9943 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 60 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 9 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 1 times.
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
10031 | if (inCoreOnly && leaf.buffer().isOutOfCore()) continue; |
100 | 18 | auto state = filter.state(leaf); | |
101 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 7 times.
|
18 | if (state == index::ALL) { |
102 | 9941 | sum += leaf.pointCount(); | |
103 |
5/8✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
24 | } else if (state != index::NONE) { |
104 |
6/12✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 60 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 60 times.
✗ Branch 14 not taken.
|
150 | sum += iterCount(leaf.beginIndexAll(filter)); |
105 | } | ||
106 | } | ||
107 | 1325 | return sum; | |
108 | }; | ||
109 | |||
110 | 410 | LeafManagerT leafManager(tree); | |
111 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
205 | if (threaded) { |
112 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
205 | return tbb::parallel_reduce(leafManager.leafRange(), Index64(0), countLambda, |
113 | 56 | [] (Index64 n, Index64 m) -> Index64 { return n + m; }); | |
114 | } | ||
115 | else { | ||
116 | ✗ | return countLambda(leafManager.leafRange(), Index64(0)); | |
117 | } | ||
118 | } | ||
119 | |||
120 | |||
121 | template <typename PointDataTreeT, typename FilterT> | ||
122 | 71 | Index64 pointOffsets( std::vector<Index64>& pointOffsets, | |
123 | const PointDataTreeT& tree, | ||
124 | const FilterT& filter, | ||
125 | const bool inCoreOnly, | ||
126 | const bool threaded) | ||
127 | { | ||
128 | using LeafT = typename PointDataTreeT::LeafNodeType; | ||
129 | using LeafManagerT = typename tree::LeafManager<const PointDataTreeT>; | ||
130 | |||
131 | // allocate and zero values in point offsets array | ||
132 | |||
133 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
71 | pointOffsets.assign(tree.leafCount(), Index64(0)); |
134 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
71 | if (pointOffsets.empty()) return 0; |
135 | |||
136 | // compute total points per-leaf | ||
137 | |||
138 | 140 | LeafManagerT leafManager(tree); | |
139 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
70 | leafManager.foreach( |
140 | 28611 | [&pointOffsets, &filter, &inCoreOnly](const LeafT& leaf, size_t pos) { | |
141 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 22795 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 5816 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
|
28615 | if (inCoreOnly && leaf.buffer().isOutOfCore()) return; |
142 | auto state = filter.state(leaf); | ||
143 | if (state == index::ALL) { | ||
144 | 22795 | pointOffsets[pos] = leaf.pointCount(); | |
145 | } else if (state != index::NONE) { | ||
146 |
1/2✓ Branch 1 taken 5816 times.
✗ Branch 2 not taken.
|
5816 | pointOffsets[pos] = iterCount(leaf.beginIndexAll(filter)); |
147 | } | ||
148 | }, | ||
149 | threaded); | ||
150 | |||
151 | // turn per-leaf totals into cumulative leaf totals | ||
152 | |||
153 | 70 | Index64 pointOffset(pointOffsets[0]); | |
154 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
28615 | for (size_t n = 1; n < pointOffsets.size(); n++) { |
155 | 28545 | pointOffset += pointOffsets[n]; | |
156 | 28545 | pointOffsets[n] = pointOffset; | |
157 | } | ||
158 | |||
159 | return pointOffset; | ||
160 | } | ||
161 | |||
162 | |||
163 | template <typename PointDataGridT, typename GridT, typename FilterT> | ||
164 | typename GridT::Ptr | ||
165 | 18 | pointCountGrid( const PointDataGridT& points, | |
166 | const FilterT& filter) | ||
167 | { | ||
168 | static_assert(std::is_integral<typename GridT::ValueType>::value || | ||
169 | std::is_floating_point<typename GridT::ValueType>::value, | ||
170 | "openvdb::points::pointCountGrid must return an integer or floating-point scalar grid"); | ||
171 | |||
172 | using PointDataTreeT = typename PointDataGridT::TreeType; | ||
173 | using TreeT = typename GridT::TreeType; | ||
174 | |||
175 | 18 | typename TreeT::Ptr tree = | |
176 | point_mask_internal::convertPointsToScalar<TreeT, PointDataTreeT, FilterT> | ||
177 | (points.tree(), filter); | ||
178 | |||
179 |
3/8✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
36 | typename GridT::Ptr grid(new GridT(tree)); |
180 |
3/8✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
36 | grid->setTransform(points.transform().copy()); |
181 | 18 | return grid; | |
182 | } | ||
183 | |||
184 | |||
185 | template <typename PointDataGridT, typename GridT, typename FilterT> | ||
186 | typename GridT::Ptr | ||
187 | pointCountGrid( const PointDataGridT& points, | ||
188 | const openvdb::math::Transform& transform, | ||
189 | const FilterT& filter) | ||
190 | { | ||
191 | static_assert( std::is_integral<typename GridT::ValueType>::value || | ||
192 | std::is_floating_point<typename GridT::ValueType>::value, | ||
193 | "openvdb::points::pointCountGrid must return an integer or floating-point scalar grid"); | ||
194 | |||
195 | // This is safe because the PointDataGrid can only be modified by the deformer | ||
196 | using AdapterT = TreeAdapter<typename PointDataGridT::TreeType>; | ||
197 | auto& nonConstPoints = const_cast<typename AdapterT::NonConstGridType&>(points); | ||
198 | |||
199 | NullDeformer deformer; | ||
200 | return point_mask_internal::convertPointsToScalar<GridT>( | ||
201 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | nonConstPoints, transform, filter, deformer); |
202 | } | ||
203 | |||
204 | |||
205 | //////////////////////////////////////// | ||
206 | |||
207 | |||
208 | } // namespace points | ||
209 | } // namespace OPENVDB_VERSION_NAME | ||
210 | } // namespace openvdb | ||
211 | |||
212 | #endif // OPENVDB_POINTS_POINT_COUNT_HAS_BEEN_INCLUDED | ||
213 |