コード例 #1
0
ファイル: BasicComputer.cpp プロジェクト: badbadc0ffee/XCSoar
/**
 * Calculates the vario values for gps vario, gps total energy vario
 * Sets Vario to GPSVario or received Vario data from instrument
 */
static void
ComputeGPSVario(MoreData &basic,
                const MoreData &last, const MoreData &last_gps)
{
  if (basic.noncomp_vario_available && last.noncomp_vario_available) {
    /* If we have a noncompensated vario signal, we use that to compute
       the "GPS" total energy vario value, even if navigate by GPS
       altitude is configured, because a vario is expected to be more
       exact. */

    /* use the "Validity" time stamp, because it reflects when this
       vertical speed was measured, and GPS time may not be available */
    const fixed delta_t =
      basic.noncomp_vario_available.GetTimeDifference(last.noncomp_vario_available);

    if (positive(delta_t)) {
      /* only update when a new value was received */

      fixed delta_e = basic.energy_height - last.energy_height;

      basic.gps_vario = basic.noncomp_vario;
      basic.gps_vario_TE = basic.noncomp_vario + delta_e / delta_t;
      basic.gps_vario_available = basic.noncomp_vario_available;
    }
  } else if (basic.pressure_altitude_available && last.pressure_altitude_available) {
    /* Barring that, we prefer pressure altitude for the "GPS" vario,
       even if navigate by GPS altitude is configured, because pressure
       altitude is expected to be more exact. */

    const fixed delta_t =
      basic.pressure_altitude_available.GetTimeDifference(last.pressure_altitude_available);

    if (positive(delta_t)) {
      /* only update when a new value was received */

      fixed delta_h = basic.pressure_altitude - last.pressure_altitude;
      fixed delta_e = basic.energy_height - last.energy_height;

      basic.gps_vario = delta_h / delta_t;
      basic.gps_vario_TE = (delta_h + delta_e) / delta_t;
      basic.gps_vario_available = basic.pressure_altitude_available;
    }
  } else if (basic.baro_altitude_available && last.baro_altitude_available) {
    /* barometric altitude is also ok, but it's rare that it is
       available when pressure altitude is not */

    const fixed delta_t =
      basic.baro_altitude_available.GetTimeDifference(last.baro_altitude_available);

    if (positive(delta_t)) {
      /* only update when a new value was received */

      fixed delta_h = basic.baro_altitude - last.baro_altitude;
      fixed delta_e = basic.energy_height - last.energy_height;

      basic.gps_vario = delta_h / delta_t;
      basic.gps_vario_TE = (delta_h + delta_e) / delta_t;
      basic.gps_vario_available = basic.baro_altitude_available;
    }
  } else if (basic.gps_altitude_available && last_gps.gps_altitude_available &&
             basic.time_available && last_gps.time_available) {
    /* use the GPS time stamp, because it reflects when this altitude
       was measured by the GPS receiver; the Validity object just
       shows when this value was parsed by XCSoar */
    const fixed delta_t = basic.time - last_gps.time;

    if (positive(delta_t)) {
      /* only update when a new value was received */

      fixed delta_h = basic.gps_altitude - last_gps.gps_altitude;
      fixed delta_e = basic.energy_height - last_gps.energy_height;

      basic.gps_vario = delta_h / delta_t;
      basic.gps_vario_TE = (delta_h + delta_e) / delta_t;
      basic.gps_vario_available = basic.gps_altitude_available;
    }
  } else {
    basic.gps_vario = basic.gps_vario_TE = fixed(0);
    basic.gps_vario_available.Clear();
  }
}
コード例 #2
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;
}
コード例 #3
0
bool 
GlideResult::IsFinalGlide() const 
{
  return IsOk() && !negative(altitude_difference) && !positive(height_climb);
}
コード例 #4
0
bool 
AbstractAirspace::Intercept(const AircraftState &state,
                            const AirspaceAircraftPerformance &perf,
                            AirspaceInterceptSolution &solution,
                            const GeoPoint &loc_start,
                            const GeoPoint &loc_end) const
{
  const bool only_vertical = (loc_start == loc_end) &&
                             (loc_start == state.location);

  const fixed distance_start = only_vertical ?
                               fixed_zero : state.location.Distance(loc_start);

  const fixed distance_end =
      (loc_start == loc_end) ?
      distance_start :
      (only_vertical ? fixed_zero : state.location.Distance(loc_end));

  AirspaceInterceptSolution solution_this =
    AirspaceInterceptSolution::Invalid();

  // need to scan at least three sides, top, far, bottom (if not terrain)

  AirspaceInterceptSolution solution_candidate =
    AirspaceInterceptSolution::Invalid();

  if (!only_vertical) {
    solution_candidate = InterceptVertical(state, perf, distance_start);
    // search near wall
    if (solution_candidate.IsValid() && 
        ((solution_candidate.elapsed_time < solution_this.elapsed_time) ||
         negative(solution_this.elapsed_time)))
      solution_this = solution_candidate;


    if (distance_end != distance_start) {
      // need to search far wall also
      solution_candidate = InterceptVertical(state, perf, distance_end);
      if (solution_candidate.IsValid() &&
          ((solution_candidate.elapsed_time < solution_this.elapsed_time) ||
           negative(solution_this.elapsed_time)))
        solution_this = solution_candidate;
    }
  }

  solution_candidate = InterceptHorizontal(state, perf, distance_start,
                                           distance_end, false);
  // search top wall
  if (solution_candidate.IsValid() && 
      ((solution_candidate.elapsed_time < solution_this.elapsed_time) ||
       negative(solution_this.elapsed_time)))
    solution_this = solution_candidate;
  
  // search bottom wall
  if (!altitude_base.IsTerrain()) {
    solution_candidate = InterceptHorizontal(state, perf, distance_start,
                                             distance_end, true);
    if (solution_candidate.IsValid() && 
        ((solution_candidate.elapsed_time < solution_this.elapsed_time) ||
         negative(solution_this.elapsed_time)))
      solution_this = solution_candidate;
  }

  if (solution_this.IsValid()) {
    solution = solution_this;
    if (solution.distance == distance_start)
      solution.location = loc_start;
    else if (solution.distance == distance_end)
      solution.location = loc_end;
    else if (positive(distance_end))
      solution.location =
          state.location.Interpolate(loc_end, solution.distance / distance_end);
    else
      solution.location = loc_start;

    assert(!negative(solution.distance));
    return true;
  }
  else
    solution = AirspaceInterceptSolution::Invalid();

  return false;
}
コード例 #5
0
ファイル: Deserialiser.cpp プロジェクト: ThomasXBMC/XCSoar
static ObservationZonePoint *
DeserialiseOZ(const Waypoint &wp, const ConstDataNode &node, bool is_turnpoint)
{
  const TCHAR *type = node.GetAttribute(_T("type"));
  if (type == nullptr)
    return nullptr;

  if (StringIsEqual(type, _T("Line"))) {
    LineSectorZone *ls = new LineSectorZone(wp.location);

    fixed length;
    if (node.GetAttribute(_T("length"), length) && positive(length))
      ls->SetLength(length);

    return ls;
  } else if (StringIsEqual(type, _T("Cylinder"))) {
    CylinderZone *ls = new CylinderZone(wp.location);

    fixed radius;
    if (node.GetAttribute(_T("radius"), radius) && positive(radius))
      ls->SetRadius(radius);

    return ls;
  } else if (StringIsEqual(type, _T("MatCylinder"))) {
    return CylinderZone::CreateMatCylinderZone(wp.location);
  } else if (StringIsEqual(type, _T("Sector"))) {

    fixed radius, inner_radius;
    Angle start, end;
    SectorZone *ls;

    if (node.GetAttribute(_T("inner_radius"), inner_radius)) {
      AnnularSectorZone *als = new AnnularSectorZone(wp.location);
      als->SetInnerRadius(inner_radius);
      ls = als;
    } else
      ls = new SectorZone(wp.location);

    if (node.GetAttribute(_T("radius"), radius) && positive(radius))
      ls->SetRadius(radius);
    if (node.GetAttribute(_T("start_radial"), start))
      ls->SetStartRadial(start);
    if (node.GetAttribute(_T("end_radial"), end))
      ls->SetEndRadial(end);

    return ls;
  } else if (StringIsEqual(type, _T("FAISector")))
    return SymmetricSectorZone::CreateFAISectorZone(wp.location, is_turnpoint);
  else if (StringIsEqual(type, _T("SymmetricQuadrant"))) {
    fixed radius = fixed(10000);
    node.GetAttribute(_T("radius"), radius);

    return new SymmetricSectorZone(wp.location, radius);
  } else if (StringIsEqual(type, _T("Keyhole")))
    return KeyholeZone::CreateDAeCKeyholeZone(wp.location);
  else if (StringIsEqual(type, _T("CustomKeyhole"))) {
    fixed radius = fixed(10000), inner_radius = fixed(500);
    Angle angle = Angle::QuarterCircle();

    node.GetAttribute(_T("radius"), radius);
    node.GetAttribute(_T("inner_radius"), inner_radius);
    node.GetAttribute(_T("angle"), angle);

    KeyholeZone *keyhole =
      KeyholeZone::CreateCustomKeyholeZone(wp.location, radius, angle);
    keyhole->SetInnerRadius(inner_radius);
    return keyhole;
  } else if (StringIsEqual(type, _T("BGAStartSector")))
    return KeyholeZone::CreateBGAStartSectorZone(wp.location);
  else if (StringIsEqual(type, _T("BGAFixedCourse")))
    return KeyholeZone::CreateBGAFixedCourseZone(wp.location);
  else if (StringIsEqual(type, _T("BGAEnhancedOption")))
    return KeyholeZone::CreateBGAEnhancedOptionZone(wp.location);

  return nullptr;
}
コード例 #6
0
ファイル: test_troute.cpp プロジェクト: davidswelt/XCSoar
static void
test_troute(const RasterMap& map, fixed mwind, fixed mc, RoughAltitude ceiling)
{
  GlideSettings settings;
  settings.SetDefaults();
  GlidePolar polar(mc);
  SpeedVector wind(Angle::Degrees(fixed(0)), mwind);
  TerrainRoute route;
  route.UpdatePolar(settings, polar, polar, wind);
  route.SetTerrain(&map);

  GeoPoint origin(map.GetMapCenter());

  fixed pd = map.pixel_distance(origin, 1);
  printf("# pixel size %g\n", (double)pd);

  bool retval= true;

  {
    std::ofstream fout ("results/terrain.txt");
    unsigned nx = 100;
    unsigned ny = 100;
    for (unsigned i=0; i< nx; ++i) {
      for (unsigned j=0; j< ny; ++j) {
        fixed fx = (fixed)i/(nx-1)*fixed_two-fixed_one;
        fixed fy = (fixed)j/(ny-1)*fixed_two-fixed_one;
        GeoPoint x(origin.longitude+Angle::Degrees(fixed(0.6)*fx),
                   origin.latitude+Angle::Degrees(fixed(0.4)*fy));
        short h = map.GetInterpolatedHeight(x);
        fout << x.longitude.Degrees() << " " << x.latitude.Degrees() << " " << h << "\n";
      }
      fout << "\n";
    }
    fout << "\n";
  }

  RoutePlannerConfig config;
  config.mode = RoutePlannerConfig::Mode::BOTH;

  unsigned i=0;
  for (fixed ang=fixed_zero; ang< fixed_two_pi; ang+= fixed_quarter_pi*fixed_half) {
    GeoPoint dest = GeoVector(fixed(40000.0), Angle::Radians(ang)).EndPoint(origin);

    short hdest = map.GetHeight(dest)+100;

    retval = route.Solve(AGeoPoint(origin,
                                   RoughAltitude(map.GetHeight(origin) + 100)),
                         AGeoPoint(dest,
                                   RoughAltitude(positive(mc)
                                                 ? hdest
                                                 : std::max(hdest, (short)3200))),
                         config, ceiling);
    char buffer[80];
    sprintf(buffer,"terrain route solve, dir=%g, wind=%g, mc=%g ceiling=%d",
            (double)ang, (double)mwind, (double)mc, (int)ceiling);
    ok(retval, buffer, 0);
    PrintHelper::print_route(route);
    i++;
  }

  // polar.SetMC(fixed_zero);
  // route.UpdatePolar(polar, wind);
}
コード例 #7
0
ファイル: CylinderZone.hpp プロジェクト: DRIZO/xcsoar
 /**
  * Set radius property
  *
  * @param new_radius Radius (m) of cylinder
  */
 virtual void SetRadius(fixed new_radius) {
   assert(positive(new_radius));
   radius = new_radius;
 }
