* @brief Decimate the visible [xLo, xHi] slice of a monotonic time ring to render * columns. Times rebase so the newest sample sits at 0 (axis [-T, 0]); monotonic * time resolves the window as two binary searches and the slice is walked once. * Buckets sit on an absolute newest-anchored column-width lattice (shimmer fix). */
| 1150 | * Buckets sit on an absolute newest-anchored column-width lattice (shimmer fix). |
| 1151 | */ |
| 1152 | inline bool downsampleTimeWindow(const AxisData& timeX, |
| 1153 | const AxisData& valueY, |
| 1154 | ssfp_t xLo, |
| 1155 | ssfp_t xHi, |
| 1156 | int w, |
| 1157 | int h, |
| 1158 | QList<QPointF>& out, |
| 1159 | DownsampleWorkspace* ws) |
| 1160 | { |
| 1161 | out.clear(); |
| 1162 | const std::size_t n = std::min<std::size_t>(timeX.size(), valueY.size()); |
| 1163 | if (n == 0 || w <= 0 || h <= 0 || !(xLo < xHi)) |
| 1164 | return true; |
| 1165 | |
| 1166 | std::size_t xn0, xn1, yn0, yn1; |
| 1167 | const ssfp_t *xp0, *xp1, *yp0, *yp1; |
| 1168 | spanFromFixedQueue(timeX, xp0, xn0, xp1, xn1); |
| 1169 | spanFromFixedQueue(valueY, yp0, yn0, yp1, yn1); |
| 1170 | |
| 1171 | auto xAbs = [&](std::size_t i) -> ssfp_t { |
| 1172 | return (i < xn0) ? xp0[i] : xp1[i - xn0]; |
| 1173 | }; |
| 1174 | auto yAt = [&](std::size_t i) -> ssfp_t { |
| 1175 | return (i < yn0) ? yp0[i] : yp1[i - yn0]; |
| 1176 | }; |
| 1177 | |
| 1178 | const ssfp_t newest = xAbs(n - 1); |
| 1179 | auto tRel = [&](std::size_t i) -> ssfp_t { |
| 1180 | return xAbs(i) - newest; |
| 1181 | }; |
| 1182 | |
| 1183 | const std::size_t lo = dsLowerBound(n, xAbs, xLo + newest); |
| 1184 | const std::size_t hi = dsUpperBound(n, xAbs, xHi + newest); |
| 1185 | |
| 1186 | const std::size_t visible = (hi > lo) ? (hi - lo) : 0; |
| 1187 | if (visible == 0) |
| 1188 | return true; |
| 1189 | |
| 1190 | auto xWin = [&](std::size_t i) -> ssfp_t { |
| 1191 | return tRel(lo + i); |
| 1192 | }; |
| 1193 | auto yWin = [&](std::size_t i) -> ssfp_t { |
| 1194 | return yAt(lo + i); |
| 1195 | }; |
| 1196 | |
| 1197 | const std::size_t C = std::size_t(w); |
| 1198 | ws->reset(C); |
| 1199 | |
| 1200 | const ssfp_t span = std::max<ssfp_t>(1e-12, xHi - xLo); |
| 1201 | const auto scaleX = static_cast<ssfp_t>(w - 1) / span; |
| 1202 | const ssfp_t colWidth = span / static_cast<ssfp_t>(std::max(1, w - 1)); |
| 1203 | const ssfp_t anchorShift = newest - std::floor(newest / colWidth) * colWidth; |
| 1204 | |
| 1205 | auto xBkt = [&](std::size_t i) -> ssfp_t { |
| 1206 | return tRel(lo + i) + anchorShift; |
| 1207 | }; |
| 1208 | |
| 1209 | dsAccumulateBuckets(visible, w, xLo, scaleX, xBkt, yWin, ws); |
no test coverage detected