* @brief Downsample a 2D series (X,Y) into screen-space pixels, preserving extremes. * X must be monotonic non-decreasing: the X bounds come from the finite * endpoints and the Y bounds from the filled columns, so the samples are * walked once (bucket accumulation) instead of twice. */
| 1079 | * walked once (bucket accumulation) instead of twice. |
| 1080 | */ |
| 1081 | inline bool downsampleMonotonic( |
| 1082 | const AxisData& X, const AxisData& Y, int w, int h, QList<QPointF>& out, DownsampleWorkspace* ws) |
| 1083 | { |
| 1084 | out.clear(); |
| 1085 | const std::size_t n = std::min<std::size_t>(X.size(), Y.size()); |
| 1086 | if (n == 0 || w <= 0 || h <= 0) |
| 1087 | return true; |
| 1088 | |
| 1089 | std::size_t xn0, xn1, yn0, yn1; |
| 1090 | const ssfp_t *xp0, *xp1, *yp0, *yp1; |
| 1091 | spanFromFixedQueue(X, xp0, xn0, xp1, xn1); |
| 1092 | spanFromFixedQueue(Y, yp0, yn0, yp1, yn1); |
| 1093 | |
| 1094 | auto xAt = [&](std::size_t i) -> ssfp_t { |
| 1095 | return (i < xn0) ? xp0[i] : xp1[i - xn0]; |
| 1096 | }; |
| 1097 | auto yAt = [&](std::size_t i) -> ssfp_t { |
| 1098 | return (i < yn0) ? yp0[i] : yp1[i - yn0]; |
| 1099 | }; |
| 1100 | |
| 1101 | std::size_t firstFinite = 0; |
| 1102 | std::size_t lastFinite = 0; |
| 1103 | if (!dsFiniteEnds(n, xAt, yAt, firstFinite, lastFinite)) |
| 1104 | return false; |
| 1105 | |
| 1106 | const ssfp_t xmin = xAt(firstFinite); |
| 1107 | const ssfp_t xmax = xAt(lastFinite); |
| 1108 | if (!(xmin < xmax)) { |
| 1109 | dsEmitSteppedFallback(n, w, firstFinite, lastFinite, xAt, yAt, out); |
| 1110 | return true; |
| 1111 | } |
| 1112 | |
| 1113 | const std::size_t C = std::size_t(w); |
| 1114 | ws->reset(C); |
| 1115 | |
| 1116 | const auto scaleX = static_cast<ssfp_t>(w - 1) / std::max(1e-12, xmax - xmin); |
| 1117 | dsAccumulateBuckets(n, w, xmin, scaleX, xAt, yAt, ws); |
| 1118 | |
| 1119 | ssfp_t ymin = 0; |
| 1120 | ssfp_t ymax = 0; |
| 1121 | if (!dsColumnYBounds(ws, C, ymin, ymax)) |
| 1122 | return false; |
| 1123 | |
| 1124 | const auto scaleY = static_cast<ssfp_t>(h) / std::max(1e-12, ymax - ymin); |
| 1125 | |
| 1126 | out.reserve(w * 3 / 2 + 8); |
| 1127 | for (std::size_t c = 0; c < C; ++c) { |
| 1128 | if (ws->cnt[c] == 0) |
| 1129 | continue; |
| 1130 | |
| 1131 | dsEmitColumnPoints(c, scaleY, ws, xAt, yAt, out); |
| 1132 | } |
| 1133 | |
| 1134 | return true; |
| 1135 | } |
| 1136 | |
| 1137 | /** |
| 1138 | * @brief Downsample a LineSeries (paired X and Y AxisData) for rendering. |
no test coverage detected