19 const auto at = [&grid](
int x,
int y) {
return double(grid.
heights[(qsizetype(y) * grid.
width) + x]); };
28 , _shiftToMax(
TileMath::kMaxZoom - key.zoom)
29 , _patchView(pyramid.bestTileFor(key))
35 const int verticesPerEdge = _gridSize + 1;
36 _north.resize(verticesPerEdge);
37 _south.resize(verticesPerEdge);
38 _west.resize(verticesPerEdge);
39 _east.resize(verticesPerEdge);
42 heights.reserve(qsizetype(verticesPerEdge) * verticesPerEdge);
43 bool mismatched =
false;
44 for (
int row = 0; row <= _gridSize; row++) {
45 const qint64 m = (qint64(_key.
y) * _gridSize) + row;
46 for (
int col = 0; col <= _gridSize; col++) {
47 const qint64 n = (qint64(_key.
x) * _gridSize) + col;
48 const float own = _patchView.
isValid() ? _viewHeight(_patchView, n, m) : 0.0f;
49 if ((row > 0) && (row < _gridSize) && (col > 0) && (col < _gridSize)) {
53 const BoundaryVertex vertex = _boundaryVertex(n, m, own);
54 heights.append(vertex.height);
55 mismatched = mismatched || (vertex.mismatch != 0.0f);
59 if (row == _gridSize) {
65 if (col == _gridSize) {
74 QList<float> corrections(heights.size(), 0.0f);
75 for (
int row = 1; row < _gridSize; row++) {
76 for (
int col = 1; col < _gridSize; col++) {
77 const qsizetype index = (qsizetype(row) * verticesPerEdge) + col;
78 corrections[index] = _interiorCorrection(row, col);
79 heights[index] += corrections[index];
83 _trackEdgeStep(corrections);
93 const double u = (std::ldexp(
double(n), view.
key.
zoom - _key.
zoom) / _gridSize) - view.
key.
x;
94 const double v = (std::ldexp(
double(m), view.
key.
zoom - _key.
zoom) / _gridSize) - view.
key.
y;
100int PatchSampler::_touchingCells(qint64 s, qint64 (&cells)[2])
const
104 const qint64 cell = s / _gridSize;
105 if (cell < cellCount) {
106 cells[count++] = cell;
108 if (((s % _gridSize) == 0) && (cell > 0)) {
109 cells[count++] = cell - 1;
117 for (
const TileMemo& memo : _memos) {
118 if (memo.tile == tile) {
124 if (!_pyramid.
hasDescendant(tile) && (_memos.size() < _memos.capacity())) {
125 _memos.append({tile, view});
130PatchSampler::BoundaryVertex PatchSampler::_boundaryVertex(qint64 n, qint64 m,
float own)
134 const int xCount = _touchingCells(n << _shiftToMax, xCells);
135 const int yCount = _touchingCells(m << _shiftToMax, yCells);
141 BoundaryVertex vertex;
142 for (
int yi = 0; (yi < yCount) && (vertex.zoom < 0); yi++) {
143 for (
int xi = 0; xi < xCount; xi++) {
146 vertex.height = _viewHeight(view, n, m);
152 const float mismatch = vertex.height - own;
153 vertex.mismatch = std::isfinite(mismatch) ? mismatch : 0.0f;
161float PatchSampler::_interiorCorrection(
int row,
int col)
const
163 const auto weight = [](
int distance) {
return 1.0 / (double(distance) *
distance); };
164 const double north = weight(row);
165 const double south = weight(_gridSize - row);
166 const double west = weight(col);
167 const double east = weight(_gridSize - col);
168 const double sum = (north * _north[col].mismatch) + (south * _south[col].mismatch) + (west * _west[row].mismatch) +
169 (east * _east[row].mismatch);
170 return static_cast<float>(sum / (north + south + west + east));
173void PatchSampler::_trackEdgeStep(
const QList<float>& corrections)
175 const int ownZoom = _patchView.
isValid() ? _patchView.
key.
zoom : -1;
176 const int cornerSpan = _gridSize / 4;
177 for (
int row = 0; row <= _gridSize; row++) {
178 const bool fullRow = (row == 0) || (row == _gridSize);
179 for (
int col = 0; col <= _gridSize; col += (fullRow ? 1 : _gridSize)) {
180 const int along = fullRow ? col : row;
181 if (std::min(along, _gridSize - along) < cornerSpan) {
184 const BoundaryVertex& vertex = (row == 0) ? _north[col]
185 : (row == _gridSize) ? _south[col]
186 : (col == 0) ? _west[row]
189 if (vertex.zoom == ownZoom) {
194 const int inwardRow = std::clamp(row, 1, _gridSize - 1);
195 const int inwardCol = std::clamp(col, 1, _gridSize - 1);
196 inward = corrections[(qsizetype(inwardRow) * (_gridSize + 1)) + inwardCol];
198 const float step = std::abs(vertex.mismatch - inward);
199 if (!(step > _edgeStep->
step)) {
202 _edgeStep->
step = step;
203 _edgeStep->
row = row;
204 _edgeStep->
col = col;
double bilinearAtUV(int w, int h, double u, double v, SampleAt at)
View bestTileFor(const TileMath::TileKey &key) const
bool hasDescendant(const TileMath::TileKey &key) const
QList< float > sample()
The (gridSize+1)^2 vertex heights, row-major from the NW corner.
static double heightAtUV(const ElevationTilePyramid::Grid &grid, double u, double v)
PatchSampler(const ElevationTilePyramid &pyramid, const TileMath::TileKey &key, int gridSize, EdgeStep *edgeStep=nullptr)
edgeStep, when set, receives the patch's largest EdgeStep
double distance(const Ecef &left, const Ecef &right)
Straight-line distance between left and right, in metres.
Decoded elevation samples for one tile, row-major from the NW corner.
QList< float > heights
meters
const Grid * grid
null when nothing stored covers the query
TileMath::TileKey key
stored tile the view samples
int row
boundary vertex of the largest step
int boundaryZoom
zoom of the tile the boundary vertex resolved to
int ownZoom
zoom of the patch's backing tile; -1 = no data