ViennaLS
Loading...
Searching...
No Matches
lsDetectFeatures.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <hrleCartesianPlaneIterator.hpp>
4#include <hrleSparseBoxIterator.hpp>
5#include <hrleSparseStarIterator.hpp>
8#include <lsDomain.hpp>
9
10#include <vcSmartPointer.hpp>
11#include <vcVectorUtil.hpp>
12
13namespace viennals {
14
15using namespace viennacore;
16
17enum struct FeatureDetectionEnum : unsigned {
18 CURVATURE = 0,
19 NORMALS_ANGLE = 1,
20};
21
27template <class T, int D> class DetectFeatures {
28 typedef typename Domain<T, D>::DomainType hrleDomainType;
29 SmartPointer<Domain<T, D>> levelSet = nullptr;
31 T flatLimit = 1.;
32 T flatLimit2 = 1.;
33 std::vector<T> flaggedCells;
34
35public:
36 static constexpr char featureMarkersLabel[] = "FeatureMarkers";
37
39
40 DetectFeatures(SmartPointer<Domain<T, D>> passedLevelSet)
41 : levelSet(passedLevelSet) {}
42
43 DetectFeatures(SmartPointer<Domain<T, D>> passedLevelSet, T passedLimit)
44 : levelSet(passedLevelSet), flatLimit(passedLimit),
45 flatLimit2(flatLimit * flatLimit) {}
46
47 DetectFeatures(SmartPointer<Domain<T, D>> passedLevelSet, T passedLimit,
48 FeatureDetectionEnum passedMethod)
49 : levelSet(passedLevelSet), flatLimit(passedLimit),
50 flatLimit2(flatLimit * flatLimit), method(passedMethod) {}
51
52 void setDetectionThreshold(T threshold) {
53 flatLimit = threshold;
54 flatLimit2 = flatLimit * flatLimit;
55 }
56
61 method = passedMethod;
62 }
63
65 void apply() {
66 if (method == FeatureDetectionEnum::CURVATURE) {
67 FeatureDetectionCurvature();
68 } else {
69 FeatureDetectionNormals();
70 }
71
72 // insert into pointData of levelSet
73 auto &pointData = levelSet->getPointData();
74 auto vectorDataPointer = pointData.getScalarData(featureMarkersLabel, true);
75 // if it does not exist, insert new feature vector
76 if (vectorDataPointer == nullptr) {
77 pointData.insertNextScalarData(flaggedCells, featureMarkersLabel);
78 } else {
79 // if it does exist, just swap the old with the new values
80 *vectorDataPointer = std::move(flaggedCells);
81 }
82 }
83
84private:
85 // Detects Features of the level set by calculating the absolute Curvature of
86 // each active grid point (levelset value <= 0.5). In 3D the Gaussian
87 // Curvature is also calculated to detect minimal surfaces. The minimal
88 // curvature value that should be considered a feature is passed to the
89 // constructor 0.0 Curvature describes a flat plane, the bigger the passed
90 // parameter gets the more grid points will be detected as features.
91 void FeatureDetectionCurvature() {
92 flaggedCells.clear();
93
94 auto grid = levelSet->getGrid();
95 typename Domain<T, D>::DomainType &domain = levelSet->getDomain();
96 std::vector<std::vector<T>> flagsReserve(levelSet->getNumberOfSegments());
97
98#pragma omp parallel num_threads((levelSet)->getNumberOfSegments())
99 {
100 int p = 0;
101#ifdef _OPENMP
102 p = omp_get_thread_num();
103#endif
104
105 auto &flagsSegment = flagsReserve[p];
106 flagsSegment.reserve(
107 levelSet->getDomain().getDomainSegment(p).getNumberOfPoints());
108
109 hrleVectorType<hrleIndexType, D> startVector =
110 (p == 0) ? grid.getMinGridPoint() : domain.getSegmentation()[p - 1];
111
112 hrleVectorType<hrleIndexType, D> endVector =
113 (p != static_cast<int>(domain.getNumberOfSegments() - 1))
114 ? domain.getSegmentation()[p]
115 : grid.incrementIndices(grid.getMaxGridPoint());
116
117 for (hrleCartesianPlaneIterator<typename Domain<T, D>::DomainType>
118 neighborIt(levelSet->getDomain(), startVector, 1);
119 neighborIt.getIndices() < endVector; neighborIt.next()) {
120
121 auto &center = neighborIt.getCenter();
122 if (!center.isDefined()) {
123 continue;
124 } else if (std::abs(center.getValue()) > 0.5) {
125 flagsSegment.push_back(0);
126 continue;
127 }
128
129 T curve = lsInternal::meanCurvature(neighborIt);
130 if (std::abs(curve) > flatLimit) {
131 flagsSegment.push_back(1);
132 } else {
133 if constexpr (D == 2) {
134 flagsSegment.push_back(0);
135 } else {
136 curve = lsInternal::gaussianCurvature(neighborIt);
137 if (std::abs(curve) > flatLimit2)
138 flagsSegment.push_back(1);
139 else
140 flagsSegment.push_back(0);
141 }
142 }
143 }
144 }
145
146 flaggedCells.reserve(levelSet->getNumberOfPoints());
147 for (unsigned i = 0; i < levelSet->getNumberOfSegments(); ++i)
148 flaggedCells.insert(flaggedCells.end(), flagsReserve[i].begin(),
149 flagsReserve[i].end());
150 }
151
152 // Detects Features of the level set by comparing the angle of each normal
153 // vector on the surface to its adjacent normal vectors. The minimal angle
154 // that should be considered a feature is passed to the class constructor.
155 void FeatureDetectionNormals() {
156 // Clear results from previous run
157 flaggedCells.clear();
158
159 auto &grid = levelSet->getGrid();
160 auto &domain = levelSet->getDomain();
161 T cosAngleTreshold = std::cos(flatLimit);
162
163 // CALCULATE NORMALS
164 Expand<T, D>(levelSet, 3).apply();
165 CalculateNormalVectors<T, D>(levelSet).apply();
166 const auto &normals = *(levelSet->getPointData().getVectorData(
168
169 std::vector<std::vector<T>> flagsReserve(levelSet->getNumberOfSegments());
170
171 // Compare angles between normal vectors
172#pragma omp parallel num_threads((levelSet)->getNumberOfSegments())
173 {
174 int p = 0;
175#ifdef _OPENMP
176 p = omp_get_thread_num();
177#endif
178
179 Vec3D<T> zeroVector{};
180
181 std::vector<T> &flagsSegment = flagsReserve[p];
182 flagsSegment.reserve(
183 levelSet->getDomain().getDomainSegment(p).getNumberOfPoints());
184
185 hrleVectorType<hrleIndexType, D> startVector =
186 (p == 0) ? grid.getMinGridPoint() : domain.getSegmentation()[p - 1];
187
188 hrleVectorType<hrleIndexType, D> endVector =
189 (p != static_cast<int>(domain.getNumberOfSegments() - 1))
190 ? domain.getSegmentation()[p]
191 : grid.incrementIndices(grid.getMaxGridPoint());
192
193 for (hrleSparseBoxIterator<typename Domain<T, D>::DomainType> neighborIt(
194 levelSet->getDomain(), startVector, 1);
195 neighborIt.getIndices() < endVector; neighborIt.next()) {
196 if (!neighborIt.getCenter().isDefined()) {
197 continue;
198 } else if (std::abs(neighborIt.getCenter().getValue()) >= 0.5) {
199 flagsSegment.push_back(0);
200 continue;
201 }
202
203 Vec3D<T> centerNormal = normals[neighborIt.getCenter().getPointId()];
204
205 bool flag = false;
206
207 for (unsigned dir = 0; dir < (D * D * D); dir++) {
208 Vec3D<T> currentNormal =
209 normals[neighborIt.getNeighbor(dir).getPointId()];
210
211 if (currentNormal != zeroVector) {
212 T skp = 0.;
213 // Calculate scalar product
214 for (int j = 0; j < D; j++) {
215 skp += currentNormal[j] * centerNormal[j];
216 }
217 // Vectors are normlized so skp = cos(alpha)
218 if ((cosAngleTreshold - skp) >= 0.) {
219 flag = true;
220 break;
221 }
222 }
223 }
224
225 if (flag) {
226 flagsSegment.push_back(1);
227 } else {
228 flagsSegment.push_back(0);
229 }
230 }
231 }
232
233 for (unsigned i = 0; i < levelSet->getNumberOfSegments(); ++i)
234 flaggedCells.insert(flaggedCells.end(), flagsReserve[i].begin(),
235 flagsReserve[i].end());
236 }
237};
238
239} // namespace viennals
static constexpr char normalVectorsLabel[]
Definition lsCalculateNormalVectors.hpp:31
This class detects features of the level set function. This class offers two methods to determine fea...
Definition lsDetectFeatures.hpp:27
DetectFeatures(SmartPointer< Domain< T, D > > passedLevelSet, T passedLimit, FeatureDetectionEnum passedMethod)
Definition lsDetectFeatures.hpp:47
static constexpr char featureMarkersLabel[]
Definition lsDetectFeatures.hpp:36
void apply()
Execute the algorithm.
Definition lsDetectFeatures.hpp:65
void setDetectionThreshold(T threshold)
Definition lsDetectFeatures.hpp:52
void setDetectionMethod(FeatureDetectionEnum passedMethod)
Set which algorithm to use to detect features. The curvature-based algorithm should always be preferr...
Definition lsDetectFeatures.hpp:60
DetectFeatures(SmartPointer< Domain< T, D > > passedLevelSet, T passedLimit)
Definition lsDetectFeatures.hpp:43
DetectFeatures(SmartPointer< Domain< T, D > > passedLevelSet)
Definition lsDetectFeatures.hpp:40
DetectFeatures()
Definition lsDetectFeatures.hpp:38
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28
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
DomainType & getDomain()
get const reference to the underlying hrleDomain data structure
Definition lsDomain.hpp:144
T gaussianCurvature(It &it, bool bigStencil=false)
Calculates the Gaussian Curvature of the level set function from a suitable hrle iterator....
Definition lsCurvatureFormulas.hpp:181
T meanCurvature(It &it, bool bigStencil=false)
Calculates the Mean Curvature of the level set function from a suitable hrle iterator....
Definition lsCurvatureFormulas.hpp:161
Definition lsAdvect.hpp:46
FeatureDetectionEnum
Definition lsDetectFeatures.hpp:17
constexpr int D
Definition pyWrap.cpp:65
double T
Definition pyWrap.cpp:63