コード例 #1
0
ファイル: WaypointReaderFS.cpp プロジェクト: damianob/xcsoar
bool
WaypointReaderFS::ParseLine(const TCHAR* line, const unsigned linenum,
                              Waypoints &way_points)
{
  //$FormatGEO
  //ACONCAGU  S 32 39 12.00    W 070 00 42.00  6962  Aconcagua
  //BERGNEUS  N 51 03 07.02    E 007 42 22.02   488  Bergneustadt [A]
  //GOLDENGA  N 37 49 03.00    W 122 28 42.00   227  Golden Gate Bridge
  //REDSQUAR  N 55 45 15.00    E 037 37 12.00   123  Red Square
  //SYDNEYOP  S 33 51 25.02    E 151 12 54.96     5  Sydney Opera

  //$FormatUTM
  //Aconcagu 19H   0405124   6386692   6962  Aconcagua
  //Bergneus 32U   0409312   5656398    488  Bergneustadt [A]
  //Golden G 10S   0545914   4185695    227  Golden Gate Bridge
  //Red Squa 37U   0413390   6179582    123  Red Square
  //Sydney O 56H   0334898   6252272      5  Sydney Opera

  if (line[0] == '\0')
    return true;

  if (linenum == 0 &&
      _tcsstr(line, _T("$FormatUTM")) == line) {
    is_utm = true;
    return true;
  }

  if (line[0] == _T('$'))
    return true;

  // Determine the length of the line
  size_t len = _tcslen(line);
  // If less then 27 characters -> something is wrong -> cancel
  if (len < (is_utm ? 39 : 47))
    return false;

  GeoPoint location;
  if ((!is_utm && !ParseLocation(line + 10, location)) ||
      (is_utm && !ParseLocationUTM(line + 9, location)))
    return false;

  Waypoint new_waypoint(location);
  new_waypoint.file_num = file_num;
  new_waypoint.original_id = 0;

  if (!ParseString(line, new_waypoint.name, 8))
    return false;

  if (!ParseAltitude(line + (is_utm ? 32 : 41), new_waypoint.elevation) &&
      !CheckAltitude(new_waypoint))
    return false;

  // Description (Characters 35-44)
  if (len > (is_utm ? 38 : 47))
    ParseString(line + (is_utm ? 38 : 47), new_waypoint.comment);

  way_points.Append(new_waypoint);
  return true;
}
コード例 #2
0
ファイル: WaypointReaderOzi.cpp プロジェクト: kwtskran/XCSoar
bool
WaypointReaderOzi::ParseLine(const TCHAR *line, Waypoints &way_points)
{
  if (line[0] == '\0')
    return true;

  // Ignore first four header lines
  if (ignore_lines > 0) {
    --ignore_lines;
    return true;
  }

  TCHAR ctemp[255];
  const TCHAR *params[20];
  static constexpr unsigned int max_params = ARRAY_SIZE(params);
  size_t n_params;

  if (_tcslen(line) >= ARRAY_SIZE(ctemp))
    /* line too long for buffer */
    return false;

  // Get fields
  n_params = ExtractParameters(line, ctemp, params, max_params, true, _T('"'));

  // Check if the basic fields are provided
  if (n_params < 15)
    return false;

  GeoPoint location;
  // Latitude (e.g. 5115.900N)
  if (!ParseAngle(params[2], location.latitude))
    return false;

  // Longitude (e.g. 00715.900W)
  if (!ParseAngle(params[3], location.longitude))
    return false;

  location.Normalize(); // ensure longitude is within -180:180

  Waypoint new_waypoint = factory.Create(location);

  long value;
  new_waypoint.original_id = (ParseNumber(params[0], value) ? value : 0);

  if (!ParseString(params[1], new_waypoint.name))
    return false;

  if (ParseNumber(params[14], value) && value != -777)
    new_waypoint.elevation = Units::ToSysUnit(value, Unit::FEET);
  else if (!factory.FallbackElevation(new_waypoint))
    return false;

  // Description (Characters 35-44)
  ParseString(params[11], new_waypoint.comment);

  way_points.Append(std::move(new_waypoint));
  return true;
}
コード例 #3
0
bool
WaypointReaderZander::ParseLine(const TCHAR* line, const unsigned linenum,
                              Waypoints &way_points)
{
  // If (end-of-file or comment)
  if (line[0] == '\0' || line[0] == 0x1a ||
      _tcsstr(line, _T("**")) == line ||
      _tcsstr(line, _T("*")) == line)
    // -> return without error condition
    return true;

  // Determine the length of the line
  size_t len = _tcslen(line);
  // If less then 34 characters -> something is wrong -> cancel
  if (len < 34)
    return false;

  GeoPoint location;

  // Latitude (Characters 13-20 // DDMMSS(N/S))
  if (!ParseAngle(line + 13, location.latitude, true))
    return false;

  // Longitude (Characters 21-29 // DDDMMSS(E/W))
  if (!ParseAngle(line + 21, location.longitude, false))
    return false;

  location.Normalize(); // ensure longitude is within -180:180

  Waypoint new_waypoint(location);
  new_waypoint.file_num = file_num;
  new_waypoint.original_id = 0;

  // Name (Characters 0-12)
  if (!ParseString(line, new_waypoint.name, 12))
    return false;

  // Altitude (Characters 30-34 // e.g. 1561 (in meters))
  /// @todo configurable behaviour
  if (!ParseAltitude(line + 30, new_waypoint.elevation) &&
      !CheckAltitude(new_waypoint))
    return false;

  // Description (Characters 35-44)
  if (len > 35)
    ParseString(line + 35, new_waypoint.comment, 9);

  // Flags (Characters 45-49)
  if (len < 46 || !ParseFlags(line + 45, new_waypoint))
    if (len < 36 || !ParseFlagsFromDescription(line + 35, new_waypoint))
      new_waypoint.flags.turn_point = true;

  way_points.Append(new_waypoint);
  return true;
}
コード例 #4
0
ファイル: TestWaypoints.cpp プロジェクト: kwtskran/XCSoar
static unsigned
TestCopy(Waypoints& waypoints)
{
  const WaypointPtr wp = waypoints.LookupId(5);
  if (!wp)
    return false;

  unsigned size_old = waypoints.size();
  Waypoint wp_copy = *wp;
  wp_copy.id = waypoints.size() + 1;
  waypoints.Append(std::move(wp_copy));
  waypoints.Optimise();
  unsigned size_new = waypoints.size();
  return (size_new == size_old + 1);
}
コード例 #5
0
ファイル: TestWaypoints.cpp プロジェクト: kwtskran/XCSoar
static void
AddSpiralWaypoints(Waypoints &waypoints,
                   const GeoPoint &center = GeoPoint(Angle::Degrees(51.4),
                                                     Angle::Degrees(7.85)),
                   Angle angle_start = Angle::Degrees(0),
                   Angle angle_step = Angle::Degrees(15),
                   fixed distance_start = fixed(0),
                   fixed distance_step = fixed(1000),
                   fixed distance_max = fixed(150000))
{
  assert(positive(distance_step));

  for (unsigned i = 0;; ++i) {
    GeoVector vector;
    vector.distance = distance_start + distance_step * i;
    if (vector.distance > distance_max)
      break;

    vector.bearing = angle_start + angle_step * i;

    Waypoint waypoint;
    waypoint.location = vector.EndPoint(center);
    waypoint.original_id = i;
    waypoint.elevation = fixed(i * 10 - 500);

    StaticString<256> buffer;

    if (i % 7 == 0) {
      buffer = _T("Airfield");
      waypoint.type = Waypoint::Type::AIRFIELD;
    } else if (i % 3 == 0) {
      buffer = _T("Field");
      waypoint.type = Waypoint::Type::OUTLANDING;
    } else
      buffer = _T("Waypoint");

    buffer.AppendFormat(_T(" #%d"), i + 1);
    waypoint.name = buffer;

    waypoints.Append(std::move(waypoint));
  }

  waypoints.Optimise();
}
コード例 #6
0
bool
WaypointReaderSeeYou::ParseLine(const TCHAR* line, Waypoints &waypoints)
{
  enum {
    iName = 0,
    iLatitude = 3,
    iLongitude = 4,
    iElevation = 5,
    iStyle = 6,
    iRWDir = 7,
    iRWLen = 8,
    iFrequency = 9,
    iDescription = 10,
  };

  if (first) {
    first = false;

    /* skip first line if it doesn't begin with a quotation character
       (usually the field order line) */
    if (line[0] != _T('\"'))
      return true;
  }

  // If (end-of-file or comment)
  if (StringIsEmpty(line) ||
      StringStartsWith(line, _T("*")))
    // -> return without error condition
    return true;

  TCHAR ctemp[4096];
  if (_tcslen(line) >= ARRAY_SIZE(ctemp))
    /* line too long for buffer */
    return false;

  // If task marker is reached ignore all following lines
  if (StringStartsWith(line, _T("-----Related Tasks-----")))
    ignore_following = true;
  if (ignore_following)
    return true;

  // Get fields
  const TCHAR *params[20];
  size_t n_params = ExtractParameters(line, ctemp, params,
                                      ARRAY_SIZE(params), true, _T('"'));

  // Check if the basic fields are provided
  if (iName >= n_params ||
      iLatitude >= n_params ||
      iLongitude >= n_params)
    return false;

  GeoPoint location;

  // Latitude (e.g. 5115.900N)
  if (!ParseAngle(params[iLatitude], location.latitude, true))
    return false;

  // Longitude (e.g. 00715.900W)
  if (!ParseAngle(params[iLongitude], location.longitude, false))
    return false;

  location.Normalize(); // ensure longitude is within -180:180

  Waypoint new_waypoint = factory.Create(location);

  // Name (e.g. "Some Turnpoint")
  if (*params[iName] == _T('\0'))
    return false;
  new_waypoint.name = params[iName];

  // Elevation (e.g. 458.0m)
  /// @todo configurable behaviour
  if ((iElevation >= n_params ||
      !ParseAltitude(params[iElevation], new_waypoint.elevation)) &&
      !factory.FallbackElevation(new_waypoint))
    return false;

  // Style (e.g. 5)
  if (iStyle < n_params)
    ParseStyle(params[iStyle], new_waypoint.type);

  new_waypoint.flags.turn_point = true;

  // Frequency & runway direction/length (for airports and landables)
  // and description (e.g. "Some Description")
  if (new_waypoint.IsLandable()) {
    if (iFrequency < n_params)
      new_waypoint.radio_frequency = RadioFrequency::Parse(params[iFrequency]);

    // Runway length (e.g. 546.0m)
    double rwlen = -1;
    if (iRWLen < n_params && ParseDistance(params[iRWLen], rwlen) &&
        rwlen > 0)
      new_waypoint.runway.SetLength(uround(rwlen));

    if (iRWDir < n_params && *params[iRWDir]) {
      TCHAR *end;
      int direction =_tcstol(params[iRWDir], &end, 10);
      if (end == params[iRWDir] || direction < 0 || direction > 360 ||
          (direction == 0 && rwlen <= 0))
        direction = -1;
      else if (direction == 360)
        direction = 0;
      if (direction >= 0)
        new_waypoint.runway.SetDirectionDegrees(direction);
    }
  }

  if (iDescription < n_params) {
    /*
     * This convention was introduced by the OpenAIP
     * project (http://www.openaip.net/), since no waypoint type
     * exists for thermal hotspots.
     */
    if (StringStartsWith(params[iDescription], _T("Hotspot")))
      new_waypoint.type = Waypoint::Type::THERMAL_HOTSPOT;

    new_waypoint.comment = params[iDescription];
  }

  waypoints.Append(std::move(new_waypoint));
  return true;
}
コード例 #7
0
bool
WaypointReaderCompeGPS::ParseLine(const TCHAR* line, const unsigned linenum,
                                  Waypoints &waypoints)
{
  /*
   * G  WGS 84
   * U  1
   * W  IT05FC A 46.9121939503ºN 11.9605922700°E 27-MAR-62 00:00:00 566.000000 Ahornach Sand, Ahornach LP, GS und HG
   * w  Waypoint,0,-1.0,16777215,255,0,0,7,,0.0,
   * W  IT05FB A 46.9260440931ºN 11.9676733017°E 27-MAR-62 00:00:00 1425.000000 Ahornach Sand, Ahornach SP, GS und HG
   * w  Waypoint,0,-1.0,16777215,255,0,0,7,,0.0,
   *
   * W ShortName 31T 318570 4657569 27-MAR-62 00:00:00 0 some Comments
   * W ShortName A 41.234234N 7.234424W 27-MAR-62 00:00:00 0 Comments
   */

  // Skip projection and file encoding information
  if (*line == _T('G') || *line == _T('B'))
    return true;

  // Check for format: UTM or LatLon
  if (*line == _T('U') && _tcsstr(line, _T("U  0")) == line) {
    is_utm = true;
    return true;
  }

  // Skip non-waypoint lines
  if (*line != _T('W'))
    return true;

  // Skip W indicator and whitespace
  line++;
  while (*line == _T(' '))
    line++;

  // Find next space delimiter, skip shortname
  const TCHAR *name = line;
  const TCHAR *space = _tcsstr(line, _T(" "));
  if (space == NULL)
    return false;

  unsigned name_length = space - line;
  if (name_length == 0)
    return false;

  line = space;
  while (*line == _T(' '))
    line++;

  // Parse location
  GeoPoint location;
  if ((!is_utm && !ParseLocation(line, location)) ||
      (is_utm && !ParseLocationUTM(line, location)))
    return false;

  // Skip whitespace
  while (*line == _T(' '))
    line++;

  // Skip unused date field
  line = _tcsstr(line, _T(" "));
  if (line == NULL)
    return false;

  line++;

  // Skip unused time field
  line = _tcsstr(line, _T(" "));
  if (line == NULL)
    return false;

  line++;

  // Create new waypoint instance
  Waypoint waypoint(location);
  waypoint.file_num = file_num;
  waypoint.original_id = 0;
  waypoint.name.assign(name, name_length);

  // Parse altitude
  if (!ParseAltitude(line, waypoint.elevation) &&
      !CheckAltitude(waypoint))
    return false;

  // Skip whitespace
  while (*line == _T(' '))
    line++;

  // Parse waypoint name
  waypoint.comment.assign(line);

  waypoints.Append(std::move(waypoint));
  return true;
}
コード例 #8
0
bool
WaypointReaderWinPilot::ParseLine(const TCHAR *line, Waypoints &waypoints)
{
  TCHAR ctemp[4096];
  const TCHAR *params[20];
  static constexpr unsigned int max_params = ARRAY_SIZE(params);
  size_t n_params;

  // If (end-of-file)
  if (line[0] == '\0')
    // -> return without error condition
    return true;

  // If comment
  if (line[0] == _T('*')) {
    if (first) {
      first = false;
      welt2000_format = (_tcsstr(line, _T("WRITTEN BY WELT2000")) != nullptr);
    }

    // -> return without error condition
    return true;
  }

  if (_tcslen(line) >= ARRAY_SIZE(ctemp))
    /* line too long for buffer */
    return false;

  GeoPoint location;

  // Get fields
  n_params = ExtractParameters(line, ctemp, params, max_params, true);
  if (n_params < 6)
    return false;

  // Latitude (e.g. 51:15.900N)
  if (!ParseAngle(params[1], location.latitude, true))
    return false;

  // Longitude (e.g. 00715.900W)
  if (!ParseAngle(params[2], location.longitude, false))
    return false;
  location.Normalize(); // ensure longitude is within -180:180

  Waypoint new_waypoint = factory.Create(location);

  // Name (e.g. KAMPLI)
  if (*params[5] == _T('\0'))
    return false;
  new_waypoint.name=params[5];

  // Altitude (e.g. 458M)
  /// @todo configurable behaviour
  if (!ParseAltitude(params[3], new_waypoint.elevation) &&
      !factory.FallbackElevation(new_waypoint))
    return false;

  if (n_params > 6) {
    // Description (e.g. 119.750 Airport)
    new_waypoint.comment=params[6];
    if (welt2000_format)
      ParseRunwayDirection(params[6], new_waypoint.runway);
  }

  // Waypoint Flags (e.g. AT)
  ParseFlags(params[4], new_waypoint);

  waypoints.Append(std::move(new_waypoint));
  return true;
}
コード例 #9
0
ファイル: harness_waypoints.cpp プロジェクト: mobotics/XCSoar
/** 
 * Initialises waypoints with random and non-random waypoints
 * for testing
 *
 * @param waypoints waypoints class to add waypoints to
 */
