gcc_const static unsigned ContourInterval(const TerrainHeight h, const unsigned contour_height_scale) { if (gcc_unlikely(h.IsSpecial()) || h.GetValue() <= 0) return 0; return ContourInterval(h.GetValue(), contour_height_scale); }
bool RasterTileCache::FirstIntersection(const int x0, const int y0, const int x1, const int y1, int h_origin, int h_dest, const int slope_fact, const int h_ceiling, const int h_safety, RasterLocation &_location, int &_h, const bool can_climb) const { RasterLocation location(x0, y0); if (!IsInside(location)) // origin is outside overall bounds return false; const TerrainHeight h_origin2 = GetFieldDirect(x0, y0).first; if (h_origin2.IsInvalid()) { _location = location; _h = h_origin; return true; } if (!h_origin2.IsSpecial()) h_origin = std::max(h_origin, (int)h_origin2.GetValue()); h_dest = std::max(h_dest, h_origin); // line algorithm parameters const int dx = abs(x1-x0); const int dy = abs(y1-y0); int err = dx-dy; const int sx = (x0 < x1)? 1: -1; const int sy = (y0 < y1)? 1: -1; // max number of steps to walk const int max_steps = (dx+dy); // calculate number of fine steps to produce a step on the overview field const int step_fine = std::max(1, max_steps >> INTERSECT_BITS); // number of steps for update to the overview map const int step_coarse = std::max(1<< OVERVIEW_BITS, step_fine); // number of steps to be cleared after climbing over obstruction const int intersect_steps = 32; // counter for steps to reach next position to be checked on the field. unsigned step_counter = 0; // total counter of fine steps int total_steps = 0; // number of steps since intersection int intersect_counter = 0; #ifdef DEBUG_TILE printf("# max steps %d\n", max_steps); printf("# step coarse %d\n", step_coarse); printf("# step fine %d\n", step_fine); #endif // early exit if origin is too high (should not occur) if (h_origin> h_ceiling) { #ifdef DEBUG_TILE printf("# fint start above ceiling %d %d\n", h_origin, h_ceiling); #endif _location = location; _h = h_origin; return true; } #ifdef DEBUG_TILE printf("# fint width %d height %d\n", width, height); #endif // location of last point within ceiling limit that doesnt intersect RasterLocation last_clear_location = location; int last_clear_h = h_origin; while (true) { if (!step_counter) { if (!IsInside(location)) break; // outside bounds const auto field_direct = GetFieldDirect(location.x, location.y); if (field_direct.first.IsInvalid()) break; const int h_terrain = field_direct.first.GetValueOr0() + h_safety; step_counter = field_direct.second ? step_fine : step_coarse; // calculate height of glide so far const int dh = (total_steps * slope_fact) >> RASTER_SLOPE_FACT; // current aircraft height int h_int = dh + h_origin; if (can_climb) { h_int = std::min(h_int, h_dest); } #ifdef DEBUG_TILE printf("%d %d %d %d %d # fint\n", location.x, location.y, h_int, h_terrain, h_ceiling); #endif // this point has intersected if aircraft is below terrain height const bool this_intersecting = (h_int< h_terrain); if (this_intersecting) { intersect_counter = 1; // when intersecting, consider origin to have started higher const int h_jump = h_terrain - h_int; h_origin += h_jump; if (can_climb) { // if intersecting beyond desired destination height, allow dest height // to be increased if (h_terrain> h_dest) h_dest = h_terrain; } else { // if can't climb, must jump so path is pure glide h_dest += h_jump; } h_int = h_terrain; } if (h_int > h_ceiling) { _location = last_clear_location; _h = last_clear_h; #ifdef DEBUG_TILE printf("# fint reach ceiling\n"); #endif return true; // reached ceiling } if (!this_intersecting) { if (intersect_counter) { intersect_counter+= step_counter; // was intersecting, now cleared. // exit with small height above terrain #ifdef DEBUG_TILE printf("# fint int->clear\n"); #endif if (intersect_counter >= intersect_steps) { _location = location; _h = h_int; return true; } } else { last_clear_location = location; last_clear_h = h_int; } } } if (!intersect_counter && (total_steps == max_steps)) { #ifdef DEBUG_TILE printf("# fint cleared\n"); #endif return false; } const int e2 = 2*err; if (e2 > -dy) { err -= dy; location.x += sx; if (step_counter) step_counter--; total_steps++; } if (e2 < dx) { err += dx; location.y += sy; if (step_counter) step_counter--; total_steps++; } } // early exit due to inability to find clearance after intersecting if (intersect_counter) { _location = last_clear_location; _h = last_clear_h; #ifdef DEBUG_TILE printf("# fint early exit\n"); #endif return true; } return false; }
static void test_troute(const RasterMap &map, double mwind, double mc, int ceiling) { GlideSettings settings; settings.SetDefaults(); RoutePlannerConfig config; config.mode = RoutePlannerConfig::Mode::BOTH; GlidePolar polar(mc); SpeedVector wind(Angle::Degrees(0), mwind); TerrainRoute route; route.UpdatePolar(settings, config, polar, polar, wind); route.SetTerrain(&map); GeoPoint origin(map.GetMapCenter()); auto pd = map.PixelDistance(origin, 1); printf("# pixel size %g\n", (double)pd); bool retval= true; { Directory::Create(Path(_T("output/results"))); std::ofstream fout ("output/results/terrain.txt"); unsigned nx = 100; unsigned ny = 100; for (unsigned i=0; i< nx; ++i) { for (unsigned j=0; j< ny; ++j) { auto fx = (double)i / (nx - 1) * 2 - 1; auto fy = (double)j / (ny - 1) * 2 - 1; GeoPoint x(origin.longitude + Angle::Degrees(0.6 * fx), origin.latitude + Angle::Degrees(0.4 * fy)); TerrainHeight h = map.GetInterpolatedHeight(x); fout << x.longitude.Degrees() << " " << x.latitude.Degrees() << " " << h.GetValue() << "\n"; } fout << "\n"; } fout << "\n"; } unsigned i=0; for (double ang = 0; ang < M_2PI; ang += M_PI / 8) { GeoPoint dest = GeoVector(40000.0, Angle::Radians(ang)).EndPoint(origin); int hdest = map.GetHeight(dest).GetValueOr0() + 100; retval = route.Solve(AGeoPoint(origin, map.GetHeight(origin).GetValueOr0() + 100), AGeoPoint(dest, mc > 0 ? hdest : std::max(hdest, 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(0); // route.UpdatePolar(polar, wind); }
void GlueMapWindow::DrawPanInfo(Canvas &canvas) const { if (!render_projection.IsValid()) return; GeoPoint location = render_projection.GetGeoLocation(); TextInBoxMode mode; mode.shape = LabelShape::OUTLINED; mode.align = TextInBoxMode::Alignment::RIGHT; const Font &font = *look.overlay.overlay_font; canvas.Select(font); unsigned padding = Layout::FastScale(4); unsigned height = font.GetHeight(); int y = 0 + padding; int x = render_projection.GetScreenWidth() - padding; if (compass_visible) /* don't obscure the north arrow */ /* TODO: obtain offset from CompassRenderer */ y += Layout::Scale(19) + Layout::FastScale(13); if (terrain) { TerrainHeight elevation = terrain->GetTerrainHeight(location); if (!elevation.IsSpecial()) { StaticString<64> elevation_long; elevation_long = _("Elevation: "); elevation_long += FormatUserAltitude(elevation.GetValue()); TextInBox(canvas, elevation_long, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; } } TCHAR buffer[256]; FormatGeoPoint(location, buffer, ARRAY_SIZE(buffer), _T('\n')); TCHAR *start = buffer; while (true) { auto *newline = StringFind(start, _T('\n')); if (newline != nullptr) *newline = _T('\0'); TextInBox(canvas, start, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; if (newline == nullptr) break; start = newline + 1; } }