コード例 #8
0
  bool ExcludeAltitude(const AbstractAirspace& airspace) {
    if (!positive(max_alt))
      return false;

    return (airspace.GetBaseAltitude(state) > max_alt);
  }
コード例 #9
0
ファイル: CylinderZone.hpp プロジェクト: DRIZO/xcsoar
 CylinderZone(const CylinderZone &other, const GeoPoint &reference)
   :ObservationZonePoint((const ObservationZonePoint &)other, reference),
    radius(other.radius) {
   assert(positive(radius));
 }
コード例 #10
0
ファイル: CylinderZone.hpp プロジェクト: DRIZO/xcsoar
 /**
  * Constructor.
  *
  * @param loc Location of center
  * @param _radius Radius (m) of cylinder
  *
  * @return Initialised object
  */
 CylinderZone(const GeoPoint &loc, const fixed _radius = fixed(10000.0))
   :ObservationZonePoint(Shape::CYLINDER, true, loc), radius(_radius) {
   assert(positive(radius));
 }
コード例 #11
0
ファイル: ui_base.cpp プロジェクト: Karlan88/xray
sPoly2D* C2DFrustum::ClipPoly	(sPoly2D& S, sPoly2D& D) const
{
	bool bFullTest		= false;
	for (u32 j=0; j<S.size(); j++)
	{
		if( !m_rect.in(S[j].pt) ) {
			bFullTest	= true;
			break		;
		}
	}

	sPoly2D*	src		= &D;
	sPoly2D*	dest	= &S;
	if(!bFullTest)		return dest;

	for (u32 i=0; i<planes.size(); i++)
	{
		// cache plane and swap lists
		const Fplane2 &P	= planes[i]	;
		std::swap			(src,dest)	;
		dest->clear			()			;

		// classify all points relative to plane #i
		float cls[UI_FRUSTUM_SAFE]	;
		for (u32 j=0; j<src->size(); j++) cls[j]=P.classify((*src)[j].pt);

		// clip everything to this plane
		cls[src->size()] = cls[0]	;
		src->push_back((*src)[0])	;
		Fvector2 dir_pt,dir_uv;		float denum,t;
		for (j=0; j<src->size()-1; j++)	{
			if ((*src)[j].pt.similar((*src)[j+1].pt,EPS_S)) continue;
			if (negative(cls[j]))	{
				dest->push_back((*src)[j])	;
				if (positive(cls[j+1]))	{
					// segment intersects plane
					dir_pt.sub((*src)[j+1].pt,(*src)[j].pt);
					dir_uv.sub((*src)[j+1].uv,(*src)[j].uv);
					denum = P.n.dotproduct(dir_pt);
					if (denum!=0) {
						t = -cls[j]/denum	; //VERIFY(t<=1.f && t>=0);
						dest->last().pt.mad	((*src)[j].pt,dir_pt,t);
						dest->last().uv.mad	((*src)[j].uv,dir_uv,t);
						dest->inc();
					}
				}
			} else {
				// J - outside
				if (negative(cls[j+1]))	{
					// J+1  - inside
					// segment intersects plane
					dir_pt.sub((*src)[j+1].pt,(*src)[j].pt);
					dir_uv.sub((*src)[j+1].uv,(*src)[j].uv);
					denum = P.n.dotproduct(dir_pt);
					if (denum!=0)	{
						t = -cls[j]/denum	; //VERIFY(t<=1.f && t>=0);
						dest->last().pt.mad	((*src)[j].pt,dir_pt,t);
						dest->last().uv.mad	((*src)[j].uv,dir_uv,t);
						dest->inc();
					}
				}
			}
		}

		// here we end up with complete polygon in 'dest' which is inside plane #i
		if (dest->size()<3) return 0;
	}
	return dest;
}
コード例 #12
0
ファイル: ScoredTaskPoint.hpp プロジェクト: ThomasXBMC/XCSoar
 /**
  * Check whether aircraft has entered the observation zone.
  *
  * @return True if observation zone has been entered
  */
 bool HasEntered() const {
   return positive(state_entered.time);
 }
