double RasterProjection::FinePixelDistance(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, }; // must have called Set() first otherwise this is invalid assert(x_scale != 0); assert(y_scale != 0); Angle distance = WidthToAngle(M_SQRT2 * FACTOR * pixels); GeoPoint p = GeoPoint(location.longitude + distance, location.latitude); auto x = location.DistanceS(p); distance = HeightToAngle(M_SQRT2 * FACTOR * pixels); p = GeoPoint(location.longitude, location.latitude + distance); auto y = location.DistanceS(p); return std::max(x, y) / FACTOR; }
inline void TaskPointRenderer::DrawIsoline(const AATPoint &tp) { if (!tp.valid() || !IsTargetVisible(tp)) return; AATIsolineSegment seg(tp, flat_projection); if (!seg.IsValid()) return; #define fixed_twentieth fixed(1.0 / 20.0) GeoPoint start = seg.Parametric(fixed(0)); GeoPoint end = seg.Parametric(fixed(1)); if (m_proj.GeoToScreenDistance(start.DistanceS(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(); }
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 center = projection.ScreenToGeo(x, y); // GeoPoint "next to" Gmid (depends on terrain resolution) GeoPoint neighbor = projection.ScreenToGeo(x + quantisation_pixels, y + quantisation_pixels); // Geographical edge length of pixel in the MapWindow center in meters pixel_size = M_SQRT1_2 * center.DistanceS(neighbor); // set resolution if (pixel_size < 3000) { // Data point size of the (terrain) map in meters multiplied by 256 auto map_pixel_size = map.PixelDistance(center, 1); // How many screen pixels does one data point stretch? auto q = map_pixel_size / pixel_size; /* round down to reduce slope shading artefacts (caused by RasterBuffer interpolation) */ quantisation_effective = std::max(1, (int)q); /* disable slope shading when zoomed in very near (not enough terrain resolution to make a useful slope calculation) */ if (quantisation_effective > 25) quantisation_effective = 0; } else /* disable slope shading when zoomed out very far (too tiny) */ quantisation_effective = 0; #ifdef ENABLE_OPENGL bounds = projection.GetScreenBounds().Scale(1.5); bounds.IntersectWith(map.GetBounds()); height_matrix.Fill(map, bounds, projection.GetScreenWidth() / quantisation_pixels, projection.GetScreenHeight() / quantisation_pixels, true); last_quantisation_pixels = quantisation_pixels; #else height_matrix.Fill(map, projection, quantisation_pixels, true); #endif }
bool TargetMapWindow::isClickOnTarget(const PixelPoint pc) const { if (task == nullptr) return false; ProtectedTaskManager::Lease task_manager(*task); const GeoPoint t = task_manager->GetLocationTarget(target_index); if (!t.IsValid()) return false; const GeoPoint gp = projection.ScreenToGeo(pc.x, pc.y); if (projection.GeoToScreenDistance(gp.DistanceS(t)) < Layout::GetHitRadius()) return true; return false; }
void RasterMap::ScanLine(const GeoPoint &start, const GeoPoint &end, TerrainHeight *buffer, unsigned size, bool interpolate) const { assert(buffer != nullptr); assert(size > 0); constexpr TerrainHeight invalid = TerrainHeight::Invalid(); const double total_distance = start.DistanceS(end); if (total_distance <= 0) { std::fill_n(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_n(buffer, size, invalid); return; } double clipped_start_distance = std::max(clipped_start.DistanceS(start), 0.); double clipped_end_distance = std::max(clipped_end.DistanceS(start), 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_n(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); }