Skip to content

Commit 2b397e4

Browse files
committed
Add SplitFunctions to split domains in hypercubes
Given a domain defined by lower and upper bound points and requested_number_of_splits implements two functions: - computeSplits returns the number of splits that the region can hold (lesser or equal than the requested) - getSplit returns the ith split and the outputLowerBound and outputUpperBound of the split region. Implementation acquired from ITK: itkImageRegionSplitterMultidimensional.cxx https://github.com/InsightSoftwareConsortium/ITK/blob/f971477cdacff22a861dfcbaccd89c0cf2755af7/Modules/Core/Common/src/itkImageRegionSplitterMultidimensional.cxx - Add splitComplex to SplitFunctions - Add test and change testSplitFunctions to use Catch
1 parent aed4455 commit 2b397e4

File tree

9 files changed

+1252
-29
lines changed

9 files changed

+1252
-29
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@
129129
(Pablo Hernandez-Cerdan, [#1488](https://github.com/DGtal-team/DGtal/pull/1488))
130130
- Fix loadTable not able to read compressed tables in Windows
131131
(Pablo Hernandez-Cerdan, [#1505](https://github.com/DGtal-team/DGtal/pull/1505))
132+
- Add functions to SplitFunctions header to divide a domain into hypercubes.
133+
(Pablo Hernandez-Cerdan,[#1521](https://github.com/DGtal-team/DGtal/pull/1521))
132134
133135
- *Shapes package*
134136
- Add a moveTo(const RealPoint& point) method to implicit and star shapes

src/DGtal/topology/CubicalComplexFunctions.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ namespace DGtal
267267
const CubicalComplex< TKSpace, TCellContainer >& S2 )
268268
{
269269
typedef CubicalComplex< TKSpace, TCellContainer > CC;
270-
ASSERT( &(S1.space()) == &(S2.space()) );
270+
ASSERT( S1.space().lowerBound() == S2.space().lowerBound() &&
271+
S1.space().upperBound() == S2.space().upperBound());
271272
for ( Dimension i = 0; i <= CC::dimension; ++i )
272273
if ( ! functions::isEqual( S1.myCells[ i ], S2.myCells[ i ] ) )
273274
return false;
@@ -294,7 +295,8 @@ namespace DGtal
294295
const CubicalComplex< TKSpace, TCellContainer >& S2 )
295296
{
296297
typedef CubicalComplex< TKSpace, TCellContainer > CC;
297-
ASSERT( &(S1.space()) == &(S2.space()) );
298+
ASSERT( S1.space().lowerBound() == S2.space().lowerBound() &&
299+
S1.space().upperBound() == S2.space().upperBound());
298300
for ( Dimension i = 0; i <= CC::dimension; ++i )
299301
if ( ! functions::isEqual( S1.myCells[ i ], S2.myCells[ i ] ) )
300302
return true;
@@ -318,7 +320,8 @@ namespace DGtal
318320
const CubicalComplex< TKSpace, TCellContainer >& S2 )
319321
{
320322
typedef CubicalComplex< TKSpace, TCellContainer > CC;
321-
ASSERT( &(S1.space()) == &(S2.space()) );
323+
ASSERT( S1.space().lowerBound() == S2.space().lowerBound() &&
324+
S1.space().upperBound() == S2.space().upperBound());
322325
for ( Dimension i = 0; i <= CC::dimension; ++i )
323326
if ( ! functions::isSubset( S1.myCells[ i ], S2.myCells[ i ] ) )
324327
return false;
@@ -341,7 +344,8 @@ namespace DGtal
341344
const CubicalComplex< TKSpace, TCellContainer >& S2 )
342345
{
343346
typedef CubicalComplex< TKSpace, TCellContainer > CC;
344-
ASSERT( &(S1.space()) == &(S2.space()) );
347+
ASSERT( S1.space().lowerBound() == S2.space().lowerBound() &&
348+
S1.space().upperBound() == S2.space().upperBound());
345349
for ( Dimension i = 0; i <= CC::dimension; ++i )
346350
if ( ! functions::isSubset( S2.myCells[ i ], S1.myCells[ i ] ) )
347351
return false;
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
/**
2+
* This program is free software: you can redistribute it and/or modify
3+
* it under the terms of the GNU Lesser General Public License as
4+
* published by the Free Software Foundation, either version 3 of the
5+
* License, or (at your option) any later version.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU General Public License for more details.
11+
*
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
14+
*
15+
**/
16+
17+
#pragma once
18+
19+
/**
20+
* @file SplitFunctions.h
21+
* @author Pablo Hernandez-Cerdan (\c pablo.hernandez.cerdan@outlook.com)
22+
*
23+
* @date 2018/01/08
24+
*
25+
* Defines functions associated to split domains for multi-threading purposes.
26+
*
27+
* This file is part of the DGtal library.
28+
*/
29+
30+
#if defined(SplitFunctions_RECURSES)
31+
#error Recursive header files inclusion detected in SplitFunctions.h
32+
#else // defined(SplitFunctions_RECURSES)
33+
/** Prevents recursive inclusion of headers. */
34+
#define SplitFunctions_RECURSES
35+
36+
#if !defined SplitFunctions_h
37+
/** Prevents repeated inclusion of headers. */
38+
#define SplitFunctions_h
39+
40+
//////////////////////////////////////////////////////////////////////////////
41+
// Inclusions
42+
#include "DGtal/base/Common.h"
43+
//////////////////////////////////////////////////////////////////////////////
44+
namespace DGtal
45+
{
46+
/**
47+
* Output struct of @sa getSplit
48+
*
49+
* @tparam TPoint
50+
*/
51+
template<typename TPoint>
52+
struct SplitBounds {
53+
size_t splitIndex;
54+
TPoint lowerBound;
55+
TPoint upperBound;
56+
std::vector<unsigned int> splittedRegionIndex;
57+
};
58+
59+
namespace functions {
60+
/**
61+
* Compute the number of splits given a region defined by lowerBound and upperBound
62+
*
63+
* @tparam TPoint point type for lower and upper bound
64+
* @param[in] requested_number_of_splits number of splits (the actual splits might be less)
65+
* @param[in] lowerBound the lower bound point of the domain
66+
* @param[in] upperBound the upper bound point of the domain
67+
* @param[in,out] splits the splits for each dimension
68+
* For example, initialize splits with a std::vector, and use data to get the raw array
69+
* needed for this function.
70+
* @code
71+
* std::vector<unsigned int> splits(dimension);
72+
* auto number_of_splits = computeSplits(requested_number_of_splits,
73+
* lowerBound, upperBound, splits.data());
74+
* @endcode
75+
*
76+
* @return number of splits, lesser or equal than requested_number_of_splits
77+
*/
78+
template <typename TPoint>
79+
size_t computeSplits(
80+
const size_t requested_number_of_splits,
81+
const TPoint & lowerBound,
82+
const TPoint & upperBound,
83+
unsigned int splits[]);
84+
85+
/**
86+
* Get the ith split, where i has to be less than the number of splits
87+
* computed by @sa computeSplits.
88+
*
89+
* Returns two points corresponding to the output_lowerBound and output_upperRegion
90+
* of the ith split.
91+
*
92+
* @tparam TPoint point type for lower and upper bound
93+
* @param[in] splitIndex the ith split to be computed
94+
* @param[in] requested_number_of_splits number of splits (the actual splits might be less)
95+
* @param[in] lowerBound the lower bound point of the domain
96+
* @param[in] upperBound the upper bound point of the domain
97+
*
98+
* @return array containing output_lowerBound and output_upperBound
99+
*/
100+
template <typename TPoint>
101+
SplitBounds<TPoint> getSplit(
102+
const size_t splitIndex,
103+
const size_t requested_number_of_splits,
104+
const TPoint & lowerBound,
105+
const TPoint & upperBound);
106+
} // namespace functions
107+
108+
109+
/**
110+
* Return struct of @sa splitComplex
111+
*
112+
* Holds the splitted sub_complexes and information about the splits.
113+
*
114+
* @tparam TComplex Complex type
115+
*/
116+
template <typename TComplex>
117+
struct SplittedComplexes {
118+
/** Number of splits (might be less than the requested_number_of_splits) */
119+
size_t number_of_splits;
120+
/** Vector of sub_complexes, with the data copied from the original complex */
121+
std::vector<TComplex> sub_complexes;
122+
/** number of splits per dimension */
123+
std::vector<unsigned int> splits;
124+
/** Two points defining the domain of the splits */
125+
using PointsPair = std::array<typename TComplex::Point, 2>;
126+
/** Vector with the domains of the original splits. */
127+
std::vector<SplitBounds<typename TComplex::Point>> splits_bounds;
128+
};
129+
130+
namespace functions {
131+
132+
/**
133+
* Split a CubicalComplex (or VoxelComplex) into sub_complexes.
134+
*
135+
* @tparam TComplex
136+
* @param[in] vc input complex
137+
* @param[in] requested_number_of_splits (the actual splits might be less)
138+
*
139+
* @return SplittedComplexes with the sub_complexes and the splits domain
140+
*
141+
* @sa computeSplits
142+
* @sa getSplit
143+
*/
144+
template < typename TComplex >
145+
SplittedComplexes<TComplex>
146+
splitComplex(
147+
const TComplex & vc ,
148+
const size_t requested_number_of_splits
149+
);
150+
151+
/**
152+
* Get the number of blocks based on the splits
153+
*
154+
* @param splits vector with the number of splits per dimension,
155+
* i.e [2,2,1] means 1 division in x, and 1 divisions in y, and 0 in z, so 2 blocks.
156+
*
157+
* @return number of blocks
158+
*/
159+
inline size_t
160+
getNumberOfBorderBlocksFromSplits(const std::vector<unsigned int> & splits);
161+
/**
162+
* Get a vector of pair of points (block_lowerBound, block_upperBound)
163+
* from a domain represented by lowerBound and upperBound
164+
* and the number of splits per dimension.
165+
*
166+
* @tparam TPoint
167+
* @param lowerBound
168+
* @param upperBound
169+
* @param splits_bounds from SplittedComplexes @sa splitComplex
170+
* @param wide_of_block_sub_complex wide of the border, defaults to just
171+
* a plane in 3D, or a line in 2D.
172+
* If wide is greater than zero, the blocks are hypercubes around the original border.
173+
*
174+
* @return vector with border blocks defined by its lower and upper bounds
175+
* There is one border block per split in each dimension.
176+
*/
177+
template <typename TPoint>
178+
std::vector<std::array<TPoint, 2>>
179+
getBorderBlocksFromSplits(
180+
const TPoint & lowerBound,
181+
const TPoint & upperBound,
182+
const std::vector<SplitBounds<TPoint>> & splits_bounds,
183+
const size_t wide_of_block_sub_complex = 0
184+
);
185+
186+
187+
/**
188+
* Perform an union between out and each complex in complexes.
189+
* out |= complex;
190+
*
191+
* @tparam TComplex complex type
192+
* @param[in,out] out complex where the merge is stored
193+
* @param[in] complexes vector of complexes
194+
*/
195+
template < typename TComplex >
196+
void
197+
mergeSubComplexes(TComplex & out,
198+
const std::vector<TComplex> &complexes);
199+
200+
template < typename TComplex >
201+
TComplex
202+
extractSubComplex(
203+
const TComplex & vc ,
204+
const typename TComplex::Point & sub_lowerBound,
205+
const typename TComplex::Point & sub_upperBound
206+
);
207+
208+
/**
209+
* Given a cell and some boundaries, returns if the cell is in the border
210+
* or close to the border (if wide_point is used).
211+
*
212+
* Used internally in:
213+
* @sa getBorderVoxels, @sa getBorderVoxelsWithDistanceMap
214+
*
215+
* @tparam TComplex complex type
216+
* @param lowerBound the lowerBound of the hypercube defining a border (usually vc.lowerBound().
217+
* @param upperBound the upperBound of the hypercube defining a border (usually vc.upperBound().
218+
* @param wide_point the wide of the border (3D), defaults to nullptr, which is equivalent to {1,1,1}
219+
* it has to be greater than zero.
220+
* @param lowerBound_to_ignore lowerBound defining an hypercube of borders to ignore
221+
* @param upperBound_to_ignore upperBound defining an hypercube of borders to ignore
222+
*
223+
* @return true if cell is in the border, given the input parameters
224+
*/
225+
template < typename TComplex >
226+
bool
227+
isInBorder(
228+
const typename TComplex::KSpace::Cell & cell,
229+
const typename TComplex::Point & lowerBound,
230+
const typename TComplex::Point & upperBound,
231+
const typename TComplex::Point * wide_point = nullptr,
232+
const typename TComplex::Point * lowerBound_to_ignore = nullptr,
233+
const typename TComplex::Point * upperBound_to_ignore= nullptr
234+
);
235+
236+
/**
237+
* Get the voxels from the border of the input vc.
238+
* If lowerBound_to_ignore and upperBound_to_ignore are set, the borders
239+
* defined by those bounds are ignored.
240+
*
241+
* lowerBound and upperBound are usually the lower and upper bound
242+
* of the input complex vc, but they can also be changed to get the
243+
* borders of a smaller hypercube contained in vc.
244+
*
245+
* @tparam TComplex
246+
* @param vc input complex
247+
* @param lowerBound the lowerBound of the hypercube defining a border (usually vc.lowerBound().
248+
* @param upperBound the upperBound of the hypercube defining a border (usually vc.upperBound().
249+
* @param wide_point the wide of the border (3D), defaults to nullptr, which is equivalent to {1,1,1}
250+
* it has to be greater than zero.
251+
* @param lowerBound_to_ignore lowerBound defining an hypercube of borders to ignore
252+
* @param upperBound_to_ignore upperBound defining an hypercube of borders to ignore
253+
*
254+
* @return vector with iterators of the border
255+
*/
256+
template < typename TComplex >
257+
std::vector<typename TComplex::CellMapIterator>
258+
getBorderVoxels(
259+
TComplex & vc,
260+
const typename TComplex::Point & lowerBound,
261+
const typename TComplex::Point & upperBound,
262+
const typename TComplex::Point * wide_point = nullptr,
263+
const typename TComplex::Point * lowerBound_to_ignore = nullptr,
264+
const typename TComplex::Point * upperBound_to_ignore = nullptr
265+
);
266+
template < typename TComplex, typename TDistanceTransform >
267+
std::vector<typename TComplex::CellMapIterator>
268+
getBorderVoxelsWithDistanceMap(
269+
TComplex & vc,
270+
const typename TComplex::Point & lowerBound,
271+
const typename TComplex::Point & upperBound,
272+
const typename TComplex::Point * wide_point = nullptr,
273+
const typename TComplex::Point * lowerBound_to_ignore = nullptr,
274+
const typename TComplex::Point * upperBound_to_ignore = nullptr,
275+
const TDistanceTransform * dist_map = nullptr
276+
);
277+
278+
/**
279+
* Helper function to get the border voxels obtained from
280+
* @sa getBorderVoxels to the desired data.
281+
*
282+
* @tparam TComplex Complex type
283+
* @param vc input complex
284+
* @param border_iterators iterators from getBorderVoxels
285+
* @param data data of the cell to set in the border
286+
*/
287+
template < typename TComplex >
288+
void
289+
setBorderData(
290+
TComplex & vc,
291+
const std::vector<typename TComplex::CellMapIterator> &border_iterators,
292+
const DGtal::uint32_t &data);
293+
} // namespace functions
294+
} // namespace DGtal
295+
296+
///////////////////////////////////////////////////////////////////////////////
297+
// Includes inline functions.
298+
#include "DGtal/topology/SplitFunctions.ih"
299+
300+
// //
301+
///////////////////////////////////////////////////////////////////////////////
302+
303+
#endif // !defined SplitFunctions_h
304+
305+
#undef SplitFunctions_RECURSES
306+
#endif // else defined(SplitFunctions_RECURSES)

0 commit comments

Comments
 (0)