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