void ChartRenderer::ScaleYFromData(const LeastSquares &lsdata) { if (lsdata.IsEmpty()) return; if (y.unscaled) { y.min = lsdata.GetMinY(); y.max = lsdata.GetMaxY(); y.unscaled = false; } else { y.min = std::min(y.min, lsdata.GetMinY()); y.max = std::max(y.max, lsdata.GetMaxY()); } if (lsdata.HasResult()) { auto y0 = lsdata.GetYAtMinX(); auto y1 = lsdata.GetYAtMaxX(); y.min = std::min({y.min, y0, y1}); y.max = std::max({y.max, y0, y1}); } if (fabs(y.max - y.min) > 50) { y.scale = (y.max - y.min); if (y.scale > 0) y.scale = (rc.bottom - rc.top - padding_bottom) / y.scale; } else { y.scale = 2000; } }
void ChartRenderer::DrawTrendN(const LeastSquares &lsdata, ChartLook::Style style) { if (!lsdata.HasResult()) return; if (x.unscaled || y.unscaled) return; double xmin = 0.5; double xmax = lsdata.GetCount() + 0.5; double ymin = lsdata.GetYAtMinX(); double ymax = lsdata.GetYAtMaxX(); DrawLine(xmin, ymin, xmax, ymax, look.GetPen(style)); }
void ChartRenderer::ScaleXFromData(const LeastSquares &lsdata) { if (lsdata.IsEmpty()) return; if (x.unscaled) { x.min = lsdata.GetMinX(); x.max = lsdata.GetMaxX(); x.unscaled = false; } else { x.min = std::min(x.min, lsdata.GetMinX()); x.max = std::max(x.max, lsdata.GetMaxX()); } x.scale = (x.max - x.min); if (x.scale > 0) x.scale = (rc.right - rc.left - padding_left) / x.scale; }
void ChartRenderer::DrawLineGraph(const LeastSquares &lsdata, const Pen &pen) { const auto &slots = lsdata.GetSlots(); assert(slots.size() >= 2); const unsigned n = slots.size(); RasterPoint *points = point_buffer.get(n); RasterPoint *p = points; for (const auto &i : slots) *p++ = ToScreen(i.x, i.y); assert(p == points + n); canvas.Select(pen); canvas.DrawPolyline(points, n); }
void ChartRenderer::DrawFilledLineGraph(const LeastSquares &lsdata) { const auto &slots = lsdata.GetSlots(); assert(slots.size() >= 2); const unsigned n = slots.size() + 2; RasterPoint *points = point_buffer.get(n); RasterPoint *p = points; for (const auto &i : slots) *p++ = ToScreen(i.x, i.y); const RasterPoint &last = p[-1]; *p++ = RasterPoint{ last.x, rc.bottom - padding_bottom }; *p++ = RasterPoint{ points[0].x, rc.bottom - padding_bottom }; assert(p == points + n); canvas.DrawPolygon(points, n); }
void ChartRenderer::DrawBarChart(const LeastSquares &lsdata) { if (x.unscaled || y.unscaled) return; canvas.Select(look.bar_brush); canvas.SelectNullPen(); const auto &slots = lsdata.GetSlots(); for (unsigned i = 0, n = slots.size(); i != n; i++) { int xmin((i + 1.2) * x.scale + (rc.left + padding_left)); int ymin = ScreenY(y.min); int xmax((i + 1.8) * x.scale + (rc.left + padding_left)); int ymax = ScreenY(slots[i].y); canvas.Rectangle(xmin, ymin, xmax, ymax); } }
/** * Convert a #LeastSquares to a #WaveInfo. Returns * WaveInfo::Undefined() if there is no valid result in the * #LeastSquares instance. */ gcc_pure static WaveInfo GetWaveInfo(const LeastSquares &ls, const FlatProjection &projection, double time) { if (!ls.HasResult()) return WaveInfo::Undefined(); const FlatPoint flat_location(ls.GetMiddleX(), ls.GetAverageY()); const GeoPoint location(projection.Unproject(flat_location)); const GeoPoint a(projection.Unproject(FlatPoint(ls.GetMinX(), ls.GetYAtMinX()))); const GeoPoint b(projection.Unproject(FlatPoint(ls.GetMaxX(), ls.GetYAtMaxX()))); Angle bearing = a.Bearing(b); Angle normal = (bearing + Angle::QuarterCircle()).AsBearing(); return {location, a, b, normal, time}; }
int main() { LeastSquares test; // test simple uniform weight test.add(1,1); test.add(2,2); test.add(3,3); test.add(4,4); test.add(5,5); test.add(6,6); LeastSquares::Linear result = test.fitLinearVertical(); SINVARIANT(result.intercept == 0 && result.slope == 1); SINVARIANT(Double::eq(result.get(113), 113)); SINVARIANT(test.size() == 6); // test simple non-uniform weight test.clear(); test.add(-1,0, 0.25); test.add(0,1, 0.50); test.add(1,0, 0.25); result = test.fitLinearVertical(); // compare against hand calculation SINVARIANT(result.intercept == 0.5 && result.slope == 0); // test complex uniform weight test.clear(); test.add(24037007,-321.5); test.add(27040842,-322); test.add(28042496,-323); test.add(29043391,-314); test.add(31044518,-322); test.add(39048310,-311); test.add(62067122,-317.5); test.add(116106946,-300); test.add(117107339,-301.5); test.add(118108081,-290); test.add(119109345,-296); test.add(120110256,-294.5); test.add(122113491,-289); test.add(125114789,-293.5); test.add(126115896,-296.5); test.add(127116738,-292.5); test.add(128116805,-283); test.add(129116889,-285); test.add(130116954,-281); test.add(131117031,-279); test.add(132117104,-279); test.add(133117182,-278); test.add(134117254,-273); test.add(135117331,-275.5); test.add(136118414,-278.5); test.add(137119481,-275); test.add(138119556,-274.5); test.add(139119633,-276); test.add(140119706,-273.5); test.add(141119784,-273); test.add(142119857,-273); test.add(143119954,-276); test.add(144120009,-268); test.add(145120085,-269); test.add(146120159,-269.5); test.add(147120235,-271); test.add(148120311,-267.5); test.add(149120387,-269); test.add(150120469,-269.5); result = test.fitLinearVertical(); // Results calculated using perl Statistics::OLS module INVARIANT(Double::eq(result.intercept,-334.874623780947) && Double::eq(result.slope, 4.10303516778801e-07), "bad"); // test complex uniform weight // the following numbers are manually randomly typed in test.clear(); test.add(23, -3.5, 0.1); test.add(-2, 10, 0.05); test.add(2, 30.5, 0.3); test.add(100, 45.3, 1.2); test.add(26.4, 75.3, 2.0); test.add(4.3, 57.2, 1.0); test.add(24, 23.0, 3.0); test.add(53, -40.2, 0.1); test.add(134, 1034.2, 0.56); test.add(5234, -304.56, 1.23); test.add(1345, -201.34, 3.24); test.add(21, 1123, 7.96); test.add(1, 367.34, 3.22); test.add(1345, 560.345, 0.32); test.add(5678, 272.101, 7.11); test.add(7890, 909.1, 8.09); test.add(4245, 232.5, 10.01); test.add(2490, 934, 21.89); test.add(345, 10293.3, 0.005); test.add(34, 984, 7.36); result = test.fitLinearVertical(); // Results calculated using perl Statistics::LineFit module INVARIANT(Double::eq(result.intercept, 662.946833319873) && Double::eq(result.slope, -0.0124699082339257), "bad"); cout << "Passed least_squares test\n"; return 0; }