コード例 #13
0
ファイル: FlyingComputer.cpp プロジェクト: StefanL74/XCSoar
void
FlyingComputer::Compute(fixed takeoff_speed,
                        const NMEAInfo &basic,
                        const DerivedInfo &calculated,
                        FlyingState &flying)
{
  if (!basic.time_available || !basic.location_available)
    return;

  const fixed dt = delta_time.Update(basic.time, fixed(0.5), fixed(20));
  if (negative(dt)) {
    Reset();
    flying.Reset();
  }

  if (!positive(dt))
    return;

  const auto any_altitude = basic.GetAnyAltitude();

  if (!basic.airspeed_available && !calculated.altitude_agl_valid &&
      any_altitude.first && !negative(last_ground_altitude) &&
      any_altitude.second > last_ground_altitude + fixed(250)) {
    /* lower the threshold for "not moving" when the aircraft is high
       above the take-off airfield and there's no airspeed probe; this
       shall reduce the risk of false landing detection when flying in
       strong head wind (e.g. ridge or wave) */
    fixed dh = any_altitude.second - last_ground_altitude;

    if (dh > fixed(1000))
      takeoff_speed /= 4;
    else if (dh > fixed(500))
      takeoff_speed /= 2;
    else
      takeoff_speed = takeoff_speed * 2 / 3;
  }

  if (CheckTakeOffSpeed(takeoff_speed, basic) ||
      CheckAltitudeAGL(calculated))
    Moving(flying, basic.time, dt, basic.location);
  else if (!flying.flying ||
           (CheckLandingSpeed(takeoff_speed, basic) &&
            (!any_altitude.first || !CheckClimbing(dt, any_altitude.second))))
    Stationary(flying, basic.time, dt, basic.location);

  if (any_altitude.first) {
    if (flying.on_ground)
      last_ground_altitude = any_altitude.second;

    CheckRelease(flying, basic.time, basic.location, any_altitude.second);
  } else
    sinking_since = fixed(-1);

  if (flying.flying && flying.release_location.IsValid()) {
    fixed distance = basic.location.Distance(flying.release_location);
    if (distance > flying.far_distance) {
      flying.far_location = basic.location;
      flying.far_distance = distance;
    }
  }
}
コード例 #14
0
ファイル: GlidePolar.cpp プロジェクト: alon/xcsoar
bool
GlidePolar::IsBallastable() const
{
  return positive(ballast_ratio);
}
コード例 #15
0
void
VarioBarRenderer::Draw(Canvas &canvas, const PixelRect &rc,
                            const MoreData &basic,
                            const DerivedInfo &calculated,
                            const GlidePolar &glide_polar,
                            const bool vario_bar_avg_enabled) const
{
#ifdef ENABLE_OPENGL
  const GLBlend blend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif

  RasterPoint VarioBar[6] = {
      { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 }
  };
  RasterPoint VarioBarAvg[4] = {
      { 0, 0 }, { 9, -9 }, { 9, 0 }, { 0, 0 }
  };
  RasterPoint clipping_arrow[6] = {
      { 0, 0 }, { 9, 9 }, { 18, 0 }, { 18, 6 }, { 9, 15 }, { 0, 6 }
  };
  RasterPoint clipping_arrow_av[4] = {
      { 0, 0 }, { 9, 9 }, { 9, 15 }, { 0, 6 }
  };
  RasterPoint mc_arrow[6] = {
      { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, -2 }, { 9, -11 }, { 0, -2 }
  };

  TCHAR Value[10];

  const int y0 = (rc.bottom + rc.top) / 2;

  /* NOTE: size_divisor replaces the fixed value 9 that was used throughout
   * the code sink which caused fixed size rendering regardless of
   * map size (except the effects of Layout::Scale()). This method
   * is not usable with variable map sizes (e.g. because of the cross-section
   * area). size_divisor is used to introduce a screen size dependent scaling.
   * That workaround is an ugly hack and needs a rework. */
  const auto size_divisor =
    std::max((fixed) Layout::Scale(70 / (rc.bottom - rc.top)), fixed(0.15));

  PixelScalar dy_variobar = 0;
  PixelScalar dy_variobar_av = 0;
  PixelScalar dy_variobar_mc = 0;

  PixelScalar clipping_arrow_offset = Layout::Scale(4);
  PixelScalar clipping_arrow_av_offset = Layout::Scale(4);
//  PixelScalar clipping_arrow_mc_offset = Layout::Scale(4);

  auto vario_gross = basic.brutto_vario;

  FormatUserVerticalSpeed(vario_gross, Value, false, true);
  canvas.Select(*look.font);
  const PixelSize text_size = canvas.CalcTextSize(Value);

  auto vario_avg = calculated.average;

  // cut vario_gross at +- 5 meters/s
  if (vario_gross > fixed(5))
    vario_gross = fixed(5);
  if (vario_gross < fixed(-5))
    vario_gross = fixed(-5);

  int Offset = (int)(vario_gross / size_divisor);

  Offset = Layout::Scale(Offset);
  if (!positive(vario_gross)) {
    VarioBar[1].y = Layout::Scale(9);
    dy_variobar = text_size.cy + 2;
  } else {
    VarioBar[1].y = -Layout::Scale(9);
    clipping_arrow[1].y = -clipping_arrow[1].y;
    clipping_arrow[3].y = -clipping_arrow[3].y;
    clipping_arrow[4].y = -clipping_arrow[4].y;
    clipping_arrow[5].y = -clipping_arrow[5].y;
    clipping_arrow_offset = -clipping_arrow_offset;
    dy_variobar = -1;
  }

  // cut vario_avg at +- 5 meters/s
  if (vario_avg > fixed(5))
    vario_avg = fixed(5);
  if (vario_avg < fixed(-5))
    vario_avg = fixed(-5);

  int OffsetAvg = int(vario_avg / size_divisor);

  OffsetAvg = Layout::Scale(OffsetAvg);
  if (!positive(vario_avg)) {
    VarioBarAvg[1].y = Layout::Scale(9);
    dy_variobar_av = text_size.cy + 2;
  } else {
    VarioBarAvg[1].y = -Layout::Scale(9);
    clipping_arrow_av[1].y = -clipping_arrow_av[1].y;
    clipping_arrow_av[2].y = -clipping_arrow_av[2].y;
    clipping_arrow_av[3].y = -clipping_arrow_av[3].y;
    clipping_arrow_av_offset = -clipping_arrow_av_offset;
    dy_variobar_av = -1;
  }


  //clip MC Value
  auto mc_val = glide_polar.GetMC();
  if (mc_val > fixed(5))
    mc_val = fixed(5);
  if (!positive(mc_val)) {
    dy_variobar_mc = text_size.cy + 2;
  }else{
    dy_variobar_mc = -1;
  }

  int OffsetMC = int(mc_val / size_divisor);
  OffsetMC = Layout::Scale(OffsetMC);

  for (unsigned i = 0; i < 6; i++) {
    VarioBar[i].y += y0 + dy_variobar;
    VarioBar[i].x = rc.right - Layout::Scale(VarioBar[i].x);
  }

  VarioBar[0].y -= Offset;
  VarioBar[1].y -= Offset;
  VarioBar[2].y -= Offset;

  for (unsigned i = 0; i < 4; i++) {
    VarioBarAvg[i].y += y0 + dy_variobar_av;
    VarioBarAvg[i].x = rc.right-Layout::Scale(VarioBarAvg[i].x);
  }

  VarioBarAvg[0].y -= OffsetAvg;
  VarioBarAvg[1].y -= OffsetAvg;

  // prepare mc arrow
  for (unsigned i = 0; i < 6; i++) {
    mc_arrow[i].y = Layout::Scale(mc_arrow[i].y) + y0
      - OffsetMC + dy_variobar_mc;
    mc_arrow[i].x = rc.right - Layout::Scale(mc_arrow[i].x);
  }

  // prepare clipping arrow
  for (unsigned i = 0; i < 6; i++) {
    clipping_arrow[i].y = Layout::Scale(clipping_arrow[i].y) + y0 - Offset
      + clipping_arrow_offset + dy_variobar;
    clipping_arrow[i].x = rc.right - Layout::Scale(clipping_arrow[i].x);
  }

  // prepare clipping avg
  for (unsigned i = 0; i < 4; i++) {
    clipping_arrow_av[i].y = Layout::Scale(clipping_arrow_av[i].y) + y0 - OffsetAvg
      + clipping_arrow_av_offset + dy_variobar_av;
    clipping_arrow_av[i].x = rc.right-Layout::Scale(clipping_arrow_av[i].x);
  }

  // draw actual vario bar
  if (!positive(vario_gross)) {
    canvas.Select(look.pen_sink);
    canvas.Select(look.brush_sink);
  } else {
    canvas.Select(look.pen_climb);
    canvas.Select(look.brush_climb);
  }

  canvas.DrawPolygon(VarioBar, 6);

  // draw clipping arrow
  if (vario_gross <= fixed(-5) || vario_gross >= fixed(5))
    canvas.DrawPolygon(clipping_arrow, 6);

  // draw avg vario bar
  if (!positive(vario_avg) && vario_bar_avg_enabled) {
      canvas.Select(look.pen_sink);
      canvas.Select(look.brush_sink_avg);
  } else {
    canvas.Select(look.pen_climb);
    canvas.Select(look.brush_climb_avg);
  }

  canvas.DrawPolygon(VarioBarAvg, 4);

  if (vario_avg <= fixed(-5.0) || vario_avg >= fixed(5.0))
      canvas.DrawPolygon(clipping_arrow_av, 4);

  //draw MC arrow
  canvas.Select(look.pen_mc);
  canvas.Select(look.brush_mc);

  canvas.DrawPolygon(mc_arrow, 6);

  //draw text
  canvas.SetTextColor(COLOR_BLACK);
  canvas.SetBackgroundColor(COLOR_WHITE);

  TextInBoxMode style;
  style.shape = LabelShape::ROUNDED_BLACK;
  style.move_in_view = true;

  if (text_size.cx < Layout::Scale(18)) {
    style.align = TextInBoxMode::Alignment::RIGHT;
    TextInBox(canvas, Value, rc.right, y0, style, rc);
  } else
    TextInBox(canvas, Value, rc.right-Layout::Scale(18), y0, style, rc);
}
コード例 #16
0
ファイル: TestMacCready.cpp プロジェクト: Adrien81/XCSoar
static void
Test(const fixed distance, const fixed altitude, const SpeedVector wind)
{
  const GeoVector vector(distance, Angle::Zero());
  const GlideState state(vector,
                         fixed(2000), fixed(2000) + altitude,
                         wind);
  const GlideResult result =
    MacCready::Solve(glide_settings, glide_polar, state);

  const fixed ld_ground = glide_polar.GetLDOverGround(vector.bearing, wind);

  const fixed mc = glide_polar.GetMC();
  const fixed v_climb_progress = mc * ld_ground - state.head_wind;

  const fixed initial_glide_distance = state.altitude_difference * ld_ground;
  if (initial_glide_distance >= distance ||
      (!positive(mc) && !positive(v_climb_progress))) {
    /* reachable by pure glide */
    ok1(result.validity == GlideResult::Validity::OK);

    const fixed best_speed =
      glide_polar.GetBestGlideRatioSpeed(state.head_wind);
    const fixed best_sink = glide_polar.SinkRate(best_speed);
    const fixed ld_ground2 = positive(mc)
      ? ld_ground
      : (best_speed - state.head_wind) / best_sink;

    const fixed height_glide = distance / ld_ground2;
    const fixed height_climb = fixed(0);
    const fixed altitude_difference = altitude - height_glide;

    ok1(equals(result.head_wind, wind.norm));
    ok1(equals(result.vector.distance, distance));
    ok1(equals(result.height_climb, height_climb));
    ok1(equals(result.height_glide, height_glide));
    ok1(equals(result.altitude_difference, altitude_difference));
    return;
  }

  if (!positive(v_climb_progress)) {
    /* excessive wind */
    ok1(result.validity == GlideResult::Validity::WIND_EXCESSIVE);
    return;
  }

  /*
  const fixed drifted_distance = (distance - initial_glide_distance)
    * state.head_wind / v_climb_progress;
    */
  const fixed drifted_height_climb = (distance - initial_glide_distance)
    * mc / v_climb_progress;
  const fixed drifted_height_glide =
    drifted_height_climb + state.altitude_difference;

  const fixed height_glide = drifted_height_glide;
  const fixed altitude_difference = altitude - height_glide;
  const fixed height_climb = drifted_height_climb;

  const fixed time_climb = height_climb / mc;
  const fixed time_glide = height_glide / glide_polar.GetSBestLD();
  const fixed time_elapsed = time_climb + time_glide;

  /* more tolerance with strong wind because this unit test doesn't
     optimise pure glide */
  const int accuracy = positive(altitude) && positive(wind.norm)
    ? (wind.norm > fixed(5) ? 5 : 10)
    : ACCURACY;

  ok1(result.validity == GlideResult::Validity::OK);
  ok1(equals(result.head_wind, wind.norm));
  ok1(equals(result.vector.distance, distance));
  ok1(equals(result.height_climb, height_climb, accuracy));
  ok1(equals(result.height_glide, height_glide, accuracy));
  ok1(equals(result.altitude_difference, altitude_difference, accuracy));
  ok1(equals(result.time_elapsed, time_elapsed, accuracy));
}
コード例 #17
0
ファイル: SpeedVector.hpp プロジェクト: Plantain/XCSoar
 /**
  * Returns true if the norm of the vector is non-zero.
  */
 bool is_non_zero() const {
   return positive(norm);
 }
