1 #ifndef __SIM__VOLUMETRICCONNECTEDCOMPONENTBUILDER_H__
2 #define __SIM__VOLUMETRICCONNECTEDCOMPONENTBUILDER_H__
15 template <
typename FieldType = SIM_RawIndexField>
21 using RootPairs = std::pair<exint, exint>;
22 using ScalarType =
typename FieldType::ScalarType;
24 static constexpr
exint UNVISITED_CELL = -2;
25 static constexpr
exint VISITED_CELL = -1;
26 static constexpr
bool USING_VOXEL_ARRAY = std::is_same_v<UT_VoxelArray<ScalarType>, FieldType>;
29 static constexpr
exint INACTIVE_REGION = -1;
37 const FieldType &label_cells,
40 : m_connected_regions(connected_regions)
41 , m_face_weights(faceWeights)
42 , m_min_weight(min_weight)
44 if constexpr (USING_VOXEL_ARRAY)
46 m_labelled_cells = &label_cells;
48 label_cells.getXRes(), label_cells.getYRes(), label_cells.getZRes());
52 m_labelled_cells = label_cells.field();
53 m_connected_regions.match(label_cells);
56 m_connected_regions.makeConstant(INACTIVE_REGION);
59 template<
typename IsLabelActiveFunctor>
60 exint buildConnectedComponents(
const IsLabelActiveFunctor &isCellLabelActiveFunctor);
68 return (index[2] * size[1] + index[1]) * size[0] + index[0];
71 template<
typename IsLabelActiveFunctor>
72 void buildLocalRoots(
SIM_RawIndexField &visited_cells,
const IsLabelActiveFunctor &isCellLabelActiveFunctor);
83 const IntegerMap &, root_map,
84 const IntegerMap &, region_index_map)
86 void assignRegionLabelsPartial(
const IntegerMap &root_map,
87 const IntegerMap ®ion_index_map,
103 template<
typename FieldType>
104 template<
typename IsLabelActiveFunctor>
114 visited_cells.
match(m_connected_regions);
117 buildLocalRoots(visited_cells, isCellLabelActiveFunctor);
122 parallel_root_pair_lists.
setSize(thread_count);
128 linkLocalRoots(parallel_root_pair_lists);
134 list_size += parallel_root_pair_lists[
thread].
size();
139 root_pair_list.
concat(parallel_root_pair_lists[
thread]);
146 root_to_adjacent_root_map.reserve(root_pair_list.
size());
149 UTparallelSort(root_pair_list.
begin(), root_pair_list.
end(), [](
const RootPairs &pair0,
const RootPairs &pair1)
151 if (pair0.first < pair1.first)
return true;
155 const exint rpl_size = root_pair_list.
size();
156 for (
int i = 0; i < rpl_size; )
158 exint root_key = root_pair_list[i].first;
160 auto &local_root_list = root_to_adjacent_root_map[root_key];
164 while (i < rpl_size && root_pair_list[i].
first == root_key)
166 exint adjacent_root_key = root_pair_list[i].second;
169 UT_ASSERT(local_root_list.find(adjacent_root_key) == -1);
171 local_root_list.append(adjacent_root_key);
176 #if UT_ASSERT_LEVEL > 0
178 for (
const auto& local_root_map : root_to_adjacent_root_map)
180 exint local_root_key = local_root_map.first;
181 const auto &local_root_list = local_root_map.second;
183 for (
const exint adjacent_root_key : local_root_list)
186 UT_ASSERT(root_to_adjacent_root_map.contains(adjacent_root_key));
188 const auto &adjacent_root_list = root_to_adjacent_root_map[adjacent_root_key];
191 UT_ASSERT(adjacent_root_list.find(local_root_key) >= 0);
217 for (
const auto &local_root_map : root_to_adjacent_root_map)
219 exint final_root_index = local_root_map.first;
222 if (visited_roots_map.
contains(final_root_index))
224 UT_ASSERT(visited_roots_map[final_root_index] == VISITED_CELL);
228 to_visit_list.
clear();
229 to_visit_list.
append(final_root_index);
231 visited_roots_map[final_root_index] = VISITED_CELL;
233 roots_to_finish_list.
clear();
234 roots_to_finish_list.
append(final_root_index);
238 while (!to_visit_list.
isEmpty())
240 exint local_root_index = to_visit_list.
last();
244 final_root_index =
SYSmax(final_root_index, local_root_index);
247 const auto &adjacent_root_list = root_to_adjacent_root_map[local_root_index];
248 for (
const exint adjacent_root_index : adjacent_root_list)
252 if (!visited_roots_map.
contains(adjacent_root_index))
254 visited_roots_map[adjacent_root_index] = VISITED_CELL;
255 roots_to_finish_list.
append(adjacent_root_index);
256 to_visit_list.
append(adjacent_root_index);
260 UT_ASSERT(visited_roots_map[adjacent_root_index] == VISITED_CELL);
266 for (
const exint root : roots_to_finish_list)
267 final_root_map[root] = final_root_index;
275 exint region_index = 0;
277 for (
const auto &root : final_root_map)
281 if (!region_index_map.
contains(root.second))
282 region_index_map[root.second] = region_index++;
286 assignRegionLabels(final_root_map, region_index_map);
288 m_connected_regions.fieldNC()->collapseAllTiles();
293 template<
typename FieldType>
294 template<
typename IsCellLabelActiveFunctor>
297 const IsCellLabelActiveFunctor &isCellLabelActiveFunctor)
299 using namespace SIM::FieldUtils;
303 UT_Vector3I voxel_res = m_labelled_cells->getVoxelRes();
305 const exint tiles = m_labelled_cells->numTiles();
320 to_visit_cell_list.
bumpCapacity(TILESIZE * TILESIZE * TILESIZE);
322 for (
exint i = range.begin(); i != range.end(); ++i)
328 if (boss->opInterrupt())
341 UT_ASSERT(cell[0] >= tile_start[0] && cell[0] < tile_end[0] &&
342 cell[1] >= tile_start[1] && cell[1] < tile_end[1] &&
343 cell[2] >= tile_start[2] && cell[2] < tile_end[2]);
345 if (isCellLabelActiveFunctor(vitt.
getValue()) &&
getFieldValue(visited_cells, cell) == UNVISITED_CELL)
347 const exint flat_root = flattenIndex(cell, voxel_res);
352 to_visit_cell_list.
clear();
353 to_visit_cell_list.
append(cell);
356 while (!to_visit_cell_list.
isEmpty())
362 for (
int axis : {0,1,2})
368 if (adjacent_cell[axis] < tile_start[axis] || adjacent_cell[axis] >= tile_end[axis])
373 if (
getFieldValue(visited_cells, adjacent_cell) == UNVISITED_CELL &&
374 isCellLabelActiveFunctor((*m_labelled_cells)(adjacent_cell[0],
381 if (
getFieldValue(*m_face_weights[axis], face) > m_min_weight)
384 setFieldValue(m_connected_regions, adjacent_cell, flat_root);
386 to_visit_cell_list.
append(adjacent_cell);
398 m_connected_regions.fieldNC()->collapseAllTiles();
void UTparallelSort(RandomAccessIterator begin, RandomAccessIterator end, const Compare &compare)
void bumpCapacity(exint min_capacity)
bool contains(const Key &key) const
SYS_FORCE_INLINE void removeLast()
void UTparallelForEachNumber(IntType nitems, const Body &body, const bool force_use_task_scope=true)
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
UT_Vector3T< float > UT_Vector3
exint concat(const UT_Array< T > &a)
Takes another T array and concatenate it onto my end.
bool atEnd() const
Returns true if we have iterated over all of the voxels.
void setSize(exint newsize)
void rewind()
Resets the iterator to point to the first voxel.
SYS_FORCE_INLINE void setFieldValue(SIM_RawField &field, const UT_Vector3I &cell, fpreal32 value)
void advance()
Advances the iterator to point to the next voxel.
SYS_FORCE_INLINE UT_Vector3I cellToCellMap(const UT_Vector3I &cell, const int axis, const int direction)
void rewind()
Resets the iterator to point to the first voxel.
static int getNumProcessors()
#define THREADED_METHOD2(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2)
void setTile(const UT_VoxelArrayIterator< S > &vit, UT_VoxelArray< T > *array)
SYS_FORCE_INLINE fpreal32 getFieldValue(const SIM_RawField &field, const UT_Vector3I &cell)
bool isTileConstant() const
Returns true if the tile we are currently in is a constant tile.
void getTileVoxels(UT_Vector3I &start, UT_Vector3I &end) const
This tile will iterate over the voxels indexed [start,end).
#define THREADED_METHOD1_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1)
**Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
void makeConstant(exint cval)
Sets this field to a constant value.
SIM_EXTERN_TEMPLATE(SIM_VolumetricConnectedComponentBuilder< SIM_RawField >)
void setConstArray(const UT_VoxelArray< T > *vox)
UT_API UT_Interrupt * UTgetInterrupt()
Obtain global UT_Interrupt singleton.
SYS_FORCE_INLINE UT_Vector3I cellToFaceMap(const UT_Vector3I &cell, const int axis, const int direction)
exint buildConnectedComponents(const IsLabelActiveFunctor &isCellLabelActiveFunctor)
void match(const SIM_RawField &src)
void clear()
Resets list to an empty list.
iterator end()
End iterator.
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
SIM_VolumetricConnectedComponentBuilder(SIM_RawIndexField &connected_regions, const FieldType &label_cells, const SIM_RawField **faceWeights, float min_weight=0)
void reserve(size_type num_items)