From 7afedb1702829b244fcf998391a83833efee7f01 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 22 Nov 2015 20:14:03 +0000 Subject: [PATCH] Work on visualisation of Vias --- src/GUI/WaypointList.cxx | 68 +++++++++++++++++------------ src/Navaids/routePath.cxx | 92 +++++++++++++++++++++++++++++++++++---- src/Navaids/routePath.hxx | 9 +++- 3 files changed, 129 insertions(+), 40 deletions(-) diff --git a/src/GUI/WaypointList.cxx b/src/GUI/WaypointList.cxx index 93384c348..5b010f0d2 100644 --- a/src/GUI/WaypointList.cxx +++ b/src/GUI/WaypointList.cxx @@ -465,42 +465,52 @@ void WaypointList::drawRow(int dx, int dy, int rowIndex, int y, void WaypointList::drawRowText(int x, int baseline, int rowIndex, const RoutePath& path) { flightgear::Waypt* wp(_model->waypointAt(rowIndex)); - bool isDiscontinuity = (wp->type() == "discontinuity"); + const bool isDiscontinuity = (wp->type() == "discontinuity"); + const bool isVia = (wp->type() == "via"); char buffer[128]; - int count = ::snprintf(buffer, 128, "%03d %-5s", rowIndex, wp->ident().c_str()); + int count; - FGPositioned* src = wp->source(); - if (src && !src->name().empty() && (src->name() != wp->ident())) { - // append name if present, and different to id - ::snprintf(buffer + count, 128 - count, " (%s)", src->name().c_str()); - } + if (isVia) { + // VIA has long ident but no name + count = ::snprintf(buffer, 128, "%03d %s", rowIndex, wp->ident().c_str()); + drawClippedString(legendFont, buffer, x, baseline, 300); + x += 300 + PUSTR_LGAP; + } else { + count = ::snprintf(buffer, 128, "%03d %-5s", rowIndex, wp->ident().c_str()); - drawClippedString(legendFont, buffer, x, baseline, 300); - x += 300 + PUSTR_LGAP; + FGPositioned* src = wp->source(); + if (src && !src->name().empty() && (src->name() != wp->ident())) { + // append name if present, and different to id + ::snprintf(buffer + count, 128 - count, " (%s)", src->name().c_str()); + } - if (isDiscontinuity) { - return; - } + drawClippedString(legendFont, buffer, x, baseline, 300); + x += 300 + PUSTR_LGAP; - if (_showLatLon) { - // only show for non-dynamic waypoints - if (!wp->flag(WPT_DYNAMIC)) { - SGGeod p(wp->position()); - char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S'; - char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W'; + if (isDiscontinuity) { + return; + } - ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c", - fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns); - } else { - buffer[0] = 0; - } - } else if (rowIndex > 0) { - double courseDeg = path.trackForIndex(rowIndex); - double distanceM = path.distanceForIndex(rowIndex); - ::snprintf(buffer, 128 - count, "%03.0f %5.1fnm", - courseDeg, distanceM * SG_METER_TO_NM); - } + if (_showLatLon) { + // only show for non-dynamic waypoints + if (!wp->flag(WPT_DYNAMIC)) { + SGGeod p(wp->position()); + char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S'; + char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W'; + + ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c", + fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns); + } else { + buffer[0] = 0; + } + } else if (rowIndex > 0) { + double courseDeg = path.trackForIndex(rowIndex); + double distanceM = path.distanceForIndex(rowIndex); + ::snprintf(buffer, 128 - count, "%03.0f %5.1fnm", + courseDeg, distanceM * SG_METER_TO_NM); + } + } // of is not a VIA waypoint puFont* f = &legendFont; f->drawString(buffer, x, baseline); diff --git a/src/Navaids/routePath.cxx b/src/Navaids/routePath.cxx index cae2fd711..8f7ccb668 100644 --- a/src/Navaids/routePath.cxx +++ b/src/Navaids/routePath.cxx @@ -179,8 +179,8 @@ struct TurnInfo }; /** - * given a turn exit position and heading, and an arbitrary origin postion, - * compute the turn center / angle the matches. Certain configurations may + * given a turn exit position and heading, and an arbitrary origin position, + * compute the turn center / angle that matches. Certain configurations may * fail, especially if the origin is less than two turn radii from the exit pos. */ TurnInfo turnCenterAndAngleFromExit(const SGGeod& pt, double outHeadingDeg, @@ -199,7 +199,7 @@ TurnInfo turnCenterAndAngleFromExit(const SGGeod& pt, double outHeadingDeg, double courseToTC, distanceToTC, az2; SGGeodesy::inverse(origin, r.turnCenter, courseToTC, az2, distanceToTC); if (distanceToTC < turnRadiusM) { - SG_LOG(SG_NAVAID, SG_WARN, "turnCenterAndAngleFromExit: origin point to close to turn center"); + SG_LOG(SG_NAVAID, SG_WARN, "turnCenterAndAngleFromExit: origin point too close to turn center"); return r; } @@ -253,6 +253,8 @@ public: if (ty == "hdgToAlt") { flyOver = true; } + } else if (ty == "discontinuity") { + } else { pos = wpt->position(); posValid = true; @@ -284,8 +286,11 @@ public: } } - if (posValid && !legCourseValid && previous.posValid) { - // check for duplicate points now + if (wpt->type() == "via") { + // even though both ends may be known, we don't + // want to compute a leg course for a VIA + } else if (posValid && !legCourseValid && previous.posValid) { + // check for duplicate points now if (previous.wpt->matches(wpt)) { skipped = true; } @@ -300,7 +305,7 @@ public: legCourseTrue = SGGeodesy::courseDeg(previous.pos, pos); legCourseValid = true; } - } + } // of not a VIA } void computeLegCourse(const WayptData& previous, double radiusM) @@ -309,8 +314,12 @@ public: return; } - if (wpt->type() == "hold") { - + if ((wpt->type() == "hold") || + (wpt->type() == "discontinuity") || + (wpt->type() == "via")) + { + // do nothing, we can't compute a valid leg course for these types + // we'll generate shrap turns in the path but that's no problem. } else if (wpt->type() == "runway") { FGRunway* rwy = static_cast(wpt.get())->runway(); flyOver = true; @@ -339,7 +348,7 @@ public: legCourseTrue = wpt->headingRadialDeg() + magVar; legCourseValid = true; } // of pos not valid - } // of neither hold nor runway + } // of general case } SGGeod pointOnEntryTurnFromHeading(double headingDeg) const @@ -1000,6 +1009,14 @@ SGGeodVec RoutePath::pathForIndex(int index) const // ideally we'd show a stippled line to connect the route? return SGGeodVec(); } + + if (ty == "discontinuity") { + return SGGeodVec(); // no points for a discontinuity of course + } + + if (ty == "via") { + return pathForVia(static_cast(d->waypoints[index].wpt.get()), index); + } if (ty== "hold") { return pathForHold((Hold*) d->waypoints[index].wpt.get()); @@ -1061,6 +1078,28 @@ SGGeod RoutePath::positionForIndex(int index) const return d->waypoints[index].pos; } +SGGeodVec RoutePath::pathForVia(Via* via, int index) const +{ + // previous waypoint must be valid for a VIA + if ((index == 0) || !d->waypoints[index-1].posValid) { + return SGGeodVec(); + } + + const WayptData& prev(d->waypoints[index-1]); + WayptVec enrouteWaypoints = via->expandToWaypoints(prev.wpt); + SGGeodVec r; + + WayptVec::const_iterator it; + SGGeod legStart = prev.wpt->position(); + for (it = enrouteWaypoints.begin(); it != enrouteWaypoints.end(); ++it) { + // interpolate directly into the result vector + interpolateGreatCircle(legStart, (*it)->position(), r); + legStart = (*it)->position(); + } + + return r; +} + SGGeodVec RoutePath::pathForHold(Hold* hold) const { int turnSteps = 16; @@ -1117,6 +1156,11 @@ double RoutePath::computeDistanceForIndex(int index) const return 0.0; } + + if (d->waypoints[index].wpt->type() == "via") { + return distanceForVia(static_cast(d->waypoints[index].wpt.get()), index); + } + const WayptData& prev(d->previousValidWaypoint(index)); double dist = SGGeodesy::distanceM(prev.turnExitPos, d->waypoints[index].turnEntryPos); @@ -1130,6 +1174,27 @@ double RoutePath::computeDistanceForIndex(int index) const return dist; } +double RoutePath::distanceForVia(Via* via, int index) const +{ + // previous waypoint must be valid for a VIA + if ((index == 0) || !d->waypoints[index-1].posValid) { + return 0.0; + } + + const WayptData& prev(d->waypoints[index-1]); + WayptVec enrouteWaypoints = via->expandToWaypoints(prev.wpt); + double dist = 0.0; + + WayptVec::const_iterator it; + SGGeod legStart = prev.wpt->position(); + for (it = enrouteWaypoints.begin(); it != enrouteWaypoints.end(); ++it) { + dist += SGGeodesy::distanceM(legStart, (*it)->position()); + legStart = (*it)->position(); + } + + return dist; +} + double RoutePath::trackForIndex(int index) const { if (d->waypoints[index].skipped) @@ -1190,8 +1255,12 @@ SGGeod RoutePath::positionForDistanceFrom(int index, double distanceM) const return d->waypoints[sz - 1].pos; } + const WayptData& wpt(d->waypoints[index]); const WayptData& next(d->waypoints[index+1]); + if (next.wpt->type() == "via") { + return positionAlongVia(static_cast(next.wpt.get()), index, distanceM); + } if (wpt.turnPathDistanceM > distanceM) { // on the exit path of current wpt @@ -1209,3 +1278,8 @@ SGGeod RoutePath::positionForDistanceFrom(int index, double distanceM) const // linear between turn exit and turn entry points return SGGeodesy::direct(wpt.turnExitPos, next.legCourseTrue, distanceM); } + +SGGeod RoutePath::positionAlongVia(Via* via, int previousIndex, double distanceM) const +{ + +} diff --git a/src/Navaids/routePath.hxx b/src/Navaids/routePath.hxx index 49b44de4a..b6e3102bf 100644 --- a/src/Navaids/routePath.hxx +++ b/src/Navaids/routePath.hxx @@ -31,6 +31,7 @@ namespace flightgear { class Hold; class FlightPlan; + class Via; } typedef std::vector SGGeodVec; @@ -59,9 +60,13 @@ private: void commonInit(); double computeDistanceForIndex(int index) const; - + + double distanceForVia(flightgear::Via *via, int index) const; + + SGGeodVec pathForHold(flightgear::Hold* hold) const; - + SGGeodVec pathForVia(flightgear::Via* via, int index) const; + SGGeod positionAlongVia(flightgear::Via* via, int previousIndex, double distanceM) const; void interpolateGreatCircle(const SGGeod& aFrom, const SGGeod& aTo, SGGeodVec& r) const; -- 2.39.5