ViennaLS
Loading...
Searching...
No Matches
lsBooleanOperation.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <hrleSparseStarIterator.hpp>
6#include <hrleVectorType.hpp>
7
8#include <lsDomain.hpp>
9#include <lsPrune.hpp>
10
11#include <vcLogger.hpp>
12#include <vcSmartPointer.hpp>
13
14namespace viennals {
15
16using namespace viennacore;
17
25enum struct BooleanOperationEnum : unsigned {
26 INTERSECT = 0,
27 UNION = 1,
29 INVERT = 3,
30 CUSTOM = 4
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 hrleVectorType<hrleIndexType, D> currentVector =
84 (p == 0) ? grid.getMinGridPoint()
85 : newDomain.getSegmentation()[p - 1];
86
87 hrleVectorType<hrleIndexType, D> endVector =
88 (p != static_cast<int>(newDomain.getNumberOfSegments() - 1))
89 ? newDomain.getSegmentation()[p]
90 : grid.incrementIndices(grid.getMaxGridPoint());
91
92 hrleConstSparseIterator<hrleDomainType> itA(levelSetA->getDomain(),
93 currentVector);
94 hrleConstSparseIterator<hrleDomainType> itB(levelSetB->getDomain(),
95 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 = std::max(itA.getStartIndices(), itB.getStartIndices());
128 }
129 }
130
131 // merge data
132 for (unsigned i = 1; i < newDataLS.size(); ++i) {
133 newDataLS[0].insert(newDataLS[0].end(), newDataLS[i].begin(),
134 newDataLS[i].end());
135
136 newDataSourceIds[0].insert(newDataSourceIds[0].end(),
137 newDataSourceIds[i].begin(),
138 newDataSourceIds[i].end());
139 }
140
141 // transfer data from the old LSs to new LS
142 // Only do so if the same data exists in both LSs
143 // If this is not the case, the data is invalid
144 // and therefore not needed anyway.
145 if (updateData) {
146 const auto &AData = levelSetA->getPointData();
147 const auto &BData = levelSetB->getPointData();
148 auto &newData = newlsDomain->getPointData();
149
150 // scalars
151 for (unsigned i = 0; i < AData.getScalarDataSize(); ++i) {
152 auto scalarDataLabel = AData.getScalarDataLabel(i);
153 auto BPointer = BData.getScalarData(scalarDataLabel, true);
154 if (BPointer != nullptr) {
155 auto APointer = AData.getScalarData(i);
156 // copy all data into the new scalarData
158 scalars.resize(newlsDomain->getNumberOfPoints());
159 for (unsigned j = 0; j < newlsDomain->getNumberOfPoints(); ++j) {
160 scalars[j] = (newDataLS[0][j])
161 ? APointer->at(newDataSourceIds[0][j])
162 : BPointer->at(newDataSourceIds[0][j]);
163 }
164 newData.insertNextScalarData(scalars, scalarDataLabel);
165 }
166 }
167
168 // vectors
169 for (unsigned i = 0; i < AData.getVectorDataSize(); ++i) {
170 auto vectorDataLabel = AData.getVectorDataLabel(i);
171 auto BPointer = BData.getVectorData(vectorDataLabel, true);
172 if (BPointer != nullptr) {
173 auto APointer = AData.getVectorData(i);
174 // copy all data into the new vectorData
176 vectors.resize(newlsDomain->getNumberOfPoints());
177 for (unsigned j = 0; j < newlsDomain->getNumberOfPoints(); ++j) {
178 vectors[j] = (newDataLS[0][j])
179 ? APointer->at(newDataSourceIds[0][j])
180 : BPointer->at(newDataSourceIds[0][j]);
181 }
182 newData.insertNextVectorData(vectors, vectorDataLabel);
183 }
184 }
185 }
186
187 newDomain.finalize();
188 newDomain.segment();
189 newlsDomain->setLevelSetWidth(levelSetA->getLevelSetWidth());
190
191 if (pruneResult) {
192 auto pruner = Prune<T, D>(newlsDomain);
193 pruner.setRemoveStrayZeros(true);
194 pruner.apply();
195
196 // now we need to prune, to remove stray defined points
197 Prune<T, D>(newlsDomain).apply();
198 }
199
200 levelSetA->deepCopy(newlsDomain);
201 }
202
203 void invert() {
204 auto &hrleDomain = levelSetA->getDomain();
205#pragma omp parallel num_threads(hrleDomain.getNumberOfSegments())
206 {
207 int p = 0;
208#ifdef _OPENMP
209 p = omp_get_thread_num();
210#endif
211 auto &domainSegment = hrleDomain.getDomainSegment(p);
212
213 // change all defined values
214 for (unsigned i = 0; i < domainSegment.definedValues.size(); ++i) {
215 domainSegment.definedValues[i] = -domainSegment.definedValues[i];
216 }
217
218 // add undefined values if missing
219 if (domainSegment.undefinedValues.size() < 1) {
220 domainSegment.undefinedValues.push_back(T(Domain<T, D>::NEG_VALUE));
221 }
222 if (domainSegment.undefinedValues.size() < 2) {
223 if (domainSegment.undefinedValues[0] == Domain<T, D>::NEG_VALUE) {
224 domainSegment.undefinedValues.push_back(T(Domain<T, D>::POS_VALUE));
225 } else {
226 domainSegment.undefinedValues.push_back(T(Domain<T, D>::NEG_VALUE));
227 }
228 }
229
230 // change all runTypes
231 // there are only two undefined runs: negative undefined (UNDEF_PT)
232 // and positive undefined (UNDEF_PT+1)
233 for (unsigned dim = 0; dim < D; ++dim) {
234 for (unsigned c = 0; c < domainSegment.runTypes[dim].size(); ++c) {
235 if (domainSegment.runTypes[dim][c] == hrleRunTypeValues::UNDEF_PT) {
236 domainSegment.runTypes[dim][c] = hrleRunTypeValues::UNDEF_PT + 1;
237 } else if (domainSegment.runTypes[dim][c] ==
238 hrleRunTypeValues::UNDEF_PT + 1) {
239 domainSegment.runTypes[dim][c] = hrleRunTypeValues::UNDEF_PT;
240 }
241 }
242 }
243 }
244 levelSetA->finalize();
245 }
246
247 static std::pair<T, bool> minComp(const T &a, const T &b) {
248 bool AIsSmaller = a < b;
249 if (AIsSmaller)
250 return std::make_pair(a, true);
251 else
252 return std::make_pair(b, false);
253 }
254
255 static std::pair<T, bool> maxComp(const T &a, const T &b) {
256 bool AIsLarger = a > b;
257 if (AIsLarger)
258 return std::make_pair(a, true);
259 else
260 return std::make_pair(b, false);
261 }
262
263 static std::pair<T, bool> relativeComplementComp(const T &a, const T &b) {
264 return maxComp(a, -b);
265 }
266
267public:
269
271 SmartPointer<Domain<T, D>> passedlsDomain,
273 : levelSetA(passedlsDomain), operation(passedOperation) {}
274
276 SmartPointer<Domain<T, D>> passedlsDomainA,
277 SmartPointer<Domain<T, D>> passedlsDomainB,
279 : levelSetA(passedlsDomainA), levelSetB(passedlsDomainB),
280 operation(passedOperation){};
281
283 void setLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
284 levelSetA = passedlsDomain;
285 }
286
289 void setSecondLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
290 levelSetB = passedlsDomain;
291 }
292
295 operation = passedOperation;
296 }
297
301 operationComp = passedOperationComp;
302 }
303
306 void setUpdatePointData(bool update) { updatePointData = update; }
307
309 void setPruneResult(bool pR) { pruneResult = pR; }
310
312 void apply() {
313 if (levelSetA == nullptr) {
314 Logger::getInstance()
315 .addWarning("No level set was passed to BooleanOperation. Not "
316 "performing operation.")
317 .print();
318 return;
319 }
320
321 if (static_cast<unsigned>(operation) < 3) {
322 if (levelSetB == nullptr) {
323 Logger::getInstance()
324 .addWarning("Only one level set was passed to BooleanOperation, "
325 "although two were required. Not performing operation.")
326 .print();
327 return;
328 }
329 }
330
331 switch (operation) {
333 booleanOpInternal(&BooleanOperation::maxComp);
334 break;
336 booleanOpInternal(&BooleanOperation::minComp);
337 break;
339 booleanOpInternal(&BooleanOperation::relativeComplementComp);
340 break;
342 invert();
343 break;
345 if (operationComp == nullptr) {
346 Logger::getInstance()
347 .addWarning("No comparator supplied to custom BooleanOperation. "
348 "Not performing operation.")
349 .print();
350 return;
351 }
352 booleanOpInternal(operationComp);
353 }
354 }
355};
356
357// add all template specialisations for this class
358PRECOMPILE_PRECISION_DIMENSION(BooleanOperation)
359
360} // namespace viennals
This class is used to perform boolean operations on two level sets and write the resulting level set ...
Definition lsBooleanOperation.hpp:43
void setBooleanOperationComparator(ComparatorType passedOperationComp)
Set the comparator to be used when the BooleanOperation is set to CUSTOM.
Definition lsBooleanOperation.hpp:300
void setUpdatePointData(bool update)
Set whether to update the point data stored in the LS during this algorithm. Defaults to true.
Definition lsBooleanOperation.hpp:306
void setPruneResult(bool pR)
Set whether the resulting level set should be pruned. Defaults to true.
Definition lsBooleanOperation.hpp:309
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:283
BooleanOperation(SmartPointer< Domain< T, D > > passedlsDomain, BooleanOperationEnum passedOperation=BooleanOperationEnum::INVERT)
Definition lsBooleanOperation.hpp:270
BooleanOperation()
Definition lsBooleanOperation.hpp:268
void setSecondLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Set the level set which will be used to modify the first level set.
Definition lsBooleanOperation.hpp:289
void setBooleanOperation(BooleanOperationEnum passedOperation)
Set which of the operations of BooleanOperationEnum to perform.
Definition lsBooleanOperation.hpp:294
void apply()
Perform operation.
Definition lsBooleanOperation.hpp:312
BooleanOperation(SmartPointer< Domain< T, D > > passedlsDomainA, SmartPointer< Domain< T, D > > passedlsDomainB, BooleanOperationEnum passedOperation=BooleanOperationEnum::INTERSECT)
Definition lsBooleanOperation.hpp:275
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28
static constexpr T NEG_VALUE
Definition lsDomain.hpp:55
unsigned getNumberOfSegments() const
returns the number of segments, the levelset is split into. This is useful for algorithm parallelisat...
Definition lsDomain.hpp:150
hrleDomain< T, D > DomainType
Definition lsDomain.hpp:33
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:114
static constexpr T POS_VALUE
Definition lsDomain.hpp:54
void setLevelSetWidth(int width)
Definition lsDomain.hpp:157
std::vector< T > ScalarDataType
Definition lsPointData.hpp:22
std::vector< std::array< T, 3 > > VectorDataType
Definition lsPointData.hpp:23
Removes all level set points, which do not have at least one oppositely signed neighbour (Meaning the...
Definition lsPrune.hpp:19
void apply()
removes all grid points, which do not have at least one opposite signed neighbour returns the number ...
Definition lsPrune.hpp:76
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:46
BooleanOperationEnum
Enumeration for the different types of boolean operations which are supported. When INVERT,...
Definition lsBooleanOperation.hpp:25
constexpr int D
Definition pyWrap.cpp:65
double T
Definition pyWrap.cpp:63