| 181 | } |
| 182 | |
| 183 | auto FlowAggregator::computeFlowsPerBasin( size_t numStarts, |
| 184 | const std::function<MeshTriPoint(size_t)> & startById, |
| 185 | const std::function<float(size_t)> & amountById ) const -> HashMap<VertId, Flows> |
| 186 | { |
| 187 | MR_TIMER; |
| 188 | |
| 189 | VertScalars flowInVert( mesh_.topology.vertSize() ); |
| 190 | std::vector<VertId> start2downVert( numStarts ); // for each start point stores what next vertex is on flow path (can be invalid) |
| 191 | std::vector<VertId> start2rootVert( numStarts ); |
| 192 | std::vector<SurfacePath> start2downPath( numStarts ); // till next vertex |
| 193 | |
| 194 | ParallelFor( start2downVert, [&]( size_t i ) |
| 195 | { |
| 196 | VertId nextVert; |
| 197 | if ( auto s = startById( i ); s && !s.isBd( mesh_.topology ) ) |
| 198 | { |
| 199 | EdgePoint bdPoint; |
| 200 | start2downPath[i] = computeSteepestDescentPath( mesh_, heights_, s, { .outVertexReached = &nextVert, .outBdReached = &bdPoint } ); |
| 201 | if ( bdPoint ) |
| 202 | start2downPath[i].push_back( bdPoint ); |
| 203 | start2downVert[i] = nextVert; |
| 204 | if ( nextVert ) |
| 205 | start2rootVert[i] = rootVert_[nextVert]; |
| 206 | } |
| 207 | } ); |
| 208 | |
| 209 | for ( size_t i = 0; i < numStarts; ++i ) |
| 210 | { |
| 211 | if ( auto v = start2downVert[i] ) |
| 212 | flowInVert[v] += amountById( i ); |
| 213 | } |
| 214 | |
| 215 | for ( size_t i = 0; i < vertsSortedDesc_.size(); ++i ) |
| 216 | { |
| 217 | auto vUp = vertsSortedDesc_[i]; |
| 218 | if ( !flowInVert[vUp] ) |
| 219 | continue; |
| 220 | if ( auto vDn = downFlowVert_[vUp] ) |
| 221 | flowInVert[vDn] += flowInVert[vUp]; |
| 222 | } |
| 223 | |
| 224 | HashMap<VertId, std::vector<VertId>> root2firstPolylineVert; |
| 225 | |
| 226 | // paths from sample starts to first mesh vertices |
| 227 | std::vector<size_t> start2numInRoot; |
| 228 | start2numInRoot.reserve( numStarts ); |
| 229 | for ( size_t i = 0; i < numStarts; ++i ) |
| 230 | { |
| 231 | const auto r = start2rootVert[i]; |
| 232 | auto & f = root2firstPolylineVert[r]; |
| 233 | VertId n; |
| 234 | if ( f.empty() ) |
| 235 | f.push_back( n = 0_v ); |
| 236 | else |
| 237 | n = f.back(); |
| 238 | start2numInRoot.push_back( f.size() - 1 ); |
| 239 | if ( !start2downPath[i].empty() || start2downVert[i] ) |
| 240 | n += 1 + (int)start2downPath[i].size() + start2downVert[i].valid(); |
nothing calls this directly
no test coverage detected