Skip to content

Commit 77e5776

Browse files
authored
Calculate visibility on LS grid points (#108)
* Add CalculateVisibilities function * Fix typo * Fix iterator template parameter * Default params * Delete visibility scalar data if it already exists * Visibilities calculated in any direction * Change visibility label * Add visibility test and parallelize * Fixed visibility calculation * Scale direction vector by grid delta * Fix typo * Cast grid delta to correct type --------- Co-authored-by: = <=>
1 parent f17c9f8 commit 77e5776

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#pragma once
2+
3+
#include <lsDomain.hpp>
4+
#include <vcVectorUtil.hpp>
5+
6+
namespace viennals {
7+
using namespace viennacore;
8+
9+
template <class NumericType, int D> class CalculateVisibilities {
10+
SmartPointer<Domain<NumericType, D>> levelSet;
11+
Vec3D<NumericType> direction;
12+
const NumericType epsilon = static_cast<NumericType>(1e-6);
13+
const std::string visibilitiesLabel;
14+
15+
public:
16+
CalculateVisibilities(
17+
const SmartPointer<Domain<NumericType, D>> &passedLevelSet,
18+
const Vec3D<NumericType> passedDirection,
19+
const std::string label = "Visibilities")
20+
: levelSet(passedLevelSet), direction(passedDirection),
21+
visibilitiesLabel(std::move(label)) {}
22+
23+
void apply() {
24+
25+
auto &domain = levelSet->getDomain();
26+
auto &grid = levelSet->getGrid();
27+
28+
// *** Determine extents of domain ***
29+
Vec3D<NumericType> minDefinedPoint;
30+
Vec3D<NumericType> maxDefinedPoint;
31+
// Initialize with extreme values
32+
for (int i = 0; i < D; ++i) {
33+
minDefinedPoint[i] = std::numeric_limits<NumericType>::max();
34+
maxDefinedPoint[i] = std::numeric_limits<NumericType>::lowest();
35+
}
36+
// Iterate through all defined points in the domain
37+
for (hrleSparseIterator<typename Domain<NumericType, D>::DomainType> it(
38+
domain);
39+
!it.isFinished(); it.next()) {
40+
if (!it.isDefined())
41+
continue; // Skip undefined points
42+
43+
// Get the coordinate of the current point
44+
auto point = it.getStartIndices();
45+
for (int i = 0; i < D; ++i) {
46+
// Compare to update min and max defined points
47+
NumericType coord = point[i]; // * grid.getGridDelta();
48+
minDefinedPoint[i] = std::min(minDefinedPoint[i], coord);
49+
maxDefinedPoint[i] = std::max(maxDefinedPoint[i], coord);
50+
}
51+
}
52+
//****************************
53+
54+
// Invert the vector
55+
auto dir = Normalize(Inv(direction)) *
56+
static_cast<NumericType>(domain.getGrid().getGridDelta());
57+
58+
auto numDefinedPoints = domain.getNumberOfPoints();
59+
std::vector<NumericType> visibilities(numDefinedPoints);
60+
61+
#pragma omp parallel num_threads(levelSet->getNumberOfSegments())
62+
{
63+
int p = 0;
64+
#ifdef _OPENMP
65+
p = omp_get_thread_num();
66+
#endif
67+
68+
hrleVectorType<hrleIndexType, D> startVector =
69+
(p == 0) ? grid.getMinGridPoint() : domain.getSegmentation()[p - 1];
70+
71+
hrleVectorType<hrleIndexType, D> endVector =
72+
(p != static_cast<int>(domain.getNumberOfSegments() - 1))
73+
? domain.getSegmentation()[p]
74+
: grid.incrementIndices(grid.getMaxGridPoint());
75+
76+
// Calculate the starting index for the visibility vector
77+
hrleSizeType id = 0;
78+
for (int i = 0; i < p; ++i) {
79+
id += domain.getDomainSegment(i).getNumberOfPoints();
80+
}
81+
82+
for (hrleSparseIterator<typename Domain<NumericType, D>::DomainType> it(
83+
domain, startVector);
84+
it.getStartIndices() < endVector; ++it) {
85+
86+
if (!it.isDefined())
87+
continue;
88+
89+
// Starting position of the point
90+
Vec3D<NumericType> currentPos;
91+
for (int i = 0; i < D; ++i) {
92+
currentPos[i] = it.getStartIndices(i);
93+
}
94+
95+
// Start tracing the ray
96+
NumericType minLevelSetValue =
97+
it.getValue(); // Starting level set value
98+
Vec3D<NumericType> rayPos = currentPos;
99+
bool visibility = true;
100+
101+
while (1) {
102+
// Update the ray position
103+
for (int i = 0; i < D; ++i) {
104+
rayPos[i] += dir[i];
105+
}
106+
107+
// Determine the nearest grid cell (round to nearest index)
108+
Vec3D<hrleIndexType> nearestCell;
109+
for (int i = 0; i < D; ++i) {
110+
nearestCell[i] = static_cast<hrleIndexType>(rayPos[i]);
111+
}
112+
113+
// // Before adding a cell, check if it's already visited
114+
// if (std::find(visitedCells.begin(), visitedCells.end(),
115+
// nearestCell)
116+
// == visitedCells.end()) {
117+
// visitedCells.push_back(nearestCell);
118+
// }
119+
120+
// Check if the nearest cell is within bounds
121+
bool outOfBounds = false;
122+
for (int i = 0; i < D; ++i) {
123+
if (nearestCell[i] < minDefinedPoint[i] ||
124+
nearestCell[i] > maxDefinedPoint[i]) {
125+
outOfBounds = true;
126+
break;
127+
}
128+
}
129+
130+
if (outOfBounds) {
131+
break; // Ray is outside the grid
132+
}
133+
134+
// Access the level set value at the nearest cell
135+
NumericType neighborValue = std::numeric_limits<NumericType>::max();
136+
hrleSparseIterator<typename Domain<NumericType, D>::DomainType>
137+
neighborIt(domain);
138+
neighborIt.goToIndices(nearestCell);
139+
neighborValue = neighborIt.getValue();
140+
141+
// Update the minimum value encountered
142+
if (neighborValue < minLevelSetValue) {
143+
visibility = false;
144+
break;
145+
}
146+
}
147+
148+
// Update visibility for this point
149+
visibilities[id++] = visibility ? 1.0 : 0.0;
150+
}
151+
}
152+
153+
auto &pointData = levelSet->getPointData();
154+
// delete if already exists
155+
if (int i = pointData.getScalarDataIndex(visibilitiesLabel); i != -1) {
156+
pointData.eraseScalarData(i);
157+
}
158+
pointData.insertNextScalarData(visibilities, visibilitiesLabel);
159+
}
160+
};
161+
162+
} // namespace viennals

tests/Visibility/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
project(Visibility LANGUAGES CXX)
2+
3+
add_executable(${PROJECT_NAME} "${PROJECT_NAME}.cpp")
4+
target_link_libraries(${PROJECT_NAME} PRIVATE ViennaLS)
5+
6+
add_dependencies(ViennaLS_Tests ${PROJECT_NAME})
7+
add_test(NAME ${PROJECT_NAME} COMMAND $<TARGET_FILE:${PROJECT_NAME}>)

tests/Visibility/Visibility.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <chrono>
2+
#include <iostream>
3+
4+
#include <lsCalculateVisibilities.hpp>
5+
#include <lsDomain.hpp>
6+
#include <lsExpand.hpp>
7+
#include <lsMakeGeometry.hpp>
8+
#include <lsToMesh.hpp>
9+
#include <lsVTKWriter.hpp>
10+
11+
namespace ls = viennals;
12+
13+
int main() {
14+
15+
constexpr int D = 2;
16+
17+
double gridDelta = 0.4;
18+
19+
auto sphere1 = ls::SmartPointer<ls::Domain<double, D>>::New(
20+
gridDelta); //, boundaryCons);
21+
22+
double origin[3] = {5., 0., 0.};
23+
double radius = 7.3;
24+
25+
ls::MakeGeometry<double, D>(
26+
sphere1, ls::SmartPointer<ls::Sphere<double, D>>::New(origin, radius))
27+
.apply();
28+
29+
ls::Expand<double, D>(sphere1, 5).apply();
30+
ls::CalculateVisibilities<double, D>(sphere1, ls::Vec3D<double>{0., -1.0, 0.})
31+
.apply();
32+
33+
auto mesh = ls::SmartPointer<ls::Mesh<>>::New();
34+
ls::ToMesh<double, D>(sphere1, mesh).apply();
35+
ls::VTKWriter<double>(mesh, "visibility_test.vtp").apply();
36+
37+
return 0;
38+
}

0 commit comments

Comments
 (0)