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; } } }
/** * Renders the AbstractAirspace on the canvas * @param as AbstractAirspace to render */ void Render(const AbstractAirspace& as) { int type = as.GetType(); if (type <= 0) return; // No intersections for this airspace if (m_intersections.empty()) return; // Select pens and brushes #ifndef USE_GDI Color color = airspace_look.colors[settings.colours[type]]; #ifdef ENABLE_OPENGL color = color.WithAlpha(48); #endif Brush brush(color); #else const Brush &brush = airspace_look.brushes[settings.brushes[type]]; canvas.SetTextColor(LightColor(airspace_look.colors[settings.colours[type]])); #endif PixelRect rcd; // Calculate top and bottom coordinate rcd.top = chart.screenY(as.GetTopAltitude(state)); if (as.IsBaseTerrain()) rcd.bottom = chart.screenY(fixed_zero); else rcd.bottom = chart.screenY(as.GetBaseAltitude(state)); // Iterate through the intersections for (auto it = m_intersections.begin(); it != m_intersections.end(); ++it) { const GeoPoint p_start = it->first; const GeoPoint p_end = it->second; const fixed distance_start = start.Distance(p_start); const fixed distance_end = start.Distance(p_end); // Determine left and right coordinate rcd.left = chart.screenX(distance_start); rcd.right = chart.screenX(distance_end); // only one edge found, next edge must be beyond screen if ((rcd.left == rcd.right) && (p_start == p_end)) { rcd.right = chart.screenX(chart.getXmax()); } // Draw the airspace RenderBox(rcd, brush, settings.black_outline, type); } }
inline double OrderedTask::ScanDistanceMin(const GeoPoint &location, bool full) { if (!full && location.IsValid() && last_min_location.IsValid() && DistanceIsSignificant(location, last_min_location)) { const TaskWaypoint *active = GetActiveTaskPoint(); if (active != nullptr) { const GeoPoint &target = active->GetWaypoint().location; const unsigned last_distance = (unsigned)last_min_location.Distance(target); const unsigned cur_distance = (unsigned)location.Distance(target); /* do the full scan only if the distance to the active task point has changed by more than 5%, otherwise we don't expect any relevant changes */ if (last_distance < 2000 || cur_distance < 2000 || last_distance * 20 >= cur_distance * 21 || cur_distance * 20 >= last_distance * 21) full = true; } } if (full) { RunDijsktraMin(location); last_min_location = location; } return task_points.front()->ScanDistanceMin(); }
bool AirspaceFilterData::Match(const GeoPoint &location, const FlatProjection &projection, const AbstractAirspace &as) const { if (cls != AirspaceClass::AIRSPACECLASSCOUNT && as.GetType() != cls) return false; if (name_prefix != nullptr && !as.MatchNamePrefix(name_prefix)) return false; if (!direction.IsNegative()) { const auto closest = as.ClosestPoint(location, projection); const auto bearing = location.Bearing(closest); auto direction_error = (bearing - direction).AsDelta().AbsoluteDegrees(); if (direction_error > fixed(18)) return false; } if (!negative(distance)) { const auto closest = as.ClosestPoint(location, projection); const auto distance = location.Distance(closest); if (distance > distance) return false; } return true; }
void RasterRenderer::ScanMap(const RasterMap &map, const WindowProjection &projection) { // Coordinates of the MapWindow center unsigned x = projection.GetScreenWidth() / 2; unsigned y = projection.GetScreenHeight() / 2; // GeoPoint corresponding to the MapWindow center GeoPoint Gmid = projection.ScreenToGeo(x, y); // GeoPoint "next to" Gmid (depends on terrain resolution) GeoPoint Gneighbor = projection.ScreenToGeo(x + quantisation_pixels, y + quantisation_pixels); // Geographical edge length of pixel in the MapWindow center in meters pixel_size = fixed_sqrt_half * Gmid.Distance(Gneighbor); // set resolution fixed map_pixel_size = map.pixel_distance(Gmid, 1); fixed q = map_pixel_size / pixel_size; if (pixel_size < fixed(3000)) { /* round down to reduce slope shading artefacts (caused by RasterBuffer interpolation) */ quantisation_effective = std::max(1, (int)q); if (quantisation_effective > 25) /* disable slope shading when zoomed in very near (not enough terrain resolution to make a useful slope calculation) */ quantisation_effective = 0; } else /* disable slope shading when zoomed out very far (too tiny) */ quantisation_effective = 0; height_matrix.Fill(map, projection, quantisation_pixels, true); }
void AirspaceDetailsWidget::Prepare(ContainerWindow &parent, const PixelRect &rc) { const NMEAInfo &basic = CommonInterface::Basic(); TCHAR buffer[64]; AddMultiLine(airspace.GetName()); if (!airspace.GetRadioText().empty()) AddReadOnly(_("Radio"), nullptr, airspace.GetRadioText().c_str()); AddReadOnly(_("Type"), nullptr, AirspaceFormatter::GetClass(airspace)); AirspaceFormatter::FormatAltitude(buffer, airspace.GetTop()); AddReadOnly(_("Top"), nullptr, buffer); AirspaceFormatter::FormatAltitude(buffer, airspace.GetBase()); AddReadOnly(_("Base"), nullptr, buffer); if (warnings != nullptr) { const GeoPoint closest = airspace.ClosestPoint(basic.location, warnings->GetProjection()); const fixed distance = closest.Distance(basic.location); FormatUserDistance(distance, buffer); AddReadOnly(_("Range"), nullptr, buffer); } }
void TaskPointRenderer::DrawIsoline(const AATPoint &tp) { if (!tp.valid() || !IsTargetVisible(tp)) return; AATIsolineSegment seg(tp, task_projection); if (!seg.IsValid()) return; #define fixed_twentieth fixed(1.0 / 20.0) GeoPoint start = seg.Parametric(fixed_zero); GeoPoint end = seg.Parametric(fixed_one); if (m_proj.GeoToScreenDistance(start.Distance(end)) <= 2) return; RasterPoint screen[21]; screen[0] = m_proj.GeoToScreen(start); screen[20] = m_proj.GeoToScreen(end); for (unsigned i = 1; i < 20; ++i) { fixed t = i * fixed_twentieth; GeoPoint ga = seg.Parametric(t); screen[i] = m_proj.GeoToScreen(ga); } canvas.Select(task_look.isoline_pen); canvas.SetBackgroundTransparent(); canvas.DrawPolyline(screen, 21); canvas.SetBackgroundOpaque(); }
bool update_location(const GeoPoint &location_now) { fixed range_now = location_now.Distance(waypoint.location); if (range_now < range) { range = range_now; location = location_now; return true; } return false; // TODO: or if distance from previous tp to here is greater than leg (and wasnt previously) }
fixed RasterProjection::pixel_distance(const GeoPoint &location, unsigned pixels) const { enum { /** * This factor is used to reduce fixed point rounding errors. * x_scale and y_scale are quite large numbers, and building their * reciprocals may lose a lot of precision. */ FACTOR = 256, }; Angle distance = width_to_angle(fixed_sqrt_two * FACTOR * pixels); GeoPoint p = GeoPoint(location.longitude + distance, location.latitude); fixed x = location.Distance(p); distance = height_to_angle(fixed_sqrt_two * FACTOR * pixels); p = GeoPoint(location.longitude, location.latitude + distance); fixed y = location.Distance(p); return max(x, y) / FACTOR; }
void AATPoint::GetTargetRangeRadial(fixed &range, fixed &radial) const { const fixed oldrange = range; const GeoPoint fprev = GetPrevious()->GetLocationRemaining(); const GeoPoint floc = GetLocation(); const Angle radialraw = (floc.Bearing(GetTargetLocation()) - fprev.Bearing(floc)).AsBearing(); const fixed d = floc.Distance(GetTargetLocation()); const fixed radius = floc.Distance(GetLocationMin()); const fixed rangeraw = min(fixed_one, d / radius); radial = radialraw.AsDelta().Degrees(); const fixed rangesign = (fabs(radial) > fixed(90)) ? fixed_minus_one : fixed_one; range = rangeraw * rangesign; if ((oldrange == fixed_zero) && (range == fixed_zero)) radial = fixed_zero; }
GeoPoint AirspaceCircle::ClosestPoint(const GeoPoint& loc) const { // Calculate distance from center point const fixed d = loc.Distance(m_center); // If loc is INSIDE the circle return loc itself if (d <= m_radius) return loc; // Otherwise calculate point on the circle in // the direction from center to loc return m_center.IntermediatePoint(loc, m_radius); }
RangeAndRadial AATPoint::GetTargetRangeRadial(fixed oldrange) const { const GeoPoint fprev = GetPrevious()->GetLocationRemaining(); const GeoPoint floc = GetLocation(); const Angle radialraw = (floc.Bearing(GetTargetLocation()) - fprev.Bearing(floc)).AsBearing(); Angle radial = radialraw.AsDelta(); fixed d = floc.Distance(GetTargetLocation()); if (radial < -Angle::QuarterCircle() || radial > Angle::QuarterCircle()) d = -d; const fixed radius = negative(d) ? floc.Distance(GetLocationMin()) : floc.Distance(GetLocationMax()); const fixed range = Clamp(d / radius, fixed(-1), fixed(1)); if (oldrange == fixed(0) && range == fixed(0)) radial = Angle::Zero(); return RangeAndRadial{ range, radial }; }
void Airspaces::VisitIntersecting(const GeoPoint &loc, const GeoPoint &end, AirspaceIntersectionVisitor& visitor) const { if (empty()) // nothing to do return; const GeoPoint c = loc.Middle(end); Airspace bb_target(c, task_projection); int projected_range = task_projection.ProjectRangeInteger(c, loc.Distance(end) / 2); IntersectingAirspaceVisitorAdapter adapter(loc, end, task_projection, visitor); airspace_tree.visit_within_range(bb_target, -projected_range, adapter); #ifdef INSTRUMENT_TASK n_queries++; #endif }
void Airspaces::VisitIntersecting(const GeoPoint &loc, const GeoPoint &end, AirspaceIntersectionVisitor& visitor) const { if (empty()) return; // nothing to do FlatRay ray(task_projection.project(loc), task_projection.project(end)); const GeoPoint c = loc.Middle(end); Airspace bb_target(c, task_projection); int mrange = task_projection.project_range(c, loc.Distance(end) / 2); IntersectingAirspaceVisitorAdapter adapter(loc, end, ray, visitor); airspace_tree.visit_within_range(bb_target, -mrange, adapter); #ifdef INSTRUMENT_TASK n_queries++; #endif }
bool TargetMapWindow::isClickOnTarget(const RasterPoint pc) { if (task == NULL) return false; ProtectedTaskManager::Lease task_manager(*task); if (!task_manager->HasTarget(target_index)) return false; const GeoPoint gnull(Angle::Zero(), Angle::Zero()); const GeoPoint& t = task_manager->GetLocationTarget(target_index, gnull); if (t == gnull) return false; const GeoPoint gp = projection.ScreenToGeo(pc.x, pc.y); if (projection.GeoToScreenDistance(gp.Distance(t)) < Layout::GetHitRadius()) return true; return false; }
inline void AirspaceIntersectionVisitorSlice::Render(const AbstractAirspace &as) const { AirspaceClass type = as.GetType(); // No intersections for this airspace if (intersections.empty()) return; PixelRect rcd; // Calculate top and bottom coordinate rcd.top = chart.ScreenY(as.GetTopAltitude(state)); if (as.IsBaseTerrain()) rcd.bottom = chart.ScreenY(fixed(0)); else rcd.bottom = chart.ScreenY(as.GetBaseAltitude(state)); int min_x = 1024, max_x = 0; // Iterate through the intersections for (const auto &i : intersections) { const GeoPoint &p_start = i.first; const GeoPoint &p_end = i.second; rcd.left = chart.ScreenX(start.Distance(p_start)); // only one edge found, next edge must be beyond screen if (p_start == p_end) rcd.right = chart.ScreenX(chart.GetXMax()); else rcd.right = chart.ScreenX(start.Distance(p_end)); if (rcd.left < min_x) min_x = rcd.left; if (rcd.right > max_x) max_x = rcd.right; // Draw the airspace RenderBox(rcd, type); } min_x += Layout::GetTextPadding(); max_x -= Layout::GetTextPadding(); /* draw the airspace name */ const TCHAR *name = as.GetName(); if (name != nullptr && !StringIsEmpty(name) && min_x < max_x) { canvas.SetBackgroundTransparent(); canvas.SetTextColor(COLOR_BLACK); const unsigned max_width = max_x - min_x; const PixelSize name_size = canvas.CalcTextSize(name); const int x = unsigned(name_size.cx) >= max_width ? min_x : (min_x + max_x - name_size.cx) / 2; const int y = (rcd.top + rcd.bottom - name_size.cy) / 2; canvas.DrawClippedText(x, y, max_x - x, name); } }
bool OLCTriangle::FindClosingPairs(unsigned old_size) { if (predict) { return closing_pairs.insert(ClosingPair(0, n_points-1)); } struct TracePointNodeAccessor { gcc_pure int GetX(const TracePointNode &node) const { return node.point->GetFlatLocation().longitude; } gcc_pure int GetY(const TracePointNode &node) const { return node.point->GetFlatLocation().latitude; } }; QuadTree<TracePointNode, TracePointNodeAccessor> search_point_tree; for (unsigned i = old_size; i < n_points; ++i) { TracePointNode node; node.point = &GetPoint(i); node.index = i; search_point_tree.insert(node); } search_point_tree.Optimise(); bool new_pair = false; for (unsigned i = old_size; i < n_points; ++i) { TracePointNode point; point.point = &GetPoint(i); point.index = i; const unsigned max_range = trace_master.ProjectRange(GetPoint(i).GetLocation(), max_distance); const GeoPoint start = GetPoint(i).GetLocation(); const int min_altitude = GetMinimumFinishAltitude(GetPoint(i)); const int max_altitude = GetMaximumStartAltitude(GetPoint(i)); unsigned last = 0, first = i; const auto visitor = [this, i, start, min_altitude, max_altitude, &first, &last] (const TracePointNode &node) { const SearchPoint dest = GetPoint(node.index); if (node.index + 2 < i && GetPoint(node.index).GetIntegerAltitude() <= max_altitude && start.Distance(dest.GetLocation()) <= max_distance) { // point i is last point first = std::min(node.index, first); last = i; } else if (node.index > i + 2 && GetPoint(node.index).GetIntegerAltitude() >= min_altitude && start.Distance(dest.GetLocation()) <= max_distance) { // point i is first point first = i; last = std::max(node.index, last); } }; search_point_tree.VisitWithinRange(point, max_range, visitor); if (last != 0 && closing_pairs.insert(ClosingPair(first, last))) new_pair = true; } return new_pair; }
/** * distance from this to the reference */ fixed distance(const GeoPoint & ref) const { return reference.Distance(ref); }
/** * distance from this to the reference */ fixed DistanceTo(const GeoPoint &ref) const { return location.Distance(ref); }
NearWaypoint(const Waypoint &_waypoint, const GeoPoint& _location) :waypoint(_waypoint), location(_location), leg_in(0), actual_in(0) { range = location.Distance(waypoint.location); }
NearWaypoint(const Waypoint &_waypoint, const GeoPoint& _location, const NearWaypoint& previous): waypoint(_waypoint), location(_location) { range = location.Distance(waypoint.location); update_leg(previous); }
bool operator()(const Waypoint &waypoint) { return location.Distance(waypoint.location) < distance; }
void RasterMap::ScanLine(const GeoPoint &start, const GeoPoint &end, short *buffer, unsigned size, bool interpolate) const { assert(buffer != NULL); assert(size > 0); const short invalid = RasterBuffer::TERRAIN_INVALID; const fixed total_distance = start.Distance(end); if (!positive(total_distance)) { std::fill(buffer, buffer + size, invalid); return; } /* clip the line to the map bounds */ GeoPoint clipped_start = start, clipped_end = end; const GeoClip clip(GetBounds()); if (!clip.ClipLine(clipped_start, clipped_end)) { std::fill(buffer, buffer + size, invalid); return; } fixed clipped_start_distance = std::max(clipped_start.Distance(start), fixed(0)); fixed clipped_end_distance = std::max(clipped_end.Distance(start), fixed(0)); /* calculate the offsets of the clipped range within the buffer */ unsigned clipped_start_offset = (unsigned)(size * clipped_start_distance / total_distance); unsigned clipped_end_offset = uround(size * clipped_end_distance / total_distance); if (clipped_end_offset > size) clipped_end_offset = size; if (clipped_start_offset + 2 > clipped_end_offset) { std::fill(buffer, buffer + size, invalid); return; } assert(clipped_start_offset < size); assert(clipped_end_offset <= size); /* fill the two regions which are outside the map */ std::fill(buffer, buffer + clipped_start_offset, invalid); std::fill(buffer + clipped_end_offset, buffer + size, invalid); /* now scan the middle part which is within the map */ const unsigned max_x = raster_tile_cache.GetFineWidth(); const unsigned max_y = raster_tile_cache.GetFineHeight(); RasterLocation raster_start = projection.ProjectFine(clipped_start); if (raster_start.x >= max_x) raster_start.x = max_x - 1; if (raster_start.y >= max_y) raster_start.y = max_y - 1; RasterLocation raster_end = projection.ProjectFine(clipped_end); if (raster_end.x >= max_x) raster_end.x = max_x - 1; if (raster_end.y >= max_y) raster_end.y = max_y - 1; raster_tile_cache.ScanLine(raster_start, raster_end, buffer + clipped_start_offset, clipped_end_offset - clipped_start_offset, interpolate); }
bool AirspaceCircle::Inside(const GeoPoint &loc) const { return (loc.Distance(m_center) <= m_radius); }