ViennaLS
Loading...
Searching...
No Matches
lsBooleanOperation.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <hrleSparseStarIterator.hpp>
6
7#include <lsDomain.hpp>
8#include <lsPrune.hpp>
9
10#include <vcLogger.hpp>
11#include <vcSmartPointer.hpp>
12#include <vcVectorType.hpp>
13
14#include <functional>
15
16namespace viennals {
17
18using namespace viennacore;
19
27enum struct BooleanOperationEnum : unsigned {
29 UNION = 1,
31 INVERT = 3,
33};
34
45template <class T, int D> class BooleanOperation {
46public:
48 std::function<std::pair<T, bool>(const T &, const T &)>;
49
50private:
51 typedef typename Domain<T, D>::DomainType hrleDomainType;
52 SmartPointer<Domain<T, D>> levelSetA = nullptr;
53 SmartPointer<Domain<T, D>> levelSetB = nullptr;
55 ComparatorType operationComp = nullptr;
56 bool updatePointData = true;
57 bool pruneResult = true;
58
59 void booleanOpInternal(ComparatorType comp) {
60 auto &grid = levelSetA->getGrid();
61 auto newlsDomain = SmartPointer<Domain<T, D>>::New(grid);
62 typename Domain<T, D>::DomainType &newDomain = newlsDomain->getDomain();
63 typename Domain<T, D>::DomainType &domain = levelSetA->getDomain();
64
65 newDomain.initialize(domain.getNewSegmentation(), domain.getAllocation());
66
67 const bool updateData = updatePointData;
68 // save how data should be transferred to new level set
69 // list of indices into the old pointData vector
70 std::vector<std::vector<unsigned>> newDataSourceIds;
71 std::vector<std::vector<bool>> newDataLS;
72 if (updateData) {
73 newDataSourceIds.resize(newDomain.getNumberOfSegments());
74 newDataLS.resize(newDataSourceIds.size());
75 }
76
77#pragma omp parallel num_threads(newDomain.getNumberOfSegments())
78 {
79 int p = 0;
80#ifdef _OPENMP
81 p = omp_get_thread_num();
82#endif
83
84 auto &domainSegment = newDomain.getDomainSegment(p);
85
86 viennahrle::Index<D> currentVector =
87 (p == 0) ? grid.getMinGridPoint()
88 : newDomain.getSegmentation()[p - 1];
89
90 viennahrle::Index<D> const endVector =
91 (p != static_cast<int>(newDomain.getNumberOfSegments() - 1))
92 ? newDomain.getSegmentation()[p]
93 : grid.incrementIndices(grid.getMaxGridPoint());
94
95 viennahrle::ConstSparseIterator<hrleDomainType> itA(
96 levelSetA->getDomain(), currentVector);
97 viennahrle::ConstSparseIterator<hrleDomainType> itB(
98 levelSetB->getDomain(), currentVector);
99
100 while (currentVector < endVector) {
101 const auto &comparison = comp(itA.getValue(), itB.getValue());
102 const auto &currentValue = comparison.first;
103
104 if (currentValue != Domain<T, D>::NEG_VALUE &&
105 currentValue != Domain<T, D>::POS_VALUE) {
106 domainSegment.insertNextDefinedPoint(currentVector, currentValue);
107 if (updateData) {
108 // if taken from A, set to true
109 const bool originLS = comparison.second;
110 newDataLS[p].push_back(originLS);
111 const auto originPointId =
112 (originLS) ? itA.getPointId() : itB.getPointId();
113 newDataSourceIds[p].push_back(originPointId);
114 }
115 } else {
116 domainSegment.insertNextUndefinedPoint(
117 currentVector, (currentValue < 0) ? Domain<T, D>::NEG_VALUE
119 }
120
121 switch (Compare(itA.getEndIndices(), itB.getEndIndices())) {
122 case -1:
123 itA.next();
124 break;
125 case 0:
126 itA.next();
127 default:
128 itB.next();
129 }
130 currentVector =
131 Max(itA.getStartIndices().get(), itB.getStartIndices().get());
132 }
133 }
134
135 // merge data
136 for (unsigned i = 1; i < newDataLS.size(); ++i) {
137 newDataLS[0].insert(newDataLS[0].end(), newDataLS[i].begin(),
138 newDataLS[i].end());
139
140 newDataSourceIds[0].insert(newDataSourceIds[0].end(),
141 newDataSourceIds[i].begin(),
142 newDataSourceIds[i].end());
143 }
144
145 // transfer data from the old LSs to new LS
146 // Only do so if the same data exists in both LSs
147 // If this is not the case, the data is invalid
148 // and therefore not needed anyway.
149 if (updateData) {
150 const auto &AData = levelSetA->getPointData();
151 const auto &BData = levelSetB->getPointData();
152 auto &newData = newlsDomain->getPointData();
153
154 // scalars
155 for (unsigned i = 0; i < AData.getScalarDataSize(); ++i) {
156 auto scalarDataLabel = AData.getScalarDataLabel(i);
157 auto BPointer = BData.getScalarData(scalarDataLabel, true);
158 if (BPointer != nullptr) {
159 auto APointer = AData.getScalarData(i);
160 // copy all data into the new scalarData
162 scalars.resize(newlsDomain->getNumberOfPoints());
163 for (unsigned j = 0; j < newlsDomain->getNumberOfPoints(); ++j) {
164 scalars[j] = (newDataLS[0][j])
165 ? APointer->at(newDataSourceIds[0][j])
166 : BPointer->at(newDataSourceIds[0][j]);
167 }
168 newData.insertNextScalarData(scalars, scalarDataLabel);
169 }
170 }
171
172 // vectors
173 for (unsigned i = 0; i < AData.getVectorDataSize(); ++i) {
174 auto vectorDataLabel = AData.getVectorDataLabel(i);
175 auto BPointer = BData.getVectorData(vectorDataLabel, true);
176 if (BPointer != nullptr) {
177 auto APointer = AData.getVectorData(i);
178 // copy all data into the new vectorData
180 vectors.resize(newlsDomain->getNumberOfPoints());
181 for (unsigned j = 0; j < newlsDomain->getNumberOfPoints(); ++j) {
182 vectors[j] = (newDataLS[0][j])
183 ? APointer->at(newDataSourceIds[0][j])
184 : BPointer->at(newDataSourceIds[0][j]);
185 }
186 newData.insertNextVectorData(vectors, vectorDataLabel);
187 }
188 }
189 }
190
191 newDomain.finalize();
192 newDomain.segment();
193 newlsDomain->setLevelSetWidth(levelSetA->getLevelSetWidth());
194
195 if (pruneResult) {
196 auto pruner = Prune<T, D>(newlsDomain);
197 pruner.setRemoveStrayZeros(true);
198 pruner.apply();
199
200 // now we need to prune, to remove stray defined points
201 Prune<T, D>(newlsDomain).apply();
202 }
203
204 levelSetA->deepCopy(newlsDomain);
205 }
206
207 void invert() {
208 auto &hrleDomain = levelSetA->getDomain();
209#pragma omp parallel num_threads(hrleDomain.getNumberOfSegments())
210 {
211 int p = 0;
212#ifdef _OPENMP
213 p = omp_get_thread_num();
214#endif
215 auto &domainSegment = hrleDomain.getDomainSegment(p);
216
217 // change all defined values
218 for (unsigned i = 0; i < domainSegment.definedValues.size(); ++i) {
219 domainSegment.definedValues[i] = -domainSegment.definedValues[i];
220 }
221
222 // add undefined values if missing
223 if (domainSegment.undefinedValues.size() < 1) {
224 domainSegment.undefinedValues.push_back(T(Domain<T, D>::NEG_VALUE));
225 }
226 if (domainSegment.undefinedValues.size() < 2) {
227 if (domainSegment.undefinedValues[0] == Domain<T, D>::NEG_VALUE) {
228 domainSegment.undefinedValues.push_back(T(Domain<T, D>::POS_VALUE));
229 } else {
230 domainSegment.undefinedValues.push_back(T(Domain<T, D>::NEG_VALUE));
231 }
232 }
233
234 // change all runTypes
235 // there are only two undefined runs: negative undefined (UNDEF_PT)
236 // and positive undefined (UNDEF_PT+1)
237 for (unsigned dim = 0; dim < D; ++dim) {
238 for (unsigned c = 0; c < domainSegment.runTypes[dim].size(); ++c) {
239 if (domainSegment.runTypes[dim][c] ==
240 viennahrle::RunTypeValues::UNDEF_PT) {
241 domainSegment.runTypes[dim][c] =
242 viennahrle::RunTypeValues::UNDEF_PT + 1;
243 } else if (domainSegment.runTypes[dim][c] ==
244 viennahrle::RunTypeValues::UNDEF_PT + 1) {
245 domainSegment.runTypes[dim][c] =
246 viennahrle::RunTypeValues::UNDEF_PT;
247 }
248 }
249 }
250 }
251 levelSetA->finalize();
252 }
253
254 static std::pair<T, bool> minComp(const T &a, const T &b) {
255 bool AIsSmaller = a < b;
256 if (AIsSmaller)
257 return std::make_pair(a, true);
258 else
259 return std::make_pair(b, false);
260 }
261
262 static std::pair<T, bool> maxComp(const T &a, const T &b) {
263 bool AIsLarger = a > b;
264 if (AIsLarger)
265 return std::make_pair(a, true);
266 else
267 return std::make_pair(b, false);
268 }
269
270 static std::pair<T, bool> relativeComplementComp(const T &a, const T &b) {
271 return maxComp(a, -b);
272 }
273
274public:
275 BooleanOperation() = default;
276
278 SmartPointer<Domain<T, D>> passedlsDomain,
280 : levelSetA(passedlsDomain), operation(passedOperation) {}
281
283 SmartPointer<Domain<T, D>> passedlsDomainA,
284 SmartPointer<Domain<T, D>> passedlsDomainB,
286 : levelSetA(passedlsDomainA), levelSetB(passedlsDomainB),
287 operation(passedOperation){};
288
290 void setLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
291 levelSetA = passedlsDomain;
292 }
293
296 void setSecondLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
297 levelSetB = passedlsDomain;
298 }
299
302 operation = passedOperation;
303 }
304
308 operationComp = passedOperationComp;
309 }
310
313 void setUpdatePointData(bool update) { updatePointData = update; }
314
316 void setPruneResult(bool pR) { pruneResult = pR; }
317
319 void apply() {
320 if (levelSetA == nullptr) {
321 VIENNACORE_LOG_ERROR("No level set was passed to BooleanOperation.");
322 return;
323 }
324
325 if (static_cast<unsigned>(operation) < 3) {
326 if (levelSetB == nullptr) {
327 VIENNACORE_LOG_ERROR(
328 "Only one level set was passed to BooleanOperation, "
329 "although two were required.");
330 return;
331 }
332 }
333
334 switch (operation) {
336 booleanOpInternal(&BooleanOperation::maxComp);
337 break;
339 booleanOpInternal(&BooleanOperation::minComp);
340 break;
342 booleanOpInternal(&BooleanOperation::relativeComplementComp);
343 break;
345 invert();
346 break;
348 if (operationComp == nullptr) {
349 VIENNACORE_LOG_ERROR(
350 "No comparator supplied to custom BooleanOperation.");
351 return;
352 }
353 booleanOpInternal(operationComp);
354 }
355 }
356};
357
358// add all template specialisations for this class
359PRECOMPILE_PRECISION_DIMENSION(BooleanOperation)
360
361} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
void setBooleanOperationComparator(ComparatorType passedOperationComp)
Set the comparator to be used when the BooleanOperation is set to CUSTOM.
Definition lsBooleanOperation.hpp:307
void setUpdatePointData(bool update)
Set whether to update the point data stored in the LS during this algorithm. Defaults to true.
Definition lsBooleanOperation.hpp:313
void setPruneResult(bool pR)
Set whether the resulting level set should be pruned. Defaults to true.
Definition lsBooleanOperation.hpp:316
void setLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Set which level set to perform the boolean operation on.
Definition lsBooleanOperation.hpp:290
BooleanOperation(SmartPointer< Domain< T, D > > passedlsDomain, BooleanOperationEnum passedOperation=BooleanOperationEnum::INVERT)
Definition lsBooleanOperation.hpp:277
std::function< std::pair< T, bool >(const T &, const T &)> ComparatorType
Definition lsBooleanOperation.hpp:47
void setSecondLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Set the level set which will be used to modify the first level set.
Definition lsBooleanOperation.hpp:296
void setBooleanOperation(BooleanOperationEnum passedOperation)
Set which of the operations of BooleanOperationEnum to perform.
Definition lsBooleanOperation.hpp:301
void apply()
Perform operation.
Definition lsBooleanOperation.hpp:319
BooleanOperation(SmartPointer< Domain< T, D > > passedlsDomainA, SmartPointer< Domain< T, D > > passedlsDomainB, BooleanOperationEnum passedOperation=BooleanOperationEnum::INTERSECT)
Definition lsBooleanOperation.hpp:282
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28
viennahrle::Domain< T, D > DomainType
Definition lsDomain.hpp:33
static constexpr T NEG_VALUE
Definition lsDomain.hpp:53
unsigned getNumberOfSegments() const
returns the number of segments, the levelset is split into. This is useful for algorithm parallelisat...
Definition lsDomain.hpp:154
void finalize(int newWidth)
this function sets a new levelset width and finalizes the levelset, so it is ready for use by other a...
Definition lsDomain.hpp:118
static constexpr T POS_VALUE
Definition lsDomain.hpp:52
void setLevelSetWidth(int width)
Definition lsDomain.hpp:161
std::vector< Vec3D< T > > VectorDataType
Definition lsPointData.hpp:25
std::vector< T > ScalarDataType
Definition lsPointData.hpp:24
Removes all level set points, which do not have at least one oppositely signed neighbour (Meaning the...
Definition lsPrune.hpp:17
void apply()
removes all grid points, which do not have at least one opposite signed neighbour returns the number ...
Definition lsPrune.hpp:74
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41
BooleanOperationEnum
Enumeration for the different types of boolean operations which are supported. When INVERT,...
Definition lsBooleanOperation.hpp:27
@ INTERSECT
Definition lsBooleanOperation.hpp:28
@ CUSTOM
Definition lsBooleanOperation.hpp:32
@ INVERT
Definition lsBooleanOperation.hpp:31
@ RELATIVE_COMPLEMENT
Definition lsBooleanOperation.hpp:30
@ UNION
Definition lsBooleanOperation.hpp:29