void AppendArc(Angle start, Angle end) { // 5 or -5, depending on direction const auto _step = ArcStepWidth(radius); const Angle step = Angle::Degrees(rotation * _step); const fixed threshold = _step * fixed(1.5); if (rotation > 0) { while (end < start) end += Angle::FullCircle(); } else if (rotation < 0) { while (end > start) end -= Angle::FullCircle(); } // Add first polygon point points.push_back(FindLatitudeLongitude(center, start, radius)); // Add intermediate polygon points while ((end - start).AbsoluteDegrees() > threshold) { start += step; points.push_back(FindLatitudeLongitude(center, start, radius)); } // Add last polygon point points.push_back(FindLatitudeLongitude(center, end, radius)); }
static void CalculateSector(const TCHAR *Text, TempAirspaceType &temp_area) { fixed Radius; TCHAR *Stop; GeoPoint TempPoint; static const fixed fixed_75 = fixed(7.5); const Angle BearingStep = Angle::degrees(temp_area.Rotation * fixed(5)); Radius = Units::ToSysUnit(fixed(_tcstod(&Text[2], &Stop)), unNauticalMiles); Angle StartBearing = Angle::degrees(fixed(_tcstod(&Stop[1], &Stop))); Angle EndBearing = Angle::degrees(fixed(_tcstod(&Stop[1], &Stop))); if (EndBearing < StartBearing) EndBearing += Angle::degrees(fixed_360); while ((EndBearing - StartBearing).magnitude_degrees() > fixed_75) { StartBearing = StartBearing.as_bearing(); FindLatitudeLongitude(temp_area.Center, StartBearing, Radius, &TempPoint); temp_area.points.push_back(TempPoint); StartBearing += BearingStep; } FindLatitudeLongitude(temp_area.Center, EndBearing, Radius, &TempPoint); temp_area.points.push_back(TempPoint); }
void MapWindow::DrawProjectedTrack(Canvas &canvas) { if (task == NULL || !task->Valid() || !task->getSettings().AATEnabled || task->getActiveIndex() ==0) return; if (Calculated().Circling || task->TaskIsTemporary()) { // don't display in various modes return; } // TODO feature: maybe have this work even if no task? // TODO feature: draw this also when in target pan mode GEOPOINT start = Basic().Location; GEOPOINT previous_loc = task->getTargetLocation(task->getActiveIndex() - 1); double distance_from_previous, bearing; DistanceBearing(previous_loc, start, &distance_from_previous, &bearing); if (distance_from_previous < 100.0) { bearing = Basic().TrackBearing; // too short to have valid data } POINT pt[2] = {{0,-75},{0,-400}}; if (SettingsMap().TargetPan) { double screen_range = GetScreenDistanceMeters(); double f_low = 0.4; double f_high = 1.5; screen_range = max(screen_range, Calculated().WaypointDistance); GEOPOINT p1, p2; FindLatitudeLongitude(start, bearing, f_low*screen_range, &p1); FindLatitudeLongitude(start, bearing, f_high*screen_range, &p2); LonLat2Screen(p1, pt[0]); LonLat2Screen(p2, pt[1]); } else if (fabs(bearing-Calculated().WaypointBearing)<10) { // too small an error to bother return; } else { pt[1].y = (long)(-max(MapRectBig.right-MapRectBig.left, MapRectBig.bottom-MapRectBig.top)*1.2); PolygonRotateShift(pt, 2, Orig_Aircraft.x, Orig_Aircraft.y, bearing-DisplayAngle); } Pen dash_pen(Pen::DASH, IBLSCALE(2), Color(0, 0, 0)); canvas.select(dash_pen); canvas.line(pt[0], pt[1]); }
void AATDistance::ShiftTargetOutside(double longitude, double latitude, int taskwaypoint) { // if no improvement possible, vector to outside double bearing; if (taskwaypoint>0) { DistanceBearing(latitude, longitude, WayPointList[Task[taskwaypoint+1].Index].Latitude, WayPointList[Task[taskwaypoint+1].Index].Longitude, NULL, &bearing); FindLatitudeLongitude(latitude, longitude, bearing, 100.0, &Task[taskwaypoint].AATTargetLat, &Task[taskwaypoint].AATTargetLon); UpdateTargetAltitude(Task[taskwaypoint]); TargetModified = true; } //JMWAAT Task[taskwaypoint].AATTargetOffsetRadial = bearing; // Move previous target to location that yields longest distance, // plus a little so optimal path vector points to next waypoint. }
void MapWindow::CalculateScreenPositionsThermalSources() { for (int i=0; i<MAX_THERMAL_SOURCES; i++) { if (DerivedDrawInfo.ThermalSources[i].LiftRate>0) { double dh = DerivedDrawInfo.NavAltitude -DerivedDrawInfo.ThermalSources[i].GroundHeight; if (dh<0) { DerivedDrawInfo.ThermalSources[i].Visible = false; continue; } double t = dh/DerivedDrawInfo.ThermalSources[i].LiftRate; double lat, lon; FindLatitudeLongitude(DerivedDrawInfo.ThermalSources[i].Latitude, DerivedDrawInfo.ThermalSources[i].Longitude, DerivedDrawInfo.WindBearing, -DerivedDrawInfo.WindSpeed*t, &lat, &lon); if (PointVisible(lon,lat)) { LatLon2Screen(lon, lat, DerivedDrawInfo.ThermalSources[i].Screen); DerivedDrawInfo.ThermalSources[i].Visible = PointVisible(DerivedDrawInfo.ThermalSources[i].Screen); } else { DerivedDrawInfo.ThermalSources[i].Visible = false; } } else { DerivedDrawInfo.ThermalSources[i].Visible = false; } } }
void EstimateThermalBase(const GeoPoint location, const fixed altitude, const fixed average, const SpeedVector wind, GeoPoint &ground_location, fixed &ground_alt) { if (!positive(average)) return; // Time spent in last thermal fixed Tmax = altitude / average; // Shortcut if no terrain available if (terrain == NULL) { ground_location = FindLatitudeLongitude(location, wind.bearing, wind.norm * Tmax); ground_alt = fixed_zero; return; } // Time of the 10 calculation intervals fixed dt = Tmax / 10; RasterTerrain::Lease map(*terrain); GeoPoint loc; // Iterate over 10 time-based calculation intervals for (fixed t = fixed_zero; t <= Tmax; t += dt) { // Calculate position loc = FindLatitudeLongitude(location, wind.bearing, wind.norm * t); // Calculate altitude fixed hthermal = altitude - average * t; // Calculate altitude above ground fixed dh = hthermal - GetElevation(map, loc); // Below ground level if (negative(dh)) { // Calculate time when we passed the ground level t = t + dh / average; // Calculate position loc = FindLatitudeLongitude(location, wind.bearing, wind.norm * t); break; } } ground_location = loc; ground_alt = GetElevation(map, ground_location); }
GeoPoint ThermalSource::CalculateAdjustedLocation(fixed altitude, const SpeedVector &wind) const { fixed dh = altitude - ground_height; fixed t = dh / lift_rate; return FindLatitudeLongitude(location, wind.bearing.Reciprocal(), wind.norm * t); }
GeoPoint TeamCode::GetLocation(const GeoPoint ref) const { Angle bearing = GetBearing(); fixed distance = GetRange(); return FindLatitudeLongitude(ref, bearing, distance); }
std::ostream& operator<< (std::ostream& f, const AirspaceCircle& as) { f << "# circle\n"; for (double t=0; t<=360; t+= 30) { GeoPoint l = FindLatitudeLongitude(as.m_center, Angle::Degrees(fixed(t)), as.m_radius); f << l.longitude << " " << l.latitude << " " << as.GetBase().altitude << "\n"; } f << "\n"; for (double t=0; t<=360; t+= 30) { GeoPoint l = FindLatitudeLongitude(as.m_center, Angle::Degrees(fixed(t)), as.m_radius); f << l.longitude << " " << l.latitude << " " << as.GetTop().altitude << "\n"; } f << "\n"; f << "\n"; return f; }
void MapWindow::DrawTaskOffTrackIndicator(Canvas &canvas) { if (Calculated().circling || !Basic().location_available || !Basic().track_available || !GetMapSettings().detour_cost_markers_enabled) return; const TaskStats &task_stats = Calculated().task_stats; const ElementStat ¤t_leg = task_stats.current_leg; if (!task_stats.task_valid || !current_leg.location_remaining.IsValid()) return; const GeoPoint target = current_leg.location_remaining; GeoVector vec(Basic().location, target); if ((Basic().track - vec.bearing).AsDelta().AbsoluteDegrees() < fixed(10)) // insignificant error return; fixed distance_max = std::min(vec.distance, render_projection.GetScreenDistanceMeters() * fixed(0.7)); // too short to bother if (distance_max < fixed(5000)) return; GeoPoint start = Basic().location; canvas.Select(*look.overlay_font); canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundTransparent(); GeoPoint dloc; int ilast = 0; for (fixed d = fixed(1) / 4; d <= fixed(1); d += fixed(1) / 4) { dloc = FindLatitudeLongitude(start, Basic().track, distance_max * d); fixed distance0 = start.Distance(dloc); fixed distance1 = target.Distance(dloc); fixed distance = fixed(distance0 + distance1) / vec.distance; int idist = iround((distance - fixed(1)) * 100); if ((idist != ilast) && (idist > 0) && (idist < 1000)) { TCHAR Buffer[5]; _stprintf(Buffer, _T("%d"), idist); RasterPoint sc = render_projection.GeoToScreen(dloc); PixelSize tsize = canvas.CalcTextSize(Buffer); canvas.DrawText(sc.x - tsize.cx / 2, sc.y - tsize.cy / 2, Buffer); ilast = idist; } } }
void SimFastForward() { if(HasKeyboard()) { double gs=GPS_INFO.Speed*10.0; if (gs<100) gs=100; FindLatitudeLongitude(GPS_INFO.Latitude, GPS_INFO.Longitude, GPS_INFO.TrackBearing, gs, &GPS_INFO.Latitude, &GPS_INFO.Longitude); } }
static void CalculateSector(AirspaceDatabase &airspace_database, TCHAR *Text, unsigned &NumberOfAirspacePoints) { double Radius; double StartBearing; double EndBearing; TCHAR *Stop; Radius = NAUTICALMILESTOMETRES * (double)_tcstod(&Text[2], &Stop); StartBearing = (double)_tcstod(&Stop[1], &Stop); EndBearing = (double)_tcstod(&Stop[1], &Stop); GEOPOINT c; c.Longitude = CenterX; c.Latitude = CenterY; while(fabs(EndBearing-StartBearing) > 7.5) { if(StartBearing >= 360) StartBearing -= 360; if(StartBearing < 0) StartBearing += 360; // if (bFillMode) // Trig calcs not needed on first pass { FindLatitudeLongitude(c, StartBearing, Radius, &TempPoint); } AddPoint(airspace_database, &TempPoint, &TempArea.NumPoints, NumberOfAirspacePoints); StartBearing += Rotation *5 ; } // if (bFillMode) // Trig calcs not needed on first pass { FindLatitudeLongitude(c, EndBearing, Radius, &TempPoint); } AddPoint(airspace_database, &TempPoint, &TempArea.NumPoints, NumberOfAirspacePoints); }
static void AppendArc(std::vector<GeoPoint> &points, GeoPoint center, fixed radius, fixed _step) { Angle start = Angle::Zero(); Angle end = Angle::HalfCircle(); // 5 or -5, depending on direction const Angle step = Angle::Degrees(_step); // Add first polygon point points.push_back(FindLatitudeLongitude(center, start, radius)); // Add intermediate polygon points while ((end - start).AbsoluteDegrees() > _step * 3 / 2) { start = (start + step).AsBearing(); points.push_back(FindLatitudeLongitude(center, start, radius)); } // Add last polygon point points.push_back(FindLatitudeLongitude(center, end, radius)); }
static void CalculateArc(AirspaceDatabase &airspace_database, TCHAR *Text, unsigned &NumberOfAirspacePoints) { GEOPOINT Start; GEOPOINT End; double StartBearing; double EndBearing; double Radius; TCHAR *Comma = NULL; ReadCoords(&Text[3],&Start.Longitude , &Start.Latitude); Comma = _tcschr(Text,','); if(!Comma) return; ReadCoords(&Comma[1],&End.Longitude , &End.Latitude); GEOPOINT c; c.Longitude = CenterX; c.Latitude = CenterY; DistanceBearing(c, Start, &Radius, &StartBearing); EndBearing = Bearing(c, End); TempPoint.Latitude = Start.Latitude; TempPoint.Longitude = Start.Longitude; AddPoint(airspace_database, &TempPoint, &TempArea.NumPoints, NumberOfAirspacePoints); while(fabs(EndBearing-StartBearing) > 7.5) { StartBearing += Rotation *5 ; if(StartBearing > 360) StartBearing -= 360; if(StartBearing < 0) StartBearing += 360; if (bFillMode) { // Trig calcs not needed on first pass GEOPOINT c; c.Longitude = CenterX; c.Latitude = CenterY; FindLatitudeLongitude(c, StartBearing, Radius, &TempPoint); } AddPoint(airspace_database, &TempPoint, &TempArea.NumPoints, NumberOfAirspacePoints); } TempPoint = End; AddPoint(airspace_database, &TempPoint, &TempArea.NumPoints, NumberOfAirspacePoints); }
void Simulator::Process(NMEAInfo &basic) { assert(is_simulator()); Touch(basic); basic.location = FindLatitudeLongitude(basic.location, basic.track, basic.ground_speed); // use this to test FLARM parsing/display if (IsDebug() && !IsAltair()) GenerateFLARMTraffic(basic); }
static void CalculateSector(const TCHAR *Text, TempAirspaceType &temp_area) { // 5 or -5, depending on direction const Angle BearingStep = Angle::degrees(temp_area.Rotation * fixed(5)); // Determine radius and start/end bearing TCHAR *Stop; fixed Radius = Units::ToSysUnit(fixed(_tcstod(&Text[2], &Stop)), unNauticalMiles); Angle StartBearing = Angle::degrees(fixed(_tcstod(&Stop[1], &Stop))).as_bearing(); Angle EndBearing = Angle::degrees(fixed(_tcstod(&Stop[1], &Stop))).as_bearing(); // Add intermediate polygon points GeoPoint TempPoint; while ((EndBearing - StartBearing).magnitude_degrees() > fixed_7_5) { TempPoint = FindLatitudeLongitude(temp_area.Center, StartBearing, Radius); temp_area.points.push_back(TempPoint); StartBearing = (StartBearing + BearingStep).as_bearing(); } // Add last polygon point TempPoint = FindLatitudeLongitude(temp_area.Center, EndBearing, Radius); temp_area.points.push_back(TempPoint); }
static void ScanAirspaceCircleBounds(AirspaceDatabase &airspace_database, int i, double bearing) { AIRSPACE_CIRCLE &circle = airspace_database.AirspaceCircle[i]; GEOPOINT loc; FindLatitudeLongitude(circle.Location, bearing, circle.Radius, &loc); circle.bounds.minx = min(loc.Longitude, circle.bounds.minx); circle.bounds.maxx = max(loc.Longitude, circle.bounds.maxx); circle.bounds.miny = min(loc.Latitude, circle.bounds.miny); circle.bounds.maxy = max(loc.Latitude, circle.bounds.maxy); }
static bool ParseArcTNP(const TCHAR *Text, TempAirspaceType &temp_area) { if (temp_area.points.empty()) return false; // (ANTI-)CLOCKWISE RADIUS=34.95 CENTRE=N523333 E0131603 TO=N522052 E0122236 GeoPoint from = temp_area.points.back(); const TCHAR* parameter; if ((parameter = _tcsstr(Text, _T(" "))) == NULL) return false; if ((parameter = string_after_prefix_ci(parameter, _T(" CENTRE="))) == NULL) return false; ParseCoordsTNP(parameter, temp_area.Center); GeoPoint to; if ((parameter = _tcsstr(parameter, _T(" "))) == NULL) return false; parameter++; if ((parameter = _tcsstr(parameter, _T(" "))) == NULL) return false; if ((parameter = string_after_prefix_ci(parameter, _T(" TO="))) == NULL) return false; ParseCoordsTNP(parameter, to); Angle bearing_from; Angle bearing_to; fixed radius; static const fixed fixed_75 = fixed(7.5); const Angle BearingStep = Angle::degrees(temp_area.Rotation * fixed(5)); DistanceBearing(temp_area.Center, from, &radius, &bearing_from); bearing_to = Bearing(temp_area.Center, to); GeoPoint TempPoint; while ((bearing_to - bearing_from).magnitude_degrees() > fixed_75) { bearing_from += BearingStep; bearing_from = bearing_from.as_bearing(); FindLatitudeLongitude(temp_area.Center, bearing_from, radius, &TempPoint); temp_area.points.push_back(TempPoint); } return true; }
static void CalculateArc(const TCHAR *Text, TempAirspaceType &temp_area) { // 5 or -5, depending on direction const Angle BearingStep = Angle::degrees(temp_area.Rotation * fixed(5)); // Read start coordinates GeoPoint Start; if (!ReadCoords(&Text[3], Start)) return; // Skip comma character const TCHAR* Comma = _tcschr(Text, ','); if (!Comma) return; // Read end coordinates GeoPoint End; if (!ReadCoords(&Comma[1], End)) return; // Determine start bearing and radius Angle StartBearing; fixed Radius; temp_area.Center.distance_bearing(Start, Radius, StartBearing); // Determine end bearing Angle EndBearing = Bearing(temp_area.Center, End); // Add first polygon point GeoPoint TempPoint = Start; temp_area.points.push_back(TempPoint); // Add intermediate polygon points while ((EndBearing - StartBearing).magnitude_degrees() > fixed_7_5) { StartBearing = (StartBearing + BearingStep).as_bearing(); TempPoint = FindLatitudeLongitude(temp_area.Center, StartBearing, Radius); temp_area.points.push_back(TempPoint); } // Add last polygon point TempPoint = End; temp_area.points.push_back(TempPoint); }
void ThermalLocator::Update(const fixed t_0, const GeoPoint &location_0, const SpeedVector wind, ThermalLocatorInfo &therm) { if (n_points < TLOCATOR_NMIN) { therm.estimate_valid = false; return; // nothing to do. } GeoPoint dloc = FindLatitudeLongitude(location_0, wind.bearing, wind.norm); TaskProjection projection; projection.reset(location_0); projection.update_fast(); // drift points Drift(t_0, projection, location_0 - dloc); FlatPoint av = glider_average(); // find thermal center relative to glider's average position FlatPoint f0(fixed_zero, fixed_zero); fixed acc = fixed_zero; for (unsigned i = 0; i < n_points; ++i) { f0 += (points[i].loc_drift-av)*points[i].lift_weight; acc += points[i].lift_weight; } // if sufficient data, estimate location if (!positive(acc)) { therm.estimate_valid = false; return; } f0 = f0 * (fixed_one/acc) + av; therm.estimate_location = projection.funproject(f0); therm.estimate_valid = true; }
void TrackLineRenderer::DrawProjected(Canvas &canvas, const WindowProjection &projection, const NMEAInfo &basic, const DerivedInfo &calculated, const MapSettings &settings, bool wind_relative) { // projection.GetMapScale() <= 6000; GeoPoint traildrift; if (calculated.wind_available && !wind_relative) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } else { traildrift = GeoPoint(Angle::Zero(), Angle::Zero()); } auto dt = ARC_SWEEP/ARC_STEPS/ std::max(MIN_RATE,calculated.turn_rate_heading_smoothed.Absolute()); Angle heading = basic.attitude.heading; GeoPoint loc = basic.location; RasterPoint pts[ARC_STEPS+1]; pts[0] = projection.GeoToScreen(loc); int i = 1; while (i <= ARC_STEPS) { GeoVector v(basic.true_airspeed*dt, heading); loc = v.EndPoint(loc.Parametric(traildrift, dt)); pts[i] = projection.GeoToScreen(loc); heading += calculated.turn_rate_heading_smoothed*dt; i++; } canvas.Select(look.track_line_pen); canvas.DrawPolyline(pts, i); }
void AATDistance::ShiftTargetFromInFront(double longitude, double latitude, int taskwaypoint) { double course_bearing; // this point is in sector and is improved // JMW, now moves target to in line with previous target whenever // you are in AAT sector and improving on the target distance //JMWAAT Task[taskwaypoint].AATTargetOffsetRadial = -1.0; if (Task[taskwaypoint].AATTargetLocked) { // have improved on the locked value, so unlock it in case user // wants to move it. Task[taskwaypoint].AATTargetOffsetRadius = -1.0; Task[taskwaypoint].AATTargetOffsetRadial = 0; Task[taskwaypoint].AATTargetLocked = false; } DistanceBearing(Task[taskwaypoint-1].AATTargetLat, Task[taskwaypoint-1].AATTargetLon, latitude, longitude, NULL, &course_bearing); course_bearing = AngleLimit360(course_bearing+ Task[taskwaypoint].AATTargetOffsetRadial); FindLatitudeLongitude(latitude, longitude, course_bearing, AATCloseDistance(), &Task[taskwaypoint].AATTargetLat, &Task[taskwaypoint].AATTargetLon); // JMW, distance here was 100m, now changed to speed * 2 UpdateTargetAltitude(Task[taskwaypoint]); TargetModified = true; CalculateAATIsoLines(); }
double FindInsideAATSectorDistance(double latitude, double longitude, int taskwaypoint, double course_bearing, double p_found) { double max_distance; if(Task[taskwaypoint].AATType == SECTOR) { max_distance = Task[taskwaypoint].AATSectorRadius; } else { max_distance = Task[taskwaypoint].AATCircleRadius; } // Do binary bounds search for longest distance within sector double delta = max_distance; double t_distance_lower = p_found; double t_distance = p_found+delta*2; int steps = 0; do { double t_lat, t_lon; FindLatitudeLongitude(latitude, longitude, course_bearing, t_distance, &t_lat, &t_lon); if (InAATTurnSector(t_lon, t_lat, taskwaypoint, 0)) { t_distance_lower = t_distance; // ok, can go further t_distance += delta; } else { t_distance -= delta; } delta /= 2.0; } while ((delta>5.0)&&(steps++<20)); return t_distance_lower; }
void AppendArc(const GeoPoint start, const GeoPoint end) { // Determine start bearing and radius const GeoVector v = center.DistanceBearing(start); Angle start_bearing = v.bearing; const fixed radius = v.distance; // 5 or -5, depending on direction const auto _step = ArcStepWidth(radius); const Angle step = Angle::Degrees(rotation * _step); const fixed threshold = _step * fixed(1.5); // Determine end bearing Angle end_bearing = center.Bearing(end); if (rotation > 0) { while (end_bearing < start_bearing) end_bearing += Angle::FullCircle(); } else if (rotation < 0) { while (end_bearing > start_bearing) end_bearing -= Angle::FullCircle(); } // Add first polygon point points.push_back(start); // Add intermediate polygon points while ((end_bearing - start_bearing).AbsoluteDegrees() > threshold) { start_bearing += step; points.push_back(FindLatitudeLongitude(center, start_bearing, radius)); } // Add last polygon point points.push_back(end); }
double FindInsideAATSectorDistance_old(double latitude, double longitude, int taskwaypoint, double course_bearing, double p_found) { bool t_in_sector; double delta; double max_distance; if(Task[taskwaypoint].AATType == SECTOR) { max_distance = Task[taskwaypoint].AATSectorRadius*2; } else { max_distance = Task[taskwaypoint].AATCircleRadius*2; } delta = max(250.0, max_distance/40.0); double t_distance = p_found; double t_distance_inside; do { double t_lat, t_lon; t_distance_inside = t_distance; t_distance += delta; FindLatitudeLongitude(latitude, longitude, course_bearing, t_distance, &t_lat, &t_lon); t_in_sector = InAATTurnSector(t_lon, t_lat, taskwaypoint, 0); } while (t_in_sector); return t_distance_inside; }
void Simulator::Process(NMEAInfo &basic) { if (!is_simulator()) return; basic.UpdateClock(); basic.connected.Update(basic.clock); basic.gps.satellites_used = -1; basic.gps.simulator = true; basic.gps.real = false; #ifdef ANDROID basic.gps.android_internal_gps = false; #endif basic.location = FindLatitudeLongitude(basic.location, basic.track, basic.ground_speed); basic.location_available.Update(basic.clock); basic.gps_altitude_available.Update(basic.clock); basic.track_available.Update(basic.clock); basic.ground_speed_available.Update(basic.clock); basic.time_available.Update(basic.clock); basic.time += fixed_one; (BrokenTime &)basic.date_time_utc = BrokenTime::FromSecondOfDayChecked((unsigned)basic.time); // use this to test FLARM parsing/display if (is_debug() && !is_altair()) GenerateFLARMTraffic(basic); // clear Airspeed as it is not available in simulation mode basic.airspeed_available.Clear(); basic.airspeed_real = false; }
static void CalculateArc(const TCHAR *Text, TempAirspaceType &temp_area) { GeoPoint Start; GeoPoint End; Angle StartBearing; fixed Radius; const TCHAR *Comma = NULL; GeoPoint TempPoint; static const fixed fixed_75 = fixed(7.5); const Angle BearingStep = Angle::degrees(temp_area.Rotation * fixed(5)); ReadCoords(&Text[3], Start); Comma = _tcschr(Text, ','); if (!Comma) return; ReadCoords(&Comma[1], End); DistanceBearing(temp_area.Center, Start, &Radius, &StartBearing); Angle EndBearing = Bearing(temp_area.Center, End); TempPoint.Latitude = Start.Latitude; TempPoint.Longitude = Start.Longitude; temp_area.points.push_back(TempPoint); while ((EndBearing - StartBearing).magnitude_degrees() > fixed_75) { StartBearing += BearingStep; StartBearing = StartBearing.as_bearing(); FindLatitudeLongitude(temp_area.Center, StartBearing, Radius, &TempPoint); temp_area.points.push_back(TempPoint); } TempPoint = End; temp_area.points.push_back(TempPoint); }
void WhereAmI::run(void) { #ifdef TESTBENCH StartupStore(_T("Oracle : start to find position") NEWLINE); #endif PeriodClock _time; _time.Update(); ResetNearestTopology(); LockTerrainDataGraphics(); const vectorObj center = { MapWindow::GetPanLongitude(), MapWindow::GetPanLatitude() }; rectObj bounds = { center.x, center.y, center.x, center.y }; for(int i = 0; i < 10; ++i) { double X, Y; FindLatitudeLongitude(center.y, center.x, i*360/10, 30*1000, &Y, &X ); bounds.minx = std::min(bounds.minx, X); bounds.maxx = std::max(bounds.maxx, X); bounds.miny = std::min(bounds.miny, Y); bounds.maxy = std::max(bounds.maxy, Y); } for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { // See also CheckScale for category checks! We should use a function in fact. if ( TopoStore[z]->scaleCategory == 10 || (TopoStore[z]->scaleCategory >= 70 && TopoStore[z]->scaleCategory <=100)) { TopoStore[z]->SearchNearest(bounds); } } } TCHAR ttmp[100]; double dist,wpdist,brg; NearestTopoItem *item=NULL; bool found=false, over=false, saynear=false, needmorewp=false, secondwpdone=false; #if TESTBENCH if (NearestBigCity.Valid) StartupStore(_T("... NEAREST BIG CITY <%s> at %.0f km brg=%.0f\n"), NearestBigCity.Name,NearestBigCity.Distance/1000,NearestBigCity.Bearing); if (NearestCity.Valid) StartupStore(_T("... NEAREST CITY <%s> at %.0f km brg=%.0f\n"), NearestCity.Name,NearestCity.Distance/1000,NearestCity.Bearing); if (NearestSmallCity.Valid) StartupStore(_T("... NEAREST TOWN <%s> at %.0f km brg=%.0f\n"), NearestSmallCity.Name,NearestSmallCity.Distance/1000,NearestSmallCity.Bearing); if (NearestWaterArea.Valid) StartupStore(_T("... NEAREST WATER AREA <%s> at %.0f km brg=%.0f\n"), NearestWaterArea.Name,NearestWaterArea.Distance/1000,NearestWaterArea.Bearing); #endif _stprintf(toracle,_T("%s\n\n"), MsgToken(1724)); // YOUR POSITION: if (NearestBigCity.Valid) { _tcscat(toracle, OracleFormatDistance(NearestBigCity.Name,MsgToken(1714), NearestBigCity.Distance, NearestBigCity.Bearing,0)); // the city _tcscat(toracle, _T("\n")); } if (NearestCity.Valid && NearestSmallCity.Valid) { if ( (NearestCity.Distance - NearestSmallCity.Distance) <=3000) item=&NearestCity; else item=&NearestSmallCity; } else { if (NearestCity.Valid) item=&NearestCity; else if (NearestSmallCity.Valid) item=&NearestSmallCity; } if (item) { dist=item->Distance; brg=item->Bearing; if (dist>1500) { // // 2km South of city // _stprintf(ttmp,_T("%.0f %s %s %s "), dist*DISTANCEMODIFY, Units::GetDistanceName(), DegreesToText(brg), MsgToken(1715)); // of the city _tcscat(toracle,ttmp); } else { // // Over city // _stprintf(ttmp,_T("%s "),MsgToken(1716)); // Over the city _tcscat(toracle,ttmp); over=true; } _stprintf(ttmp,_T("<%s>"), item->Name); _tcscat(toracle,ttmp); found=true; } // Careful, some wide water areas have the center far away from us even if we are over them. // We can only check for 2-5km distances max. if (NearestWaterArea.Valid) { if (found) { if (NearestWaterArea.Distance<2000) { if (over) { // // Over city and lake // _stprintf(ttmp,_T(" %s %s"), MsgToken(1717),NearestWaterArea.Name); // and _tcscat(toracle,ttmp); saynear=true; } else { // // 2km South of city // over lake // _stprintf(ttmp,_T("\n%s %s"), MsgToken(1718),NearestWaterArea.Name); // over _tcscat(toracle,ttmp); saynear=true; } } else { if (NearestWaterArea.Distance<6000) { if (over) { // // Over city // near lake // _stprintf(ttmp,_T("\n%s %s"), MsgToken(1719),NearestWaterArea.Name); // near to _tcscat(toracle,ttmp); } else { // // 2km South of city // near lake // _stprintf(ttmp,_T("\n%s %s"), MsgToken(1718),NearestWaterArea.Name); // over _tcscat(toracle,ttmp); } } // else no mention to water area, even if it is the only item. Not accurate! } } else { if (NearestWaterArea.Distance>2000) { brg=NearestWaterArea.Bearing; // // 2km North of lake // _stprintf(ttmp,_T("%.0f %s %s "), NearestWaterArea.Distance*DISTANCEMODIFY, Units::GetDistanceName(), DegreesToText(brg)); _tcscat(toracle,ttmp); _stprintf(ttmp,_T("%s <%s>"), MsgToken(1711),NearestWaterArea.Name); // of _tcscat(toracle,ttmp); } else { // // Over lake // _stprintf(ttmp,_T("%s <%s>"), MsgToken(1718),NearestWaterArea.Name); // over _tcscat(toracle,ttmp); over=true; } found=true; } } _tcscat(toracle,_T("\n")); // find nearest turnpoint & nearest Landable unsigned idx_nearest_airport = 0; unsigned idx_nearest_unknown = 0; { double dist_airport = std::numeric_limits<double>::max(); double dist_unknown = std::numeric_limits<double>::max(); for(unsigned i=NUMRESWP; i<WayPointList.size(); ++i) { if(WayPointList[i].Style == STYLE_THERMAL) continue; DistanceBearing(GPS_INFO.Latitude, GPS_INFO.Longitude, WayPointList[i].Latitude, WayPointList[i].Longitude, &(WayPointCalc[i].Distance), &(WayPointCalc[i].Bearing)); if(WayPointCalc[i].Distance > 70000) continue; // To Far if(WayPointCalc[i].WpType == WPT_AIRPORT) { if(WayPointCalc[i].Distance < dist_airport) { dist_airport = WayPointCalc[i].Distance; idx_nearest_airport = i; } } if(WayPointCalc[i].Distance < dist_unknown) { dist_unknown = WayPointCalc[i].Distance; idx_nearest_unknown = i; } } } int j = idx_nearest_unknown; if (!ValidNotResWayPoint(j)) goto _end; found=true; _dowp: DistanceBearing( WayPointList[j].Latitude,WayPointList[j].Longitude, GPS_INFO.Latitude, GPS_INFO.Longitude, &wpdist,&brg); TCHAR wptype[100]; switch(WayPointList[j].Style) { case STYLE_AIRFIELDGRASS: case STYLE_GLIDERSITE: _stprintf(wptype,_T("%s "), MsgToken(1720)); // the airfield of break; case STYLE_OUTLANDING: _stprintf(wptype,_T("%s "), MsgToken(1721)); // the field of needmorewp=true; break; case STYLE_AIRFIELDSOLID: _stprintf(wptype,_T("%s "), MsgToken(1722)); // the airport of break; default: _tcscpy(wptype,_T("")); needmorewp=true; break; } if ( (_tcslen(wptype)==0) && WayPointCalc[j].IsLandable) { if (WayPointCalc[j].IsAirport) { _stprintf(wptype,_T("%s "), MsgToken(1720)); // the airfield of needmorewp=false; } else { _stprintf(wptype,_T("%s "), MsgToken(1721)); // the field of needmorewp=true; } } else { if (_tcslen(wptype)==0 ) { _tcscpy(wptype,_T("")); needmorewp=true; } } // nn km south if (wpdist>2000) { // // 2km South of city // and/over lake // 4 km SW of waypoint _stprintf(ttmp,_T("\n%.0f %s %s "), wpdist*DISTANCEMODIFY, Units::GetDistanceName(), DegreesToText(brg)); _tcscat(toracle,ttmp); _stprintf(ttmp,_T("%s %s<%s>"), MsgToken(1711),wptype,WayPointList[j].Name); // of _tcscat(toracle,ttmp); } else { if (found) { if (over) { if (saynear) { // // 2km South of city // over lake // near waypoint // ---- // Over city and lake // near waypoint _stprintf(ttmp,_T("\n%s %s<%s>"), MsgToken(1719),wptype,WayPointList[j].Name); // near to _tcscat(toracle,ttmp); } else { // Over city // near lake and waypoint _stprintf(ttmp,_T(" %s %s<%s>"), MsgToken(1717),wptype,WayPointList[j].Name); // and _tcscat(toracle,ttmp); } } else { _stprintf(ttmp,_T("\n%s %s<%s>"), MsgToken(1719),wptype,WayPointList[j].Name); // near to _tcscat(toracle,ttmp); } } else { // // Near waypoint (because "over" could be wrong, we have altitudes in wp!) // _stprintf(ttmp,_T("%s %s<%s>"), MsgToken(1723),wptype,WayPointList[j].Name); // Near to _tcscat(toracle,ttmp); } } if (!needmorewp) goto _end; if (secondwpdone) goto _end; j=idx_nearest_airport; if (!ValidNotResWayPoint(j)) goto _end; secondwpdone=true; goto _dowp; _end: UnlockTerrainDataGraphics(); #ifdef ULLIS_PRIVATE_FEATURES _stprintf(ttmp,_T("\n\nin %i ft (MSL)"), (int)( GPS_INFO.Altitude*TOFEET)); // in height _tcscat(toracle,ttmp); #endif // VERY SORRY - YOUR POSITION IS UNKNOWN! if (!found) _stprintf(toracle,_T("\n\n%s\n\n%s"), MsgToken(1725),MsgToken(1726)); CharUpper(toracle); #ifdef TESTBENCH StartupStore(_T("Oracle : Result found in %d ms") NEWLINE, _time.Elapsed()); #endif }
void Statistics::RenderTask(LKSurface& Surface, const RECT& rc, const bool olcmode) { int i, j; unsigned int ui; double fXY_Scale = 1.5; double lat1 = 0; double lon1 = 0; double lat2 = 0; double lon2 = 0; double x1, y1, x2=0, y2=0; double lat_c, lon_c; double aatradius[MAXTASKPOINTS]; // find center ResetScale(); if ( (!ValidTaskPoint(0) || !ValidTaskPoint(1)) && !olcmode) { DrawNoData(Surface,rc); return; } for (i=0; i<MAXTASKPOINTS; i++) { aatradius[i]=0; } bool nowaypoints = true; for (i=0; i<MAXTASKPOINTS; i++) { if (ValidTaskPoint(i)) { lat1 = WayPointList[Task[i].Index].Latitude; lon1 = WayPointList[Task[i].Index].Longitude; ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); nowaypoints = false; } } if (nowaypoints ) { DrawNoData(Surface, rc); return; } CPointGPSArray trace; CContestMgr::Instance().Trace(trace); for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); ScaleYFromValue(rc, lat1); ScaleXFromValue(rc, lon1); } const auto hfOldU = Surface.SelectObject(LK8InfoNormalFont); lat_c = (y_max+y_min)/2; lon_c = (x_max+x_min)/2; int nwps = 0; // find scale ResetScale(); lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); for (i=0; i<MAXTASKPOINTS; i++) { if (ValidTaskPoint(i)) { nwps++; lat1 = WayPointList[Task[i].Index].Latitude; lon1 = WayPointList[Task[i].Index].Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); if (AATEnabled) { double aatlat; double aatlon; double bearing; double radius; if (ValidTaskPoint(i+1)) { if (Task[i].AATType == SECTOR) radius = Task[i].AATSectorRadius; else radius = Task[i].AATCircleRadius; for (j=0; j<4; j++) { bearing = j*360.0/4; FindLatitudeLongitude(WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, bearing, radius, &aatlat, &aatlon); x1 = (aatlon-lon_c)*fastcosine(aatlat); y1 = (aatlat-lat_c); ScaleXFromValue(rc, x1); ScaleYFromValue(rc, y1); if (j==0) { aatradius[i] = fabs(aatlat-WayPointList[Task[i].Index].Latitude); } } } else { aatradius[i] = 0; } } } } for(ui=0; ui<trace.size(); ui++) { lat1 = trace[ui].Latitude(); lon1 = trace[ui].Longitude(); x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); ScaleXFromValue(rc, x1*fXY_Scale); ScaleYFromValue(rc, y1*fXY_Scale); } ScaleMakeSquare(rc); // draw aat areas if (AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); #ifdef HAVE_HATCHED_BRUSH Surface.SelectObject(MapWindow::GetAirspaceBrushByClass(AATASK)); #else Surface.SelectObject(LKBrush_Yellow); #endif Surface.SelectObject(LK_WHITE_PEN); if (Task[i].AATType == SECTOR) { Surface.Segment((long)((x2-x_min)*xscale+rc.left+BORDER_X),(long)((y_max-y2)*yscale+rc.top),(long)(aatradius[i]*yscale),rc, Task[i].AATStartRadial, Task[i].AATFinishRadial); } else { Surface.DrawCircle((long)((x2-x_min)*xscale+rc.left+BORDER_X), (long)((y_max-y2)*yscale+rc.top), (long)(aatradius[i]*yscale), true); } } } } if (!AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; if (!ValidTaskPoint(1) ) { lat2 = GPS_INFO.Latitude; lon2 = GPS_INFO.Longitude; } else { lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; } x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); // DrawLine(hdc, rc, x1, y1, x2, y2, STYLE_DASHGREEN); if( ValidTaskPoint(4) && i <2) goto skip_FAI; #ifndef UNDITHER RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTYELLOW ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_LIGHTCYAN ); #else RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTGREY ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_GREY ); #endif skip_FAI: DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_DASHGREEN); Surface.Segment((long)((x2-x_min)*xscale+rc.left+BORDER_X),(long)((y_max-y2)*yscale+rc.top),(long)(aatradius[i]*yscale),rc, Task[i].AATStartRadial, Task[i].AATFinishRadial); } } if( ValidTaskPoint(1) && ValidTaskPoint(3)) { lat1 = WayPointList[Task[3].Index].Latitude; lon1 = WayPointList[Task[3].Index].Longitude; lat2 = WayPointList[Task[1].Index].Latitude; lon2 = WayPointList[Task[1].Index].Longitude; #ifndef UNDITHER RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTYELLOW ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_LIGHTCYAN ); #else RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,1, RGB_LIGHTGREY ); RenderFAISector ( Surface, rc, lat1, lon1, lat2, lon2, lat_c, lon_c,0, RGB_GREY ); #endif } } // draw task lines and label for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; if (!ValidTaskPoint(1) ) { lat2 = GPS_INFO.Latitude; lon2 = GPS_INFO.Longitude; } else { lat2 = WayPointList[Task[i].Index].Latitude; lon2 = WayPointList[Task[i].Index].Longitude; } x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_BLUETHIN); #if (WINDOWSPC>0) Surface.SetBackgroundOpaque(); #endif TCHAR text[100]; Surface.SetTextColor(RGB_BLUE); /* if ((i==nwps-1) && (Task[i].Index == Task[0].Index)) { _stprintf(text,TEXT("%0d"),1); DrawLabel(hdc, rc, text, x1+(x2-x1)/2, y1+(y2-y1)/2); } else */ { _stprintf(text,TEXT("%0d"),i); DrawLabel(Surface, rc, text, x1+(x2-x1)/2, y1+(y2-y1)/2); } if ((i==ActiveTaskPoint)&&(!AATEnabled)) { lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_REDTHICK); } } } // draw aat task line if (AATEnabled) { for (i=MAXTASKPOINTS-1; i>0; i--) { if (ValidTaskPoint(i) && ValidTaskPoint(i-1)) { if (i==1) { lat1 = WayPointList[Task[i-1].Index].Latitude; lon1 = WayPointList[Task[i-1].Index].Longitude; } else { lat1 = Task[i-1].AATTargetLat; lon1 = Task[i-1].AATTargetLon; } lat2 = Task[i].AATTargetLat; lon2 = Task[i].AATTargetLon; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); x2 = (lon2-lon_c)*fastcosine(lat2); y2 = (lat2-lat_c); DrawLine(Surface, rc, x1, y1, x2, y2, STYLE_REDTHICK); } } } DrawXGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); DrawYGrid(Surface, rc, 1.0, 0, STYLE_THINDASHPAPER, 1.0, false); Surface.SelectObject(hfOldU); // Draw aircraft on top lat1 = GPS_INFO.Latitude; lon1 = GPS_INFO.Longitude; x1 = (lon1-lon_c)*fastcosine(lat1); y1 = (lat1-lat_c); Surface.SetBackgroundTransparent(); DrawLabel(Surface, rc, TEXT("+"), x1, y1); }
// // LK8000 SS1 = Soaring Simulator V1 by Paolo Ventafridda // Still basic, but usable // void LKSimulator(void) { LockFlightData(); // GPS_INFO.NAVWarning = false; GPS_INFO.SatellitesUsed = 6; // Even on ground, we can turn the glider in the hangar BEARING += SimTurn; if (BEARING<0) BEARING+=360; else if (BEARING>359) BEARING-=360; #if SIMLANDING static bool crashed=false, landedwarn=true; #endif static bool doinit=true, landing=false, stallwarn=true, circling=false, flarmwasinit=false; static short counter=0; double tdistance, tbearing; double thermalstrength=0, sinkstrength=0; extern void SimFlarmTraffic(long id, double offset); if (doinit) { if (counter++<4) { UnlockFlightData(); return; } #if TESTBENCH StartupStore(_T(". SIMULATOR: real init%s"),NEWLINE); #endif // Add a couple of thermals for the boys InsertThermalHistory(GPS_INFO.Time-1887, GPS_INFO.Latitude-0.52, GPS_INFO.Longitude-0.52, 873, 1478,1.5); InsertThermalHistory(GPS_INFO.Time-987, GPS_INFO.Latitude-0.41, GPS_INFO.Longitude-0.41, 762, 1367,1.8); InsertThermalHistory(GPS_INFO.Time-100, GPS_INFO.Latitude-0.02, GPS_INFO.Longitude-0.02, 650, 1542,2.2); WayPointList[RESWP_LASTTHERMAL].Latitude = GPS_INFO.Latitude-0.022; WayPointList[RESWP_LASTTHERMAL].Longitude = GPS_INFO.Longitude-0.022; WayPointList[RESWP_LASTTHERMAL].Altitude = 650; ThLatitude=GPS_INFO.Latitude-0.022; ThLongitude=GPS_INFO.Longitude-0.022; if (EnableFLARMMap) { srand( GetTickCount()); SimFlarmTraffic(0xdd8951,22.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8944,31.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8a43,16.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8a42,41.0+(double)(rand()/1000.0)); } doinit=false; } // First Aircraft min altitude is at ground level if (ALTITUDE==0) if (CALCULATED_INFO.TerrainValid) ALTITUDE= CALCULATED_INFO.TerrainAlt; if (ISGAAIRCRAFT) { // todo: fuel consumption, engine efficiency etc. } // We cannot use doinit for flarm, because it could be enabled from configuration AFTER startup, // and it must work all the way the same in order not to confuse users. if (EnableFLARMMap) { if (!flarmwasinit) { srand( GetTickCount()); // Add a poker of traffic for the boys SimFlarmTraffic(0xdd8951,22.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8944,31.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8a43,16.0+(double)(rand()/1000.0)); SimFlarmTraffic(0xdd8a42,41.0+(double)(rand()/1000.0)); DoStatusMessage(gettext(TEXT("_@M279_"))); // FLARM DETECTED (in sim) flarmwasinit=true; } else { // Let one of the objects be a ghost and a zombie, and keep the rest real SimFlarmTraffic(0xdd8951,0); SimFlarmTraffic(0xdd8944,0); SimFlarmTraffic(0xdd8a43,0); } } if (ISPARAGLIDER || ISGLIDER) { // SetBallast is calculating sinkratecache for values starting from 4 to MAXSPEED, in m/s . // ONLY during flight, we will sink in the air if (FLYING && (IASMS>3) && (IASMS<MAXSPEED) ) { double sinkias=-1*(GlidePolar::sinkratecache[(int)IASMS]); if (sinkias>10) sinkias=10; // set a limiter for sink rate // StartupStore(_T(".... ias=%.0f sinkias=%.3f oldAlt=%.3f newAlt=%.3f\n"), // CALCULATED_INFO.IndicatedAirspeedEstimated*TOKPH, sinkias, GPS_INFO.Altitude, GPS_INFO.Altitude+sinkias); double simlift=0; if (THERMALLING == TRUE) { // entering the thermal mode right now if (!circling) { circling=true; DistanceBearing(GPS_INFO.Latitude,GPS_INFO.Longitude,ThLatitude,ThLongitude,&tdistance,&tbearing); if (tdistance>1000) { // a new thermal ThLatitude=GPS_INFO.Latitude; // we mark the new thermal ThLongitude=GPS_INFO.Longitude; ALTITUDE+=simlift; // sink rate adjusted later } else { // start circling near the old thermal } } else { // already thermalling } // ALTITUDE+=simlift+GlidePolar::minsink; } else { if (circling) { // we were circling, now leaving the thermal circling=false; } else { // not circling, already cruising } } // Are we near the thermal? DistanceBearing(GPS_INFO.Latitude,GPS_INFO.Longitude,ThLatitude,ThLongitude,&tdistance,&tbearing); thermalstrength=4; // m/s ThermalRadius=200; // we assume a perfect thermal, a circle of this diameter. Stronger in the center. // thermalbase sinkstrength=2; // how intense is the fallout of the thermal SinkRadius=150; // circular ring of the fallout if (tdistance>=ThermalRadius && tdistance<(ThermalRadius+SinkRadius) ) { // we are in the sinking zone of the thermal.. simlift= sinkstrength- ((tdistance-ThermalRadius)/SinkRadius)*sinkstrength; simlift+=0.1; // adjust rounding errors simlift*=-1; //StartupStore(_T(".. sinking zone: dist=%.1f sink=%.1f\n"), tdistance,simlift); } if (tdistance<ThermalRadius) { // we are in the lift zone simlift= thermalstrength- (tdistance/ThermalRadius)*thermalstrength; simlift+=0.1; // adjust rounding errors //StartupStore(_T(".. climbing zone: dist=%.1f climb=%.1f\n"), tdistance,simlift); } // Update altitude with the lift or sink, ALTITUDE+=simlift; // Update the new altitude with the natural sink, but not going lower than 0 ALTITUDE-=(sinkias+0.1); // rounding errors require a correction if (ALTITUDE<=0) ALTITUDE=0; #if SIMLANDING if (CALCULATED_INFO.TerrainValid && (CALCULATED_INFO.AltitudeAGL <=20) ) { if (IAS <= (MINSPEED+3)) landing=true; else { // we dont simulate crashing. LK8000 pilots never crash. crashed=true; } } if (CALCULATED_INFO.TerrainValid && (CALCULATED_INFO.AltitudeAGL >100) ) { landing=false; } if (!landing && CALCULATED_INFO.TerrainValid && (CALCULATED_INFO.AltitudeAGL <=0) ) { GPS_INFO.Speed=0; landing=true; if (landedwarn) { DoStatusMessage(_T("YOU HAVE LANDED")); landedwarn=false; } } else landedwarn=true; #endif } } // Glider/Paragliders if (FLYING) { // simple stall at 1 G if (!landing && (IAS<=STALLSPEED && IASMS>3)) { if (stallwarn) { // DoStatusMessage(_T("STALLING")); // OK, people do not like stalling. stallwarn=false; } #if 0 // DO NOT SIMULATE STALLING NOW // GPS_INFO.Speed= (GlidePolar::Vminsink*0.85)+1; ALTITUDE-=20; if (ALTITUDE<=0) ALTITUDE=0; #endif } else stallwarn=true; #if SIMLANDING if (landing || IASMS<4) { GPS_INFO.Speed-=GPS_INFO.Speed*0.2; } if (crashed) { GPS_INFO.Speed=0; } #endif if (GS<0) { GPS_INFO.Speed=0; } } FindLatitudeLongitude(GPS_INFO.Latitude, GPS_INFO.Longitude, GPS_INFO.TrackBearing, GPS_INFO.Speed*1.0, &GPS_INFO.Latitude, &GPS_INFO.Longitude); GPS_INFO.Time+= 1.0; long tsec = (long)GPS_INFO.Time; GPS_INFO.Hour = tsec/3600; GPS_INFO.Minute = (tsec-GPS_INFO.Hour*3600)/60; GPS_INFO.Second = (tsec-GPS_INFO.Hour*3600-GPS_INFO.Minute*60); UnlockFlightData(); }