コード例 #18
0
ファイル: Client.cpp プロジェクト: sorflex/CVAC_core
int ClientApp::verification(std::string testFilePath, cvac::DetectorPrx detector)
{
	appData->isVerification = true;
	Purpose positive(POSITIVE, 0);
	RunSet runSet;
	std::string suffix;
	if(appData->videoInputType)
	{
		suffix = "mpg";
	}
	else
	{
		suffix = "jpg";
	}
	
	if(appData->multiclassDetection)
	{
		std::string testFileName1 = (m_detectorName + "1." + suffix);
		std::string testFileName2 = (m_detectorName + "2." + suffix);
		std::string testFileName3 = (m_detectorName + "3." + suffix);

		Purpose pOne(MULTICLASS, 1), pTwo(MULTICLASS, 2), pThree(MULTICLASS, 3);
		addToRunSet(runSet, testFilePath, testFileName1, pOne);
		addToRunSet(runSet, testFilePath, testFileName2, pTwo);
		addToRunSet(runSet, testFilePath, testFileName3, pThree);
	}
	else
	{
    cvac::localAndClientMsg(VLogger::DEBUG, NULL, "IceBoxTestClient-verification setting RunSet dir: %s\n", testFilePath.c_str());
		std::string testFileName = (m_detectorName + "." + suffix);
		addToRunSet(runSet, testFilePath, testFileName, positive);  // Path relative to CVAC.data dir
	}
	
	try
	{    // Create our callback class so that we can be informed when process completes
		FinishedCallbackPtr finishCallback = new FinishedCallback();
		Ice::CallbackPtr finishedAsync = Ice::newCallback(finishCallback, &FinishedCallback::finished);
		Ice::AsyncResultPtr asyncResult = detector->begin_process(ident, runSet, finishedAsync);
		
		// end_myFunction should be call from the "finished" callback
		//detector->end_process(asyncResult);
		
		// Wait for the processing to complete before exiting the app
		while (!finishCallback->hasFinished())
		{
			cvac::sleep(100);
		}
		cvac::localAndClientMsg(VLogger::DEBUG_2, NULL, "IceBox test client: finished verification\n");
	}
	catch (const Ice::Exception& ex)
	{
		cvac::localAndClientMsg(VLogger::WARN, NULL, "Ice- name():  %s\n", ex.ice_name().c_str());
		cvac::localAndClientMsg(VLogger::WARN, NULL, "Ice- stackTrace(): \n%s\n", ex.ice_stackTrace().c_str());
		cvac::localAndClientMsg(VLogger::WARN, NULL, "%s\n", ex.what());
		return EXIT_FAILURE;
	}
	
	communicator()->shutdown();
	if(appData->needSBDVerified)
	{
		if(false == SBDResultsOK())
		{
			appData->detectionsVerified.push_back(false);  // Add SBD-test failure
		}
	}

  // Scan for missed detections
  bool missedDetections = false;
  while(appData->detectionsVerified.size() > 0) {

    bool element = appData->detectionsVerified.back();
    appData->detectionsVerified.pop_back();

    if(false == element) {
      missedDetections = true;
    }
  }

  if(missedDetections) {
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
コード例 #19
0
ファイル: Quadratic.hpp プロジェクト: galippi/xcsoar
 /**
  * Returns smallest real solution.  Valid only where check() has passed.
  *
  * @return smallest x value of solutions
  */
 gcc_pure fixed
 solution_min() const
 {
   return positive(da) ? solution(false) : solution(true);
 }
コード例 #20
0
void
WaypointInfoWidget::Prepare(ContainerWindow &parent, const PixelRect &rc)
{
  RowFormWidget::Prepare(parent, rc);

  const MoreData &basic = CommonInterface::Basic();
  const DerivedInfo &calculated = CommonInterface::Calculated();
  const ComputerSettings &settings = CommonInterface::GetComputerSettings();

  StaticString<64> buffer;

  if (!waypoint.comment.empty())
    AddMultiLine(waypoint.comment.c_str());

  if (waypoint.radio_frequency.IsDefined() &&
      waypoint.radio_frequency.Format(buffer.buffer(),
                                      buffer.capacity()) != nullptr) {
    buffer += _T(" MHz");
    AddReadOnly(_("Radio frequency"), nullptr, buffer);
  }

  if (waypoint.runway.IsDirectionDefined())
    buffer.UnsafeFormat(_T("%02u"), waypoint.runway.GetDirectionName());
  else
    buffer.clear();

  if (waypoint.runway.IsLengthDefined()) {
    if (!buffer.empty())
      buffer += _T("; ");

    TCHAR length_buffer[16];
    FormatSmallUserDistance(length_buffer,
                                   fixed(waypoint.runway.GetLength()));
    buffer += length_buffer;
  }

  if (!buffer.empty())
    AddReadOnly(_("Runway"), nullptr, buffer);

  if (FormatGeoPoint(waypoint.location,
                     buffer.buffer(), buffer.capacity()) != nullptr)
    AddReadOnly(_("Location"), nullptr, buffer);

  AddReadOnly(_("Elevation"), nullptr, FormatUserAltitude(waypoint.elevation));

  if (basic.time_available && basic.date_time_utc.IsDatePlausible()) {
    const SunEphemeris::Result sun =
      SunEphemeris::CalcSunTimes(waypoint.location, basic.date_time_utc,
                                 settings.utc_offset);

    const BrokenTime sunrise = BreakHourOfDay(sun.time_of_sunrise);
    const BrokenTime sunset = BreakHourOfDay(sun.time_of_sunset);

    buffer.UnsafeFormat(_T("%02u:%02u - %02u:%02u"),
                        sunrise.hour, sunrise.minute,
                        sunset.hour, sunset.minute);
    AddReadOnly(_("Daylight time"), nullptr, buffer);
  }

  if (basic.location_available) {
    const GeoVector vector = basic.location.DistanceBearing(waypoint.location);

    TCHAR distance_buffer[32];
    FormatUserDistanceSmart(vector.distance, distance_buffer,
                                   ARRAY_SIZE(distance_buffer));

    FormatBearing(buffer.buffer(), buffer.capacity(),
                  vector.bearing, distance_buffer);
    AddReadOnly(_("Bearing and Distance"), nullptr, buffer);
  }

  if (basic.location_available && basic.NavAltitudeAvailable() &&
      settings.polar.glide_polar_task.IsValid()) {
    const GlideState glide_state(basic.location.DistanceBearing(waypoint.location),
                                 waypoint.elevation + settings.task.safety_height_arrival,
                                 basic.nav_altitude,
                                 calculated.GetWindOrZero());

    GlidePolar gp0 = settings.polar.glide_polar_task;
    gp0.SetMC(fixed(0));
    AddGlideResult(_("Alt. diff. MC 0"),
                   MacCready::Solve(settings.task.glide,
                                    gp0, glide_state));

    AddGlideResult(_("Alt. diff. MC safety"),
                   MacCready::Solve(settings.task.glide,
                                    calculated.glide_polar_safety,
                                    glide_state));

    AddGlideResult(_("Alt. diff. MC current"),
                   MacCready::Solve(settings.task.glide,
                                    settings.polar.glide_polar_task,
                                    glide_state));
  }

  if (basic.location_available && basic.NavAltitudeAvailable()) {
    const TaskBehaviour &task_behaviour =
      CommonInterface::GetComputerSettings().task;

    const fixed safety_height = task_behaviour.safety_height_arrival;
    const fixed target_altitude = waypoint.elevation + safety_height;
    const fixed delta_h = basic.nav_altitude - target_altitude;
    if (positive(delta_h)) {
      const fixed distance = basic.location.Distance(waypoint.location);
      const fixed gr = distance / delta_h;
      if (GradientValid(gr)) {
        buffer.UnsafeFormat(_T("%.1f"), (double)gr);
        AddReadOnly(_("Required glide ratio"), nullptr, buffer);
      }
    }
  }
}
コード例 #21
0
ファイル: VegaVoice.cpp プロジェクト: CnZoom/XcSoarPull
bool
VegaVoiceMessage::Update(const NMEAInfo &basic,
                         const DerivedInfo &calculated,
                         const VoiceSettings &settings)
{
  const fixed Time = basic.clock;
  TCHAR text[80];

  switch(id) {
  case VV_GENERAL:
    // TODO feature: Allow this to be triggered to give generic alert
    // "INFO"
    break;
  case VV_CLIMBRATE:
    if (!settings.voice_climb_rate_enabled) return false;

    if (calculated.circling && positive(calculated.average)) {
      // Gives the average climb rate in user units every X seconds
      // while in circling mode
      // e.g. if average = 3.4 (user units)
      // Now: "CIRCLING THREE FOUR"
      // Later: "AVERAGE THREE POINT FOUR"
      _stprintf(text, _T(",%d"), VWI_CIRCLING);
      TextToDigitsSmall(text, Units::ToUserVSpeed(calculated.average));
      DoSend(Time, text);
      return true;
    }
    break;
  case VV_TERRAIN:
    if (!settings.voice_terrain_enabled) return false;
    // TODO feature: final glide with terrain warning
    // CAUTION TERRAIN
    break;
  case VV_WAYPOINTDISTANCE:
#ifdef OLD_TASK
    if (!calculated.circling && task.Valid()) {

      // Gives the distance to the active waypoint every X seconds,
      // optionally limited when at last 20 km to go?
      // calculated.LegDistanceToGo
      // e.g.: if distance is 13 (user units)
      // Now: "PLUS ONE THREE"
      // Later: "WAYPOINT DISTANCE THREE FOUR"
      //
      // height above/below final glide when
      // in final glide mode, e.g.
      // "WAYPOINT BELOW TWO HUNDRED"

      if (Units::ToUserUnit(calculated.WaypointDistance,
                            Units::DistanceUnit) < 20.0) {

	      if (!settings.EnableVoiceWaypointDistance) return false;

              _stprintf(text, _T(",%d"), VWI_PLUS);
	      TextToDigitsLarge(text, Units::ToUserUnit(calculated.WaypointDistance,
                                                  Units::DistanceUnit));
              DoSend(time, text);
	      return true;
      } else {

	      if (calculated.FinalGlide) {

	        if (!settings.EnableVoiceTaskAltitudeDifference) return false;

	        // TODO feature: BELOW FOUR HUNDRED
	        double tad = Units::ToUserUnit(calculated.TaskAltitudeDifference,
                                         Units::AltitudeUnit);
	        if (fabs(tad)>100) {
	          if (tad>0) {
                    _stprintf(text, _T(",%d"), VWI_ABOVE);
	          } else {
                    _stprintf(text, _T(",%d"), VWI_BELOW);
	          }
	          TextToDigitsHuge(text, fabs(tad));
                  DoSend(time, text);
	          return true;
	        }
	      }

      }
    }
#endif
    break;
  case VV_MACCREADY:
    if (!settings.voice_mac_cready_enabled) return false;
    // TODO feature: report when not in auto maccready mode, if
    // vario has changed in last 3 seconds but hasn't changed
    // for more than one second
    //
    // Now: ---
    // Later: "MACCREADY THREE DECIMAL FOUR"
    break;
  case VV_NEWWAYPOINT:
    if (!settings.voice_new_waypoint_enabled) return false;
#ifdef OLD_TASK
    static unsigned LastWaypoint = 1000;
    if (task.getActiveIndex() != LastWaypoint) {
      LastWaypoint = task.getActiveIndex();
      // Reports that a new waypoint is active
      // e.g.:
      // Now: "INFO"
      // Later: "NEW WAYPOINT"
      _stprintf(text, _T(",%d"), VWI_INFO);
      DoSend(time, text);
      return true;
    }
#endif
    break;
  case VV_INSECTOR:
    if (!settings.voice_in_sector_enabled) return false;
#ifdef OLD_TASK
    if (calculated.IsInSector) {
      // Reports when the aircraft is in an AAT/task sector
      // e.g.:
      // Now: INFO
      // Later: "INSIDE SECTOR"
      _stprintf(text, _T(",%d"), VWI_INFO);
      DoSend(time, text);
      return true;
    }
#endif
    break;
  case VV_AIRSPACE:
    if (!settings.voice_airspace_enabled) return false;
#ifdef OLD_TASK
    if (calculated.IsInAirspace) {
      // Reports when the aircraft is inside airspace
      // e.g.:
      // Now: "WARNING AIRSPACE"
      //
      // Later give distance/height/direction?
      // Later: "WARNING AIRSPACE ABOVE"
      _stprintf(text, _T(",%d,%d,0"), VWI_WARNING, VWI_AIRSPACE);
      DoSend(time, text);
      return true;
    }
#endif
    break;
  default:
    break;
  };
  return false;
}
コード例 #22
0
static bool
test_replay()
{
  Directory::Create(_T("output/results"));
  std::ofstream f("output/results/res-sample.txt");

  GlidePolar glide_polar(fixed(4.0));
  Waypoints waypoints;
  AircraftState state_last;

  TaskBehaviour task_behaviour;
  task_behaviour.SetDefaults();
  task_behaviour.auto_mc = true;

  TaskManager task_manager(task_behaviour, waypoints);

  TaskEventsPrint default_events(verbose);
  task_manager.SetTaskEvents(default_events);

  glide_polar.SetBallast(fixed(1.0));

  task_manager.SetGlidePolar(glide_polar);

  OrderedTask* blank = new OrderedTask(task_manager.GetTaskBehaviour());

  OrderedTask* t = task_load(blank);
  if (t) {
    task_manager.Commit(*t);
    task_manager.Resume();
  } else {
    return false;
  }

  // task_manager.get_task_advance().get_advance_state() = TaskAdvance::AUTO;

  FileLineReaderA *reader = new FileLineReaderA(replay_file.c_str());
  if (reader->error()) {
    delete reader;
    return false;
  }

  ReplayLoggerSim sim(reader);
  sim.state.netto_vario = fixed(0);

  bool do_print = verbose;
  unsigned print_counter=0;

  NMEAInfo basic;
  basic.Reset();

  while (sim.Update(basic) && !sim.started) {
  }
  state_last = sim.state;

  sim.state.wind.norm = fixed(7);
  sim.state.wind.bearing = Angle::Degrees(330);

  fixed time_last = sim.state.time;

//  uncomment this to manually go to first tp
//  task_manager.incrementActiveTaskPoint(1);

  FlyingComputer flying_computer;
  flying_computer.Reset();

  FlyingState flying_state;
  flying_state.Reset();

  while (sim.Update(basic)) {
    if (sim.state.time>time_last) {

      n_samples++;

      flying_computer.Compute(glide_polar.GetVTakeoff(),
                              sim.state, sim.state.time - time_last,
                              flying_state);
      sim.state.flying = flying_state.flying;

      task_manager.Update(sim.state, state_last);
      task_manager.UpdateIdle(sim.state);
      task_manager.UpdateAutoMC(sim.state, fixed(0));
      task_manager.SetTaskAdvance().SetArmed(true);

      state_last = sim.state;

      if (verbose>1) {
        sim.print(f);
        f.flush();
      }
      if (do_print) {
        PrintHelper::taskmanager_print(task_manager, sim.state);
      }
      do_print = (++print_counter % output_skip ==0) && verbose;
    }
    time_last = sim.state.time;
  };

  if (verbose) {
    PrintDistanceCounts();
    printf("# task elapsed %d (s)\n", (int)task_manager.GetStats().total.time_elapsed);
    printf("# task speed %3.1f (kph)\n", (int)task_manager.GetStats().total.travelled.GetSpeed()*3.6);
    printf("# travelled distance %4.1f (km)\n", 
           (double)task_manager.GetStats().total.travelled.GetDistance()/1000.0);
    printf("# scored distance %4.1f (km)\n", 
           (double)task_manager.GetStats().distance_scored/1000.0);
    if (positive(task_manager.GetStats().total.time_elapsed)) {
      printf("# scored speed %3.1f (kph)\n", 
             (double)task_manager.GetStats().distance_scored/(double)task_manager.GetStats().total.time_elapsed*3.6);
    }
  }
  return true;
}
コード例 #23
0
ファイル: TestGeoPoint.cpp プロジェクト: StefanL74/XCSoar
int main(int argc, char **argv)
{
  plan_tests(66);

  // test constructor
  GeoPoint p1(Angle::Degrees(345.32), Angle::Degrees(-6.332));
  ok1(p1.IsValid());
  ok1(equals(p1, -6.332, 345.32));

  // test normalize()
  p1.Normalize();
  ok1(p1.IsValid());
  ok1(equals(p1, -6.332, -14.68));

  // test parametric()
  GeoPoint p2(Angle::Degrees(2), Angle::Degrees(1));
  GeoPoint p3 = p1.Parametric(p2, fixed(5));
  ok1(p2.IsValid());
  ok1(p3.IsValid());
  ok1(equals(p3, -1.332, -4.68));

  // test interpolate
  GeoPoint p4 = p1.Interpolate(p3, fixed(0.5));
  ok1(p4.IsValid());
  ok1(equals(p4, -3.832, -9.68));

  GeoPoint p5 = p1.Interpolate(p3, fixed(0.25));
  ok1(p5.IsValid());
  ok1(equals(p5, -5.082, -12.18));

  // test *
  GeoPoint p6 = p2 * fixed(3.5);
  ok1(p6.IsValid());
  ok1(equals(p6, 3.5, 7));

  // test +
  p6 = p6 + p2;
  ok1(p6.IsValid());
  ok1(equals(p6, 4.5, 9));

  // test +=
  p6 += p2;
  ok1(p6.IsValid());
  ok1(equals(p6, 5.5, 11));

  // test -
  p6 = p6 - p2;
  ok1(p6.IsValid());
  ok1(equals(p6, 4.5, 9));

  // test sort()
  ok1(!p1.Sort(p3));
  ok1(p3.Sort(p1));
  ok1(!p1.Sort(p4));
  ok1(p4.Sort(p1));
  ok1(!p1.Sort(p5));
  ok1(p5.Sort(p1));
  ok1(!p4.Sort(p3));
  ok1(p3.Sort(p4));
  ok1(!p5.Sort(p3));
  ok1(p3.Sort(p5));
  ok1(!p5.Sort(p4));
  ok1(p4.Sort(p5));

  // test distance()
  //
  // note: distance between p1 and p4 and between p3 and p4 is not
  // the same due to linear interpolation instead of real geographic
  // intermediate point calculation
  ok1(equals(p2.Distance(p6), 869326.653160));
  ok1(equals(p6.Distance(p2), 869326.653160));
  ok1(equals(p1.Distance(p5), 309562.219016));
  ok1(equals(p1.Distance(p4), 619603.149273));
  ok1(equals(p1.Distance(p3), 1240649.267606));
  ok1(equals(p3.Distance(p4), 621053.760625));

  // test bearing()
  //
  // note: the bearings p1 -> p5, p5 -> p4 and so on are not the same due to
  // linear interpolation instead of real geographic intermediate point
  // calculation
  ok1(equals(p2.Bearing(p6), 63.272424));
  ok1(equals(p6.Bearing(p2), 243.608847));
  ok1(equals(p1.Bearing(p5), 63.449343));
  ok1(equals(p1.Bearing(p4), 63.582620));
  ok1(equals(p1.Bearing(p3), 63.784526));
  ok1(equals(p5.Bearing(p4), 63.466726));
  ok1(equals(p5.Bearing(p3), 63.646072));
  ok1(equals(p4.Bearing(p3), 63.540756));
  ok1(equals(p5.Bearing(p6), 65.982854));
  ok1(equals(p2.Bearing(p3), 250.786774));

  // test distance_bearing()
  // note: should be the same output as bearing() and distance()
  GeoVector v = p2.DistanceBearing(p6);
  ok1(equals(v.distance, 869326.653160));
  ok1(equals(v.bearing, 63.272424));

  // test intermediate_point()
  GeoPoint p7(Angle::Zero(), Angle::Zero());
  ok1(p7.IsValid());
  GeoPoint p8 = p7.IntermediatePoint(p2, fixed(100000));
  ok1(p8.IsValid());
  ok1(equals(p8, 0.402274, 0.804342));
  ok1(equals(p8.Distance(p7), 100000));
  GeoPoint p9 = p7.IntermediatePoint(p2, fixed(100000000));
  ok1(p9.IsValid());
  ok1(equals(p9, p2));

  // test projected_distance()
  ok1(equals(p8.ProjectedDistance(p7, p2), 100000));
  ok1(equals(p4.ProjectedDistance(p1, p3), 619599.304393));
  ok1(equals((p2 * fixed(2)).ProjectedDistance(p2, p6), 248567.832772));

  // Tests moved here from test_fixed.cpp
  GeoPoint l1(Angle::Zero(), Angle::Zero());
  ok1(l1.IsValid());
  GeoPoint l2(Angle::Degrees(-0.3), Angle::Degrees(1.0));
  ok1(l2.IsValid());
  GeoPoint l3(Angle::Degrees(0.00001), Angle::Zero());
  ok1(l3.IsValid());
  GeoPoint l4(Angle::Degrees(10), Angle::Zero());
  ok1(l4.IsValid());
  l4.SetInvalid();
  ok1(!l4.IsValid());

  bool find_lat_lon_okay = true;
  for (Angle bearing = Angle::Zero(); bearing < Angle::FullCircle();
      bearing += Angle::Degrees(5)) {
    GeoPoint p_test = FindLatitudeLongitude(p1, bearing, fixed(50000));
    find_lat_lon_okay = equals(p_test.Distance(p1), 50000) && find_lat_lon_okay;
  }
  ok1(find_lat_lon_okay);

  v = l1.DistanceBearing(l2);
  printf("Dist %g bearing %d\n",
         FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees()));
  // 116090 @ 343

  v = l1.DistanceBearing(l3);
  printf("Dist %g bearing %d\n",
         FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees()));
  ok(positive(v.distance) && v.distance < fixed(2), "earth distance short", 0);

  v = l1.DistanceBearing(l4);
  printf("Dist %g bearing %d\n",
         FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees()));

  GeoPoint p10(GeoPoint::Invalid());
  ok1(!p10.IsValid());


  return exit_status();
}
コード例 #24
0
void
ThermalBandRenderer::_DrawThermalBand(const MoreData &basic,
                                      const DerivedInfo& calculated,
                                      const ComputerSettings &settings_computer,
                                      ChartRenderer &chart,
                                      const TaskBehaviour& task_props,
                                      const bool is_infobox,
                                      const OrderedTaskSettings *ordered_props) const
{
  const ThermalBandInfo &thermal_band = calculated.thermal_band;

  // calculate height above safety height
  auto hoffset = task_props.route_planner.safety_height_terrain +
    calculated.GetTerrainBaseFallback();

  fixed h = fixed(0);
  if (basic.NavAltitudeAvailable()) {
    h = basic.nav_altitude - hoffset;
    chart.ScaleYFromValue(h);
  }

  bool draw_start_height = false;
  fixed hstart = fixed(0);

  draw_start_height = ordered_props
    && calculated.ordered_task_stats.task_valid
    && ordered_props->start_constraints.max_height != 0
    && calculated.terrain_valid;
  if (draw_start_height) {
    hstart = fixed(ordered_props->start_constraints.max_height);
    if (ordered_props->start_constraints.max_height_ref == AltitudeReference::AGL &&
        calculated.terrain_valid)
      hstart += calculated.terrain_altitude;

    hstart -= hoffset;
    chart.ScaleYFromValue(hstart);
  }

  // no thermalling has been done above safety height
  if (!positive(calculated.thermal_band.max_thermal_height))
    return;

  // calculate averages
  int numtherm = 0;

  fixed Wmax = fixed(0);
  fixed Wav = fixed(0);
  fixed Wt[ThermalBandInfo::N_BUCKETS];
  fixed ht[ThermalBandInfo::N_BUCKETS];

  for (unsigned i = 0; i < ThermalBandInfo::N_BUCKETS; ++i) {
    if (thermal_band.thermal_profile_n[i] < 6) 
      continue;

    if (positive(thermal_band.thermal_profile_w[i])) {
      // height of this thermal point [0,mth]
      // requires 5 items in bucket before displaying, to eliminate kinks
      auto wthis = thermal_band.thermal_profile_w[i] / thermal_band.thermal_profile_n[i];
      ht[numtherm] = i * calculated.thermal_band.max_thermal_height 
        / ThermalBandInfo::N_BUCKETS;
      Wt[numtherm] = wthis;
      Wmax = std::max(Wmax, wthis);
      Wav+= wthis;
      numtherm++;
    }
  }
  chart.ScaleXFromValue(Wmax);
  if (!numtherm)
    return;
  chart.ScaleXFromValue(fixed(1.5)*Wav/numtherm);

  if ((!draw_start_height) && (numtherm<=1))
    // don't display if insufficient statistics
    // but do draw if start height needs to be drawn
    return;

  const Pen *fpen = is_infobox ? nullptr : &look.pen;

  // position of thermal band
  if (numtherm > 1) {
    std::vector< std::pair<fixed, fixed> > thermal_profile;
    thermal_profile.reserve(numtherm);
    for (int i = 0; i < numtherm; ++i)
      thermal_profile.emplace_back(Wt[i], ht[i]);

    if (!is_infobox) {
#ifdef ENABLE_OPENGL
      const ScopeAlphaBlend alpha_blend;
#endif
      chart.DrawFilledY(thermal_profile, look.brush, fpen);
    } else
      chart.DrawFilledY(thermal_profile, look.brush, fpen);
  }

  // position of thermal band
  if (basic.NavAltitudeAvailable()) {
    const Pen &pen = is_infobox && look.inverse
      ? look.white_pen : look.black_pen;
    chart.DrawLine(fixed(0), h,
                   settings_computer.polar.glide_polar_task.GetMC(), h, pen);

    if (is_infobox && look.inverse)
      chart.GetCanvas().SelectWhiteBrush();
    else
      chart.GetCanvas().SelectBlackBrush();
    chart.DrawDot(settings_computer.polar.glide_polar_task.GetMC(),
                  h, Layout::Scale(2));
  }
}
コード例 #25
0
ファイル: ContestResult.hpp プロジェクト: alon/xcsoar
 bool IsDefined() const {
   return positive(score);
 }
