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);
};
/**
- * 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,
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;
}
if (ty == "hdgToAlt") {
flyOver = true;
}
+ } else if (ty == "discontinuity") {
+
} else {
pos = wpt->position();
posValid = true;
}
}
- 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;
}
legCourseTrue = SGGeodesy::courseDeg(previous.pos, pos);
legCourseValid = true;
}
- }
+ } // of not a VIA
}
void computeLegCourse(const WayptData& previous, double radiusM)
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<RunwayWaypt*>(wpt.get())->runway();
flyOver = true;
legCourseTrue = wpt->headingRadialDeg() + magVar;
legCourseValid = true;
} // of pos not valid
- } // of neither hold nor runway
+ } // of general case
}
SGGeod pointOnEntryTurnFromHeading(double headingDeg) 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<Via*>(d->waypoints[index].wpt.get()), index);
+ }
if (ty== "hold") {
return pathForHold((Hold*) d->waypoints[index].wpt.get());
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;
return 0.0;
}
+
+ if (d->waypoints[index].wpt->type() == "via") {
+ return distanceForVia(static_cast<Via*>(d->waypoints[index].wpt.get()), index);
+ }
+
const WayptData& prev(d->previousValidWaypoint(index));
double dist = SGGeodesy::distanceM(prev.turnExitPos,
d->waypoints[index].turnEntryPos);
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)
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<Via*>(next.wpt.get()), index, distanceM);
+ }
if (wpt.turnPathDistanceM > distanceM) {
// on the exit path of current wpt
// 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
+{
+
+}