Plugins
Loading...
Searching...
No Matches
river_tools.h
Go to the documentation of this file.
1
6#ifndef UG4_RIVER_TOOLS_H
7#define UG4_RIVER_TOOLS_H
8
9#include <vector>
10#include <queue>
11#include <map>
12#include <set>
13#include "common/common.h"
16
17namespace ug {
18namespace d3f {
19
38template <typename TDomain>
39void project_rivers_on_terrain(SmartPtr<TDomain> river_domain, SmartPtr<TDomain> soil_domain, const char* top_subset) {
41 typedef typename TDomain::grid_type TGrid;
42 static const int dim = TDomain::dim;
43
44 auto river_posAcc = river_domain->position_accessor();
45 auto soil_posAcc = soil_domain->position_accessor();
46 auto soil_ssHandler = soil_domain->subset_handler();
47 auto river_grid = river_domain->grid();
48 auto soil_grid = soil_domain->grid();
49
50 const int top_subset_index = soil_ssHandler->get_subset_index(top_subset);
51 UG_ASSERT(top_subset_index > -1, "project_rivers_on_terrain: Top subset '" << top_subset << "' not found.");
52
53 UG_LOG("Projecting river network onto terrain subset: " << top_subset << "\n");
54
55 // 1. Build a spatial index for the terrain surface to speed up vertex lookup
56 auto tree = tree_type();
57 tree.create_from_grid(*soil_grid,
58 soil_ssHandler->template begin<Vertex>(top_subset_index, soil_grid->top_level()),
59 soil_ssHandler->template end<Vertex>(top_subset_index, soil_grid->top_level()),
60 soil_posAcc,
61 15, 20);
62
64 vDir[dim - 1] = 1.0; // Raycast direction is +z (assuming terrain is above river nodes)
65
66 std::set<Vertex*> skipped_vertices;
67
68 // 2. Initial projection via raycasting
69 for (size_t lvl = 0; lvl <= river_grid->top_level(); ++lvl) {
70 auto vIt = river_grid->template begin<Vertex>(lvl);
71 auto end = river_grid->template end<Vertex>(lvl);
72
73 for (; vIt != end; ++vIt) {
74 Vertex* vRiver = *vIt;
75 std::vector<Vertex*> neighborhood;
76 tree.get_neighbourhood(neighborhood, river_posAcc[vRiver], 1);
77
78 if (neighborhood.empty()) {
79 skipped_vertices.insert(vRiver);
80 continue;
81 }
82
83 Vertex* closest_soil_vertex = neighborhood[0];
84 typename TGrid::template traits<Face>::secure_container faces;
85 soil_grid->template associated_elements<Vertex>(faces, closest_soil_vertex);
86
87 bool hit = false;
88 for (size_t i = 0; i < faces.size(); ++i) {
89 if (soil_ssHandler->get_subset_index(faces[i]) != top_subset_index) continue;
90
91 number smin, smax;
92 if (RayElementIntersection(smin, smax, river_posAcc[vRiver], vDir, faces[i],
93 *soil_grid, soil_posAcc, SMALL)) {
94 hit = true;
95 river_posAcc[vRiver][dim - 1] = PointOnRay(river_posAcc[vRiver], vDir, smin)[dim - 1];
96 break;
97 }
98 }
99
100 if (!hit) {
101 skipped_vertices.insert(vRiver);
102 }
103 }
104 }
105
106 // 3. Handle skipped vertices by inheriting elevation from the nearest projected neighbor
107 if (!skipped_vertices.empty()) {
108 UG_LOG("Handling " << skipped_vertices.size() << " vertices outside terrain extent...\n");
109
110 // We use a copy of the set to iterate, as we will remove elements from the original
111 std::vector<Vertex*> to_process(skipped_vertices.begin(), skipped_vertices.end());
112
113 for (Vertex* v : to_process) {
114 if (skipped_vertices.find(v) == skipped_vertices.end()) continue;
115
116 std::queue<Vertex*> q;
117 std::set<Vertex*> visited;
118 q.push(v);
119 visited.insert(v);
120
121 bool success = false;
122 while (!q.empty()) {
123 Vertex* curr = q.front();
124 q.pop();
125
126 // If curr is not in skipped_vertices, it means it has a valid elevation
127 if (skipped_vertices.find(curr) == skipped_vertices.end()) {
128 river_posAcc[v][dim - 1] = river_posAcc[curr][dim - 1];
129 skipped_vertices.erase(v);
130 success = true;
131 break;
132 }
133
134 typename TGrid::template traits<Edge>::secure_container edges;
135 river_grid->template associated_elements<Vertex>(edges, curr);
136 for (size_t i = 0; i < edges.size(); ++i) {
137 for (int j = 0; j < 2; ++j) {
138 Vertex* nb = edges[i]->vertex(j);
139 if (visited.find(nb) == visited.end()) {
140 visited.insert(nb);
141 q.push(nb);
142 }
143 }
144 }
145 }
146 if (!success) {
147 UG_THROW("Could not find a projected neighbor for vertex at " << river_posAcc[v]);
148 }
149 }
150 }
151
152 // 4. Debug output: Save the projected grid
153 std::stringstream ss;
154 ss << "projected_river";
155 #ifdef UG_PARALLEL
156 ss << "_p" << pcl::ProcRank();
157 #endif
158 ss << ".ugx";
159
160 UG_LOG("Saving projected river grid to: " << ss.str() << "\n");
161 SaveGridToUGX(*river_grid, *(river_domain->subset_handler()), ss.str().c_str());
162}
163
164} // namespace d3f
165} // namespace ug
166
167#endif // UG4_RIVER_TOOLS_H
int ProcRank()
#define UG_ASSERT(expr, msg)
#define UG_THROW(msg)
#define UG_LOG(msg)
double number
vector_t PointOnRay(const vector_t &from, const vector_t &dir, number s)
void project_rivers_on_terrain(SmartPtr< TDomain > river_domain, SmartPtr< TDomain > soil_domain, const char *top_subset)
Projects a 1D river network onto the surface of a 3D terrain.
Definition river_tools.h:39
const number SMALL
bool SaveGridToUGX(Grid &grid, ISubsetHandler &sh, const char *filename)
bool RayElementIntersection(number &sminOut, number &smaxOut, const vector2 &from, const vector2 &dir, Edge *e, Grid &g, Grid::VertexAttachmentAccessor< AVector2 > aaPos, number sml=SMALL)