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
26template <class T, int D> class CalculateNormalVectors {
27 SmartPointer<Domain<T, D>> levelSet = nullptr;
28 T maxValue = 0.5;
29
30public:
31 static constexpr char normalVectorsLabel[] = "Normals";
32
34
35 CalculateNormalVectors(SmartPointer<Domain<T, D>> passedLevelSet,
36 T passedMaxValue = 0.5)
37 : levelSet(passedLevelSet), maxValue(passedMaxValue) {}
38
39 void setLevelSet(SmartPointer<Domain<T, D>> passedLevelSet) {
40 levelSet = passedLevelSet;
41 }
42
43 void setMaxValue(const T passedMaxValue) { maxValue = passedMaxValue; }
44
45 void apply() {
46 if (levelSet == nullptr) {
47 Logger::getInstance()
48 .addError("No level set was passed to CalculateNormalVectors.")
49 .print();
50 }
51
52 if (levelSet->getLevelSetWidth() < (maxValue * 4) + 1) {
53 Logger::getInstance()
54 .addWarning("CalculateNormalVectors: Level set width must be "
55 "greater than " +
56 std::to_string((maxValue * 4) + 1) +
57 ". Expanding level set to " +
58 std::to_string((maxValue * 4) + 1) + ".")
59 .print();
60 Expand<T, D>(levelSet, (maxValue * 4) + 1).apply();
61 }
62
63 std::vector<std::vector<Vec3D<T>>> normalVectorsVector(
64 levelSet->getNumberOfSegments());
65 double pointsPerSegment =
66 double(2 * levelSet->getDomain().getNumberOfPoints()) /
67 double(levelSet->getLevelSetWidth());
68
69 auto grid = levelSet->getGrid();
70
71 // Calculate Normalvectors
72#pragma omp parallel num_threads(levelSet->getNumberOfSegments())
73 {
74 int p = 0;
75#ifdef _OPENMP
76 p = omp_get_thread_num();
77#endif
78
79 auto &normalVectors = normalVectorsVector[p];
80 normalVectors.reserve(pointsPerSegment);
81
82 viennahrle::Index<D> const startVector =
83 (p == 0) ? grid.getMinGridPoint()
84 : levelSet->getDomain().getSegmentation()[p - 1];
85
86 viennahrle::Index<D> const endVector =
87 (p != static_cast<int>(levelSet->getNumberOfSegments() - 1))
88 ? levelSet->getDomain().getSegmentation()[p]
89 : grid.incrementIndices(grid.getMaxGridPoint());
90
91 for (viennahrle::ConstSparseStarIterator<
92 typename Domain<T, D>::DomainType, 1>
93 neighborIt(levelSet->getDomain(), startVector);
94 neighborIt.getIndices() < endVector; neighborIt.next()) {
95
96 auto &center = neighborIt.getCenter();
97 if (!center.isDefined()) {
98 continue;
99 } else if (std::abs(center.getValue()) > maxValue) {
100 // push an empty vector to keep ordering correct
101 Vec3D<T> tmp = {};
102 normalVectors.push_back(tmp);
103 continue;
104 }
105
106 Vec3D<T> n;
107
108 T denominator = 0;
109 for (int i = 0; i < D; i++) {
110 T pos = neighborIt.getNeighbor(i).getValue() - center.getValue();
111 T neg = center.getValue() - neighborIt.getNeighbor(i + D).getValue();
112 n[i] = (pos + neg) * 0.5;
113 denominator += n[i] * n[i];
114 }
115
116 denominator = std::sqrt(denominator);
117 if (std::abs(denominator) < 1e-12) {
118 Logger::getInstance()
119 .addWarning("CalculateNormalVectors: Vector of length 0 at " +
120 neighborIt.getIndices().to_string())
121 .print();
122 for (unsigned i = 0; i < D; ++i)
123 n[i] = 0.;
124 } else {
125 for (unsigned i = 0; i < D; ++i) {
126 n[i] /= denominator;
127 }
128 }
129
130 normalVectors.push_back(n);
131 }
132 }
133
134 // copy all normals
135 unsigned numberOfNormals = 0;
136 for (unsigned i = 0; i < levelSet->getNumberOfSegments(); ++i) {
137 numberOfNormals += normalVectorsVector[i].size();
138 }
139 normalVectorsVector[0].reserve(numberOfNormals);
140
141 for (unsigned i = 1; i < levelSet->getNumberOfSegments(); ++i) {
142 normalVectorsVector[0].insert(normalVectorsVector[0].end(),
143 normalVectorsVector[i].begin(),
144 normalVectorsVector[i].end());
145 }
146
147 // insert into pointData of levelSet
148 auto &pointData = levelSet->getPointData();
149 auto vectorDataPointer = pointData.getVectorData(normalVectorsLabel, true);
150 // if it does not exist, insert new normals vector
151 if (vectorDataPointer == nullptr) {
152 pointData.insertNextVectorData(normalVectorsVector[0],
154 } else {
155 // if it does exist, just swap the old with the new values
156 *vectorDataPointer = std::move(normalVectorsVector[0]);
157 }
158 }
159};
160
161// add all template specialisations for this class
162PRECOMPILE_PRECISION_DIMENSION(CalculateNormalVectors)
163
164} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:9
double T
Definition Epitaxy.cpp:10
CalculateNormalVectors(SmartPointer< Domain< T, D > > passedLevelSet, T passedMaxValue=0.5)
Definition lsCalculateNormalVectors.hpp:35
static constexpr char normalVectorsLabel[]
Definition lsCalculateNormalVectors.hpp:31
void setLevelSet(SmartPointer< Domain< T, D > > passedLevelSet)
Definition lsCalculateNormalVectors.hpp:39
void apply()
Definition lsCalculateNormalVectors.hpp:45
void setMaxValue(const T passedMaxValue)
Definition lsCalculateNormalVectors.hpp:43
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