bool setup_waypoints(Waypoints &waypoints, const unsigned n) 
{

  Waypoint wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed_zero),
                                          Angle::Degrees(fixed_zero)));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(wp);

  wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed_zero), 
                                 Angle::Degrees(fixed_one)));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(wp);

  wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed_one), 
                                 Angle::Degrees(fixed_one)));
  wp.name = _T("Hello");
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed_half;
  waypoints.Append(wp);

  wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed(0.8)), 
                                 Angle::Degrees(fixed(0.5))));
  wp.name = _T("Unk");
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(wp);

  wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed_one), 
                                 Angle::Degrees(fixed_zero)));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(wp);

  wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed_zero), 
                                 Angle::Degrees(fixed(0.23))));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(wp);

  for (unsigned i=0; i<(unsigned)std::max((int)n-6,0); i++) {
    int x = rand()%1200-100;
    int y = rand()%1200-100;
    double z = rand()% std::max(terrain_height,1);
    wp = waypoints.Create(GeoPoint(Angle::Degrees(fixed(x/1000.0)), 
                                   Angle::Degrees(fixed(y/1000.0))));
    wp.type = Waypoint::Type::NORMAL;
    wp.elevation = fixed(z);
    waypoints.Append(wp);
  }
  waypoints.Optimise();

  if (verbose) {
    std::ofstream fin("results/res-wp-in.txt");
    for (unsigned i=1; i<=waypoints.size(); i++) {
      const Waypoint *wp = waypoints.LookupId(i);
      if (wp != NULL)
        fin << *wp;
    }
  }
  return true;
}
コード例 #10
0
bool
WaypointReaderSeeYou::ParseLine(const TCHAR* line, const unsigned linenum,
                              Waypoints &waypoints)
{
  enum {
    iName = 0,
    iLatitude = 3,
    iLongitude = 4,
    iElevation = 5,
    iStyle = 6,
    iRWDir = 7,
    iRWLen = 8,
    iFrequency = 9,
    iDescription = 10,
  };

  if (linenum == 0)
    ignore_following = false;

  // If (end-of-file or comment)
  if (StringIsEmpty(line) ||
      StringStartsWith(line, _T("**")) ||
      StringStartsWith(line, _T("*")))
    // -> return without error condition
    return true;

  TCHAR ctemp[4096];
  if (_tcslen(line) >= ARRAY_SIZE(ctemp))
    /* line too long for buffer */
    return false;

  // Skip first line if it doesn't begin with a quotation character
  // (usually the field order line)
  if (linenum == 0 && line[0] != _T('\"'))
    return true;

  // If task marker is reached ignore all following lines
  if (_tcsstr(line, _T("-----Related Tasks-----")) == line)
    ignore_following = true;
  if (ignore_following)
    return true;

  // Get fields
  const TCHAR *params[20];
  size_t n_params = ExtractParameters(line, ctemp, params,
                                      ARRAY_SIZE(params), true, _T('"'));

  // Check if the basic fields are provided
  if (iName >= n_params ||
      iLatitude >= n_params ||
      iLongitude >= n_params)
    return false;

  Waypoint new_waypoint;

  // Latitude (e.g. 5115.900N)
  if (!ParseAngle(params[iLatitude], new_waypoint.location.latitude, true))
    return false;

  // Longitude (e.g. 00715.900W)
  if (!ParseAngle(params[iLongitude], new_waypoint.location.longitude, false))
    return false;

  new_waypoint.location.Normalize(); // ensure longitude is within -180:180

  new_waypoint.file_num = file_num;
  new_waypoint.original_id = 0;

  // Name (e.g. "Some Turnpoint")
  if (*params[iName] == _T('\0'))
    return false;
  new_waypoint.name = params[iName];

  // Elevation (e.g. 458.0m)
  /// @todo configurable behaviour
  if ((iElevation >= n_params ||
      !ParseAltitude(params[iElevation], new_waypoint.elevation)) &&
      !CheckAltitude(new_waypoint))
    return false;

  // Style (e.g. 5)
  if (iStyle < n_params)
    ParseStyle(params[iStyle], new_waypoint.type);

  new_waypoint.flags.turn_point = true;

  // Frequency & runway direction/length (for airports and landables)
  // and description (e.g. "Some Description")
  if (new_waypoint.IsLandable()) {
    if (iFrequency < n_params)
      new_waypoint.radio_frequency = RadioFrequency::Parse(params[iFrequency]);

    // Runway length (e.g. 546.0m)
    fixed rwlen = fixed_minus_one;
    if (iRWLen < n_params && ParseDistance(params[iRWLen], rwlen) &&
        positive(rwlen))
      new_waypoint.runway.SetLength(uround(rwlen));

    if (iRWDir < n_params && *params[iRWDir]) {
      TCHAR *end;
      int direction =_tcstol(params[iRWDir], &end, 10);
      if (end == params[iRWDir] || direction < 0 || direction > 360 ||
          (direction == 0 && !positive(rwlen)))
        direction = -1;
      else if (direction == 360)
        direction = 0;
      if (direction >= 0)
        new_waypoint.runway.SetDirectionDegrees(direction);
    }
  }

  if (iDescription < n_params)
    new_waypoint.comment = params[iDescription];

  waypoints.Append(new_waypoint);
  return true;
}
コード例 #11
0
/** 
 * Initialises waypoints with random and non-random waypoints
 * for testing
 *
 * @param waypoints waypoints class to add waypoints to
 */
