#include "sailselection.h" #include "data_xp44.h" #include using namespace std; const vector SSC::zones { sail_data::zones }; string SSC::compute_range_tag(const sail_zone& z, double tws, double twa) const { const trapezoid& t {z.primary}; // interpolation ratio of tws within the zone's tws range at given twa const double twa_ratio {(twa - t.twa_min_thin) / (t.twa_max_thin - t.twa_min_thin)}; const double tws_min_at_twa {t.tws_min_thin + (t.tws_min_deep - t.tws_min_thin) * twa_ratio}; const double tws_max_at_twa {t.tws_max_thin + (t.tws_max_deep - t.tws_max_thin) * twa_ratio}; const double tws_ratio {(tws - tws_min_at_twa) / (tws_max_at_twa - tws_min_at_twa)}; // interpolation ratio of twa within the zone's twa range at given tws const double tws_ratio2 {(tws - t.tws_min_thin) / (t.tws_max_thin - t.tws_min_thin)}; const double twa_min_at_tws {t.twa_min_thin + (t.twa_min_deep - t.twa_min_thin) * tws_ratio2}; const double twa_max_at_tws {t.twa_max_thin + (t.twa_max_deep - t.twa_max_thin) * tws_ratio2}; const double twa_ratio2 {(twa - twa_min_at_tws) / (twa_max_at_tws - twa_min_at_tws)}; // combined position within zone const double position {(tws_ratio + twa_ratio2) / 2.0}; return position > 0.5 ? "uprange" : "downrange"; } string SSC::reef(double tws, double twa) const { bool r1 {false}; bool r2 {false}; for (const sail_zone& z : zones) { if (!z.is_reef) continue; const trapezoid& t {z.primary}; const double twa_ratio {(twa - t.twa_min_thin) / (t.twa_max_thin - t.twa_min_thin)}; const double tws_min_at_twa {t.tws_min_thin + (t.tws_min_deep - t.tws_min_thin) * twa_ratio}; const double tws_max_at_twa {t.tws_max_thin + (t.tws_max_deep - t.tws_max_thin) * twa_ratio}; const double tws_ratio {(tws - tws_min_at_twa) / (tws_max_at_twa - tws_min_at_twa)}; const double twa_min_at_tws {t.twa_min_thin + (t.twa_min_deep - t.twa_min_thin) * tws_ratio}; const double twa_max_at_tws {t.twa_max_thin + (t.twa_max_deep - t.twa_max_thin) * tws_ratio}; if (tws >= tws_min_at_twa && tws <= tws_max_at_twa && twa >= twa_min_at_tws && twa <= twa_max_at_tws) { if (z.name == "R1") r1 = true; if (z.name == "R2") r2 = true; } } if (r2) return "Reef 1 and Reef 2"; if (r1) return "Reef 1"; return ""; } vector SSC::lookup(double tws, double twa) const { vector results; for (const sail_zone& z : zones) { if (z.is_reef) continue; const trapezoid& p {z.primary}; const trapezoid& o {z.overlap}; // check if point is inside a trapezoid auto in_trap = [](const trapezoid& t, double tws, double twa) -> bool { const double twa_ratio {(twa - t.twa_min_thin) / (t.twa_max_thin - t.twa_min_thin)}; if (twa_ratio < 0.0 || twa_ratio > 1.0) return false; const double tws_min_at_twa {t.tws_min_thin + (t.tws_min_deep - t.tws_min_thin) * twa_ratio}; const double tws_max_at_twa {t.tws_max_thin + (t.tws_max_deep - t.tws_max_thin) * twa_ratio}; if (tws < tws_min_at_twa || tws > tws_max_at_twa) return false; const double tws_ratio {(tws - t.tws_min_thin) / (t.tws_max_thin - t.tws_min_thin)}; const double twa_min_at_tws {t.twa_min_thin + (t.twa_min_deep - t.twa_min_thin) * tws_ratio}; const double twa_max_at_tws {t.twa_max_thin + (t.twa_max_deep - t.twa_max_thin) * tws_ratio}; return twa >= twa_min_at_tws && twa <= twa_max_at_tws; }; const bool in_primary {in_trap(p, tws, twa)}; const bool in_overlap {in_trap(o, tws, twa)}; if (in_primary) { results.push_back({z.name, z.display_name, "", false}); } else if (in_overlap) { results.push_back({z.name, z.display_name, compute_range_tag(z, tws, twa), false}); } } // reef check stacks on top of sail results const string reef_str {reef(tws, twa)}; if (!reef_str.empty()) { results.push_back({"REEF", reef_str, "", true}); } return results; } ostream& operator<<(ostream& os, const sail_rec& r) { os << "

"; os << r.display_name; if (!r.range.empty()) { os << " — " << r.range; } if (r.is_reef) { os << " recommended"; } os << "

\n"; return os; }