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