ViennaLS
Loading...
Searching...
No Matches
lsCalculateNormalVectors.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <algorithm>
6
7#include <hrleSparseStarIterator.hpp>
8
9#include <lsDomain.hpp>
10#include <lsExpand.hpp>
11
12#include <vcLogger.hpp>
13#include <vcSmartPointer.hpp>
14#include <vcVectorType.hpp>
15
16namespace viennals {
17
18using namespace viennacore;
19
35template <class T, int D> class CalculateNormalVectors {
36 SmartPointer<Domain<T, D>> levelSet = nullptr;
37 T maxValue = 0.5;
38
39 // Constants for calculation
40 static constexpr T DEFAULT_MAX_VALUE = 0.5;
41 static constexpr T EPSILON = 1e-12;
42 static constexpr T FINITE_DIFF_FACTOR = 0.5;
43
44public:
45 static constexpr char normalVectorsLabel[] = "Normals";
46
48
49 CalculateNormalVectors(SmartPointer<Domain<T, D>> passedLevelSet,
50 T passedMaxValue = DEFAULT_MAX_VALUE)
51 : levelSet(passedLevelSet), maxValue(passedMaxValue) {}
52
53 void setLevelSet(SmartPointer<Domain<T, D>> passedLevelSet) {
54 levelSet = passedLevelSet;
55 }
56
57 void setMaxValue(const T passedMaxValue) {
58 if (passedMaxValue <= 0) {
59 Logger::getInstance()
60 .addWarning("CalculateNormalVectors: maxValue should be positive. "
61 "Using default value " +
62 std::to_string(DEFAULT_MAX_VALUE) + ".")
63 .print();
64 maxValue = DEFAULT_MAX_VALUE;
65 } else {
66 maxValue = passedMaxValue;
67 }
68 }
69
70 SmartPointer<Domain<T, D>> getLevelSet() const { return levelSet; }
71
72 T getMaxValue() const { return maxValue; }
73
75 bool hasNormalVectors() const {
76 if (levelSet == nullptr)
77 return false;
78 auto &pointData = levelSet->getPointData();
79 return pointData.getVectorData(normalVectorsLabel) != nullptr;
80 }
81
82 void apply() {
83 if (levelSet == nullptr) {
84 Logger::getInstance()
85 .addError("No level set was passed to CalculateNormalVectors.")
86 .print();
87 return;
88 }
89
90 if (levelSet->getLevelSetWidth() < (maxValue * 4) + 1) {
91 Logger::getInstance()
92 .addWarning("CalculateNormalVectors: Level set width must be "
93 "greater than " +
94 std::to_string((maxValue * 4) + 1) +
95 ". Expanding level set to " +
96 std::to_string((maxValue * 4) + 1) + ".")
97 .print();
98 Expand<T, D>(levelSet, (maxValue * 4) + 1).apply();
99 }
100
101 std::vector<std::vector<Vec3D<T>>> normalVectorsVector(
102 levelSet->getNumberOfSegments());
103
104 // Estimate memory requirements per thread to improve cache performance
105 double pointsPerSegment =
106 double(2 * levelSet->getDomain().getNumberOfPoints()) /
107 double(levelSet->getLevelSetWidth());
108
109 auto grid = levelSet->getGrid();
110
111 // Calculate Normalvectors
112#pragma omp parallel num_threads(levelSet->getNumberOfSegments())
113 {
114 int p = 0;
115#ifdef _OPENMP
116 p = omp_get_thread_num();
117#endif
118
119 auto &normalVectors = normalVectorsVector[p];
120 normalVectors.reserve(pointsPerSegment);
121
122 viennahrle::Index<D> const startVector =
123 (p == 0) ? grid.getMinGridPoint()
124 : levelSet->getDomain().getSegmentation()[p - 1];
125
126 viennahrle::Index<D> const endVector =
127 (p != static_cast<int>(levelSet->getNumberOfSegments() - 1))
128 ? levelSet->getDomain().getSegmentation()[p]
129 : grid.incrementIndices(grid.getMaxGridPoint());
130
131 for (viennahrle::ConstSparseStarIterator<
132 typename Domain<T, D>::DomainType, 1>
133 neighborIt(levelSet->getDomain(), startVector);
134 neighborIt.getIndices() < endVector; neighborIt.next()) {
135
136 auto &center = neighborIt.getCenter();
137 if (!center.isDefined()) {
138 continue;
139 } else if (std::abs(center.getValue()) > maxValue) {
140 // push an empty vector to keep ordering correct
141 Vec3D<T> tmp = {};
142 normalVectors.push_back(tmp);
143 continue;
144 }
145
146 Vec3D<T> n;
147
148 T denominator = 0;
149 for (int i = 0; i < D; i++) {
150 T pos = neighborIt.getNeighbor(i).getValue() - center.getValue();
151 T neg = center.getValue() - neighborIt.getNeighbor(i + D).getValue();
152 n[i] = (pos + neg) * FINITE_DIFF_FACTOR;
153 denominator += n[i] * n[i];
154 }
155
156 denominator = std::sqrt(denominator);
157 if (std::abs(denominator) < EPSILON) {
158 Logger::getInstance()
159 .addWarning("CalculateNormalVectors: Vector of length 0 at " +
160 neighborIt.getIndices().to_string())
161 .print();
162 for (unsigned i = 0; i < D; ++i)
163 n[i] = 0.;
164 } else {
165 for (unsigned i = 0; i < D; ++i) {
166 n[i] /= denominator;
167 }
168 }
169
170 normalVectors.push_back(n);
171 }
172 }
173
174 // copy all normals
175 unsigned numberOfNormals = 0;
176 for (unsigned i = 0; i < levelSet->getNumberOfSegments(); ++i) {
177 numberOfNormals += normalVectorsVector[i].size();
178 }
179 normalVectorsVector[0].reserve(numberOfNormals);
180
181 for (unsigned i = 1; i < levelSet->getNumberOfSegments(); ++i) {
182 normalVectorsVector[0].insert(normalVectorsVector[0].end(),
183 normalVectorsVector[i].begin(),
184 normalVectorsVector[i].end());
185 }
186
187 // insert into pointData of levelSet
188 auto &pointData = levelSet->getPointData();
189 auto vectorDataPointer = pointData.getVectorData(normalVectorsLabel, true);
190 // if it does not exist, insert new normals vector
191 if (vectorDataPointer == nullptr) {
192 pointData.insertNextVectorData(normalVectorsVector[0],
194 } else {
195 // if it does exist, just swap the old with the new values
196 *vectorDataPointer = std::move(normalVectorsVector[0]);
197 }
198 }
199};
200
201// add all template specialisations for this class
202PRECOMPILE_PRECISION_DIMENSION(CalculateNormalVectors)
203
204} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
static constexpr char normalVectorsLabel[]
Definition lsCalculateNormalVectors.hpp:45
SmartPointer< Domain< T, D > > getLevelSet() const
Definition lsCalculateNormalVectors.hpp:70
void setLevelSet(SmartPointer< Domain< T, D > > passedLevelSet)
Definition lsCalculateNormalVectors.hpp:53
void apply()
Definition lsCalculateNormalVectors.hpp:82
T getMaxValue() const
Definition lsCalculateNormalVectors.hpp:72
CalculateNormalVectors(SmartPointer< Domain< T, D > > passedLevelSet, T passedMaxValue=DEFAULT_MAX_VALUE)
Definition lsCalculateNormalVectors.hpp:49
void setMaxValue(const T passedMaxValue)
Definition lsCalculateNormalVectors.hpp:57
bool hasNormalVectors() const
Check if normal vectors are already calculated for the level set.
Definition lsCalculateNormalVectors.hpp:75
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
Expands the levelSet to the specified number of layers. The largest value in the levelset is thus wid...
Definition lsExpand.hpp:17
void apply()
Apply the expansion to the specified width.
Definition lsExpand.hpp:44
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:36