コード例 #26
0
 /**
  * Test whether airspace boundary is the terrain
  *
  * @return True if this altitude limit is the terrain
  */
 bool IsTerrain() const {
   return !positive(altitude_above_terrain) && type == AGL;
 }
コード例 #27
0
ファイル: FlarmComputer.cpp プロジェクト: DRIZO/xcsoar
void
FlarmComputer::Process(FlarmData &flarm, const FlarmData &last_flarm,
                       const NMEAInfo &basic)
{
  // Cleanup old calculation instances
  if (basic.time_available)
    flarm_calculations.CleanUp(basic.time);

  // if (FLARM data is available)
  if (!flarm.IsDetected())
    return;

  fixed north_to_latitude(0);
  fixed east_to_longitude(0);

  if (basic.location_available) {
    // Precalculate relative east and north projection to lat/lon
    // for Location calculations of each target
    constexpr Angle delta_lat = Angle::Degrees(0.01);
    constexpr Angle delta_lon = Angle::Degrees(0.01);

    GeoPoint plat = basic.location;
    plat.latitude += delta_lat;
    GeoPoint plon = basic.location;
    plon.longitude += delta_lon;

    fixed dlat = basic.location.Distance(plat);
    fixed dlon = basic.location.Distance(plon);

    if (positive(fabs(dlat)) && positive(fabs(dlon))) {
      north_to_latitude = delta_lat.Degrees() / dlat;
      east_to_longitude = delta_lon.Degrees() / dlon;
    }
  }

  // for each item in traffic
  for (auto &traffic : flarm.traffic.list) {
    // if we don't know the target's name yet
    if (!traffic.HasName()) {
      // lookup the name of this target's id
      const TCHAR *fname = FlarmDetails::LookupCallsign(traffic.id);
      if (fname != NULL)
        traffic.name = fname;
    }

    // Calculate distance
    traffic.distance = SmallHypot(traffic.relative_north,
                                  traffic.relative_east);

    // Calculate Location
    traffic.location_available = basic.location_available;
    if (traffic.location_available) {
      traffic.location.latitude =
          Angle::Degrees(traffic.relative_north * north_to_latitude) +
          basic.location.latitude;

      traffic.location.longitude =
          Angle::Degrees(traffic.relative_east * east_to_longitude) +
          basic.location.longitude;
    }

    // Calculate absolute altitude
    traffic.altitude_available = basic.gps_altitude_available;
    if (traffic.altitude_available)
      traffic.altitude = traffic.relative_altitude + RoughAltitude(basic.gps_altitude);

    // Calculate average climb rate
    traffic.climb_rate_avg30s_available = traffic.altitude_available;
    if (traffic.climb_rate_avg30s_available)
      traffic.climb_rate_avg30s =
        flarm_calculations.Average30s(traffic.id, basic.time, traffic.altitude);

    // The following calculations are only relevant for targets
    // where information is missing
    if (traffic.track_received && traffic.turn_rate_received &&
        traffic.speed_received && traffic.climb_rate_received)
      continue;

    // Check if the target has been seen before in the last seconds
    const FlarmTraffic *last_traffic =
      last_flarm.traffic.FindTraffic(traffic.id);
    if (last_traffic == NULL || !last_traffic->valid)
      continue;

    // Calculate the time difference between now and the last contact
    fixed dt = traffic.valid.GetTimeDifference(last_traffic->valid);
    if (positive(dt)) {
      // Calculate the immediate climb rate
      if (!traffic.climb_rate_received)
        traffic.climb_rate =
          (traffic.relative_altitude - last_traffic->relative_altitude) / dt;
    } else {
      // Since the time difference is zero (or negative)
      // we can just copy the old values
      if (!traffic.climb_rate_received)
        traffic.climb_rate = last_traffic->climb_rate;
    }

    if (positive(dt) &&
        traffic.location_available &&
        last_traffic->location_available) {
      // Calculate the GeoVector between now and the last contact
      GeoVector vec = last_traffic->location.DistanceBearing(traffic.location);

      if (!traffic.track_received)
        traffic.track = vec.bearing;

      // Calculate the turn rate
      if (!traffic.turn_rate_received) {
        Angle turn_rate = traffic.track - last_traffic->track;
        traffic.turn_rate =
          turn_rate.AsDelta().Degrees() / dt;
      }

      // Calculate the speed [m/s]
      if (!traffic.speed_received)
        traffic.speed = vec.distance / dt;
    } else {
      // Since the time difference is zero (or negative)
      // we can just copy the old values
      if (!traffic.track_received)
        traffic.track = last_traffic->track;

      if (!traffic.turn_rate_received)
        traffic.turn_rate = last_traffic->turn_rate;

      if (!traffic.speed_received)
        traffic.speed = last_traffic->speed;
    }
  }
}