bool SetupWaypoints(Waypoints &waypoints, const unsigned n)
{
  Waypoint wp = waypoints.Create(GeoPoint(Angle::Zero(),
                                          Angle::Zero()));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(std::move(wp));

  wp = waypoints.Create(GeoPoint(Angle::Zero(),
                                 Angle::Degrees(1)));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(std::move(wp));

  wp = waypoints.Create(GeoPoint(Angle::Degrees(1),
                                 Angle::Degrees(1)));
  wp.name = _T("Hello");
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.5);
  waypoints.Append(std::move(wp));

  wp = waypoints.Create(GeoPoint(Angle::Degrees(0.8),
                                 Angle::Degrees(0.5)));
  wp.name = _T("Unk");
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(std::move(wp));

  wp = waypoints.Create(GeoPoint(Angle::Degrees(1),
                                 Angle::Zero()));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(std::move(wp));

  wp = waypoints.Create(GeoPoint(Angle::Zero(),
                                 Angle::Degrees(0.23)));
  wp.type = Waypoint::Type::AIRFIELD;
  wp.elevation = fixed(0.25);
  waypoints.Append(std::move(wp));

  for (unsigned i=0; i<(unsigned)std::max((int)n-6,0); i++) {
    int x = rand()%1200-100;
    int y = rand()%1200-100;
    double z = rand()% std::max(terrain_height,1);
    wp = waypoints.Create(GeoPoint(Angle::Degrees(x / 1000.0),
                                   Angle::Degrees(y / 1000.0)));
    wp.type = Waypoint::Type::NORMAL;
    wp.elevation = fixed(z);
    waypoints.Append(std::move(wp));
  }
  waypoints.Optimise();

  if (verbose) {
    Directory::Create(Path(_T("output/results")));
    std::ofstream fin("output/results/res-wp-in.txt");
    for (unsigned i=1; i<=waypoints.size(); i++) {
      const Waypoint *wpt = waypoints.LookupId(i);
      if (wpt != NULL)
        fin << *wpt;
    }
  }
  return true;
}