ViennaLS
Loading...
Searching...
No Matches
lsMarkVoidPoints.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <hrleSparseStarIterator.hpp>
4
5#include <lsDomain.hpp>
6#include <lsGraph.hpp>
7
8namespace viennals {
9
10using namespace viennacore;
11
19enum struct VoidTopSurfaceEnum : unsigned {
24};
25
28template <class T, int D> class MarkVoidPoints {
29 using IndexType = std::size_t;
30
31 SmartPointer<Domain<T, D>> domain = nullptr;
32 bool reverseVoidDetection = false;
33 bool saveComponents = false;
34 bool detectLargestSurface = false;
35 std::size_t numComponents = 0;
36
37 // two points are connected if they have the same sign
38 static bool areConnected(const T &value1, const T &value2) {
39 return (value1 >= 0) == (value2 >= 0);
40 }
41
42 std::vector<IndexType> static mergeComponentCounts(
43 const std::vector<IndexType> &components,
44 const std::vector<IndexType> &pointsPerComponent) {
45 // find number of connected components after merge
46 // TODO: the last element in the components vector is very likely
47 // the highest index, so could just set it instead of checking all values
48 unsigned highestIndex = 0;
49 for (auto it : components) {
50 if (highestIndex < it) {
51 highestIndex = it;
52 }
53 }
54
55 // merge pointsPerComponent according to the connected components
56 std::vector<IndexType> pointsPerConnected;
57 pointsPerConnected.resize(highestIndex + 1, 0);
58 for (unsigned i = 0; i < components.size(); ++i) {
59 pointsPerConnected[components[i]] += pointsPerComponent[i];
60 }
61
62 return pointsPerConnected;
63 }
64
65 IndexType
66 calculateTopID(const std::vector<IndexType> &components,
67 const std::vector<IndexType> &pointsPerConnected) const {
68 // check which component has the most points
69 IndexType topId = 0;
70 // use first component, which contains more than 0 points
71 while (topId < pointsPerConnected.size() &&
72 pointsPerConnected[topId] == 0) {
73 ++topId;
74 }
75 for (unsigned i = topId + 1; i < pointsPerConnected.size(); ++i) {
76 if ((pointsPerConnected[topId] < pointsPerConnected[i]) !=
77 reverseVoidDetection) {
78 topId = i;
79 }
80 }
81
82 return topId;
83 }
84
85public:
86 static constexpr char voidPointLabel[] = "VoidPointMarkers";
87
88 MarkVoidPoints() = default;
89
90 MarkVoidPoints(SmartPointer<Domain<T, D>> passedlsDomain,
91 bool passedReverseVoidDetection = false)
92 : domain(passedlsDomain),
93 reverseVoidDetection(passedReverseVoidDetection) {}
94
95 void setLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
96 domain = passedlsDomain;
97 }
98
103 void setReverseVoidDetection(bool passedReverseVoidDetection) {
104 reverseVoidDetection = passedReverseVoidDetection;
105 }
106
113 void setDetectLargestSurface(bool passedDetect) {
114 detectLargestSurface = passedDetect;
115 }
116
120 switch (topSurface) {
122 reverseVoidDetection = true;
123 detectLargestSurface = false;
124 break;
126 reverseVoidDetection = false;
127 detectLargestSurface = false;
128 break;
130 reverseVoidDetection = false;
131 detectLargestSurface = true;
132 break;
134 reverseVoidDetection = true;
135 detectLargestSurface = true;
136 break;
137
138 default:
139 VIENNACORE_LOG_WARNING("MarkVoidPoints: Invalid VoidTopSurfaceEnum set. "
140 "Using default values.");
141 reverseVoidDetection = false;
142 detectLargestSurface = false;
143 break;
144 }
145 }
146
150 void setSaveComponentIds(bool scid) { saveComponents = scid; }
151
152 std::size_t getNumberOfComponents() const { return numComponents; }
153
154 void apply() {
155 lsInternal::Graph graph;
156
157 std::vector<std::vector<std::vector<IndexType>>> componentList(
158 domain->getNumberOfSegments());
159 for (unsigned segmentId = 0; segmentId < domain->getNumberOfSegments();
160 ++segmentId) {
161 componentList[segmentId].resize(D + 1);
162 for (int dim = -1; dim < D; ++dim) {
163 componentList[segmentId][dim + 1].resize(
164 domain->getDomain().getNumberOfRuns(segmentId, dim), -1);
165 }
166 }
167
168 std::size_t numberOfComponents = 0;
169 std::vector<IndexType> pointsPerComponent;
170
171 // cycle through and set up the graph to get connectivity information
172 for (viennahrle::ConstSparseStarIterator<typename Domain<T, D>::DomainType,
173 1>
174 neighborIt(domain->getDomain());
175 !neighborIt.isFinished(); neighborIt.next()) {
176 auto &center = neighborIt.getCenter();
177
178 // component id of the current run
179 auto &currentComponentId =
180 componentList[center.getSegmentId()][center.getLevel()]
181 [center.getRunTypePosition()];
182
183 // -1 means it is not set yet
184 if (currentComponentId == -1) {
185 for (int k = 0; k < 2 * D; ++k) {
186 auto &neighbor = neighborIt.getNeighbor(k);
187 const auto neighborComponentId =
188 componentList[neighbor.getSegmentId()][neighbor.getLevel()]
189 [neighbor.getRunTypePosition()];
190 // if neighbor is already defined
191 // set current component to neighbor component
192 // if they are connected
193 if (neighborComponentId != -1) {
194 if (areConnected(center.getValue(), neighbor.getValue())) {
195 currentComponentId = neighborComponentId;
196 if (center.getValue() >= 0.)
197 ++pointsPerComponent[currentComponentId];
198 break;
199 }
200 }
201 }
202 }
203
204 // it is still not set, so add new vertex
205 if (currentComponentId == -1) {
206 currentComponentId = numberOfComponents;
207 pointsPerComponent.push_back((center.getValue() > 0.) ? 1 : 0);
208 graph.insertNextVertex();
209 ++numberOfComponents;
210 }
211
212 // check if edge can be set
213 for (int k = 0; k < 2 * D; ++k) {
214 auto &neighbor = neighborIt.getNeighbor(k);
215 auto &neighborComponentId =
216 componentList[neighbor.getSegmentId()][neighbor.getLevel()]
217 [neighbor.getRunTypePosition()];
218 if (areConnected(center.getValue(), neighbor.getValue())) {
219 // if neighbor is already set
220 if (neighborComponentId != -1) {
221 // if neighbor is part of different component
222 if (currentComponentId != neighborComponentId) {
223 graph.insertNextEdge(currentComponentId, neighborComponentId);
224 }
225 } else {
226 neighborComponentId = currentComponentId;
227 if (neighbor.getValue() >= 0.)
228 ++pointsPerComponent[neighborComponentId];
229 }
230 }
231 }
232 }
233
234 auto components = graph.getConnectedComponents();
235
236 int topComponent =
237 (reverseVoidDetection) ? components[0] : components.back();
238
239 // identify which layer to keep
240 {
241 auto pointsPerConnected =
242 mergeComponentCounts(components, pointsPerComponent);
243
244 // find largest connected surface
245 if (detectLargestSurface) {
246 topComponent = calculateTopID(components, pointsPerConnected);
247 } else { // if component does not contain points, take the next one
248 while (topComponent >= 0 && pointsPerConnected[topComponent] == 0) {
249 if (reverseVoidDetection)
250 ++topComponent;
251 else
252 --topComponent;
253 }
254 }
255 }
256
257 std::vector<T> voidPointMarkers;
258 voidPointMarkers.resize(domain->getNumberOfPoints());
259
260 std::vector<T> componentMarkers;
261 if (saveComponents)
262 componentMarkers.resize(domain->getNumberOfPoints());
263
264 // cycle through again to set correct voidPointMarkers
265 for (viennahrle::ConstSparseStarIterator<typename Domain<T, D>::DomainType,
266 1>
267 neighborIt(domain->getDomain());
268 !neighborIt.isFinished(); neighborIt.next()) {
269 auto center = neighborIt.getCenter();
270
271 if (!center.isDefined())
272 continue;
273
274 // if it is positive, just check if it is part of the top component
275 if (center.getValue() >= 0) {
276 const int &oldComponentId = componentList[center.getSegmentId()][0]
277 [center.getRunTypePosition()];
278 voidPointMarkers[center.getPointId()] =
279 (components[oldComponentId] != topComponent);
280 } else {
281 // if it is negative, check all neighbours (with different sign),
282 // because they are part of of a positive component, which might
283 // be the top
284 unsigned k;
285 for (k = 0; k < 2 * D; ++k) {
286 auto &neighbor = neighborIt.getNeighbor(k);
287 if (std::signbit(neighbor.getValue()) ==
288 std::signbit(center.getValue()))
289 continue;
290 const int &oldneighborComponentId =
291 componentList[neighbor.getSegmentId()][neighbor.getLevel()]
292 [neighbor.getRunTypePosition()];
293 if (components[oldneighborComponentId] == topComponent) {
294 break;
295 }
296 }
297 voidPointMarkers[center.getPointId()] = (k == 2 * D);
298 }
299
300 if (saveComponents) {
301 const int &oldComponentId = componentList[center.getSegmentId()][0]
302 [center.getRunTypePosition()];
303 componentMarkers[center.getPointId()] = components[oldComponentId];
304 }
305 }
306
307 auto &pointData = domain->getPointData();
308 auto voidMarkersPointer = pointData.getScalarData(voidPointLabel, true);
309 // if vector data does not exist
310 if (voidMarkersPointer == nullptr) {
311 pointData.insertNextScalarData(voidPointMarkers, voidPointLabel);
312 } else {
313 *voidMarkersPointer = std::move(voidPointMarkers);
314 }
315
316 if (saveComponents) {
317 auto maxComponent =
318 *std::max_element(componentMarkers.begin(), componentMarkers.end());
319 assert(maxComponent >= 0);
320 numComponents = maxComponent;
321
322 auto componentMarkersPointer =
323 pointData.getScalarData("ConnectedComponentId", true);
324 // if vector data does not exist
325 if (componentMarkersPointer == nullptr) {
326 pointData.insertNextScalarData(componentMarkers,
327 "ConnectedComponentId");
328 } else {
329 *componentMarkersPointer = std::move(componentMarkers);
330 }
331 }
332 }
333};
334
335} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
Definition lsGraph.hpp:13
std::size_t insertNextVertex()
add new vertex
Definition lsGraph.hpp:47
std::vector< IndexType > getConnectedComponents()
Definition lsGraph.hpp:68
void insertNextEdge(std::size_t vertex1, std::size_t vertex2)
add connection of vertex1 to vertex2
Definition lsGraph.hpp:54
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
void setLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Definition lsMarkVoidPoints.hpp:95
void setReverseVoidDetection(bool passedReverseVoidDetection)
Set whether the "top" level set should be the most positive(default) connected chain of level set val...
Definition lsMarkVoidPoints.hpp:103
void apply()
Definition lsMarkVoidPoints.hpp:154
void setSaveComponentIds(bool scid)
Set whether the connected component IDs used to generate the void points should be saved....
Definition lsMarkVoidPoints.hpp:150
void setDetectLargestSurface(bool passedDetect)
Set whether the number of points of one connected surface should be used to detect void points....
Definition lsMarkVoidPoints.hpp:113
static constexpr char voidPointLabel[]
Definition lsMarkVoidPoints.hpp:86
void setVoidTopSurface(VoidTopSurfaceEnum topSurface)
Set which connected component to use as the top surface and mark all other components as void points.
Definition lsMarkVoidPoints.hpp:119
std::size_t getNumberOfComponents() const
Definition lsMarkVoidPoints.hpp:152
MarkVoidPoints(SmartPointer< Domain< T, D > > passedlsDomain, bool passedReverseVoidDetection=false)
Definition lsMarkVoidPoints.hpp:90
Definition lsAdvect.hpp:40
VoidTopSurfaceEnum
Enumeration describing which connected component to use as top surface during void point detection....
Definition lsMarkVoidPoints.hpp:19
@ LEX_HIGHEST
Definition lsMarkVoidPoints.hpp:21
@ SMALLEST
Definition lsMarkVoidPoints.hpp:23
@ LEX_LOWEST
Definition lsMarkVoidPoints.hpp:20
@ LARGEST
Definition lsMarkVoidPoints.hpp:22