void TopographyThread::Trigger(const WindowProjection &_projection) { assert(_projection.IsValid()); const GeoBounds new_bounds = _projection.GetScreenBounds(); if (last_bounds.IsValid() && last_bounds.IsInside(new_bounds)) { /* still inside cache bounds - now check if we crossed a scale threshold for at least one file, which would mean we have to update a file which was not updated for the current cache bounds */ if (scale_threshold < 0 || _projection.GetMapScale() >= scale_threshold) /* the cache is still fresh */ return; } last_bounds = new_bounds.Scale(1.1); scale_threshold = store.GetNextScaleThreshold(_projection.GetMapScale()); { const ScopeLock protect(mutex); next_projection = _projection; StandbyThread::Trigger(); } }
static void GetPolygonPoints(std::vector<RasterPoint> &pts, const AirspacePolygon &airspace, const RasterPoint pt, unsigned radius) { GeoBounds bounds = airspace.GetGeoBounds(); GeoPoint center = bounds.GetCenter(); fixed geo_heigth = bounds.GetGeoHeight(); fixed geo_width = bounds.GetGeoWidth(); fixed geo_size = std::max(geo_heigth, geo_width); WindowProjection projection; projection.SetScreenSize({radius * 2, radius * 2}); projection.SetScreenOrigin(pt.x, pt.y); projection.SetGeoLocation(center); projection.SetScale(fixed(radius * 2) / geo_size); projection.SetScreenAngle(Angle::Zero()); projection.UpdateScreenBounds(); const SearchPointVector &border = airspace.GetPoints(); pts.reserve(border.size()); for (auto it = border.begin(), it_end = border.end(); it != it_end; ++it) pts.push_back(projection.GeoToScreen(it->GetLocation())); }
int main(int argc, char **argv) { Args args(argc, argv, "PATH"); const char *map_path = args.ExpectNext(); args.ExpectEnd(); char jp2_path[4096]; strcpy(jp2_path, map_path); strcat(jp2_path, DIR_SEPARATOR_S "terrain.jp2"); TCHAR j2w_path[4096]; _tcscpy(j2w_path, PathName(map_path)); _tcscat(j2w_path, _T(DIR_SEPARATOR_S) _T("terrain.j2w")); NullOperationEnvironment operation; RasterTileCache rtc; if (!rtc.LoadOverview(jp2_path, j2w_path, operation)) { fprintf(stderr, "LoadOverview failed\n"); return EXIT_FAILURE; } GeoBounds bounds = rtc.GetBounds(); printf("bounds = %f|%f - %f|%f\n", (double)bounds.GetWest().Degrees(), (double)bounds.GetNorth().Degrees(), (double)bounds.GetEast().Degrees(), (double)bounds.GetSouth().Degrees()); do { rtc.UpdateTiles(jp2_path, rtc.GetWidth() / 2, rtc.GetHeight() / 2, 1000); } while (rtc.IsDirty()); return EXIT_SUCCESS; }
GeoBounds SearchPointVector::CalculateGeoBounds() const { GeoBounds bb = GeoBounds::Invalid(); for (const auto &i : *this) bb.Extend(i.GetLocation()); return bb; }
void DrawGeoBitmap(const RawBitmap &bitmap, PixelSize bitmap_size, const GeoBounds &bounds, const Projection &projection) { assert(bounds.IsValid()); const BulkPixelPoint vertices[] = { projection.GeoToScreen(bounds.GetNorthWest()), projection.GeoToScreen(bounds.GetNorthEast()), projection.GeoToScreen(bounds.GetSouthWest()), projection.GeoToScreen(bounds.GetSouthEast()), }; const ScopeVertexPointer vp(vertices); const GLTexture &texture = bitmap.BindAndGetTexture(); const PixelSize allocated = texture.GetAllocatedSize(); const GLfloat src_x = 0, src_y = 0, src_width = bitmap_size.cx, src_height = bitmap_size.cy; GLfloat x0 = src_x / allocated.cx; GLfloat y0 = src_y / allocated.cy; GLfloat x1 = (src_x + src_width) / allocated.cx; GLfloat y1 = (src_y + src_height) / allocated.cy; const GLfloat coord[] = { x0, y0, x1, y0, x0, y1, x1, y1, }; #ifdef USE_GLSL OpenGL::texture_shader->Use(); glEnableVertexAttribArray(OpenGL::Attribute::TEXCOORD); glVertexAttribPointer(OpenGL::Attribute::TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, coord); #else const GLEnable<GL_TEXTURE_2D> scope; OpenGL::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, coord); #endif glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #ifdef USE_GLSL glDisableVertexAttribArray(OpenGL::Attribute::TEXCOORD); OpenGL::solid_shader->Use(); #else glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif }
void RasterProjection::Set(const GeoBounds &bounds, unsigned width, unsigned height) { x_scale = fixed(width) / bounds.GetWidth().Native(); left = int(bounds.GetWest().Native() * x_scale); y_scale = fixed(height) / bounds.GetHeight().Native(); top = int(bounds.GetNorth().Native() * y_scale); }
void RasterProjection::Set(const GeoBounds &bounds, unsigned width, unsigned height) { x_scale = double(width) / bounds.GetWidth().Native(); left = AngleToWidth(bounds.GetWest()); y_scale = double(height) / bounds.GetHeight().Native(); top = AngleToHeight(bounds.GetNorth()); }
FlatBoundingBox FlatProjection::Project(const GeoBounds &bb) const { assert(IsValid()); FlatBoundingBox fb(ProjectInteger(bb.GetSouthWest()), ProjectInteger(bb.GetNorthEast())); fb.ExpandByOne(); // prevent rounding return fb; }
gcc_pure static inline rectObj ConvertRect(const GeoBounds &br) { rectObj dest; dest.minx = (double)br.GetWest().Degrees(); dest.maxx = (double)br.GetEast().Degrees(); dest.miny = (double)br.GetSouth().Degrees(); dest.maxy = (double)br.GetNorth().Degrees(); return dest; }
void OZPreviewRenderer::Draw(Canvas &canvas, const ObservationZonePoint &oz, const RasterPoint pt, unsigned radius, const TaskLook &look, const AirspaceRendererSettings &airspace_settings, const AirspaceLook &airspace_look) { fixed scale; GeoPoint center; if (IsAncientHardware()) { scale = fixed(radius) / ((const CylinderZone &)oz).GetRadius(); center = oz.GetReference(); } else { OZBoundary boundary = oz.GetBoundary(); GeoBounds bounds = GeoBounds::Invalid(); for (auto i = boundary.begin(), end = boundary.end(); i != end; ++i) bounds.Extend(*i); center = bounds.GetCenter(); fixed geo_width = bounds.GetGeoWidth(); fixed geo_heigth = bounds.GetGeoHeight(); scale = fixed(radius * 2) / std::max(geo_heigth, geo_width); } WindowProjection projection; projection.SetScreenSize({radius * 2, radius * 2}); projection.SetScreenOrigin(pt.x, pt.y); projection.SetGeoLocation(center); projection.SetScale(scale); projection.SetScreenAngle(Angle::Zero()); projection.UpdateScreenBounds(); OZRenderer ozv(look, airspace_look, airspace_settings); ozv.Draw(canvas, OZRenderer::LAYER_SHADE, projection, oz, 1); ozv.Draw(canvas, OZRenderer::LAYER_INACTIVE, projection, oz, 1); ozv.Draw(canvas, OZRenderer::LAYER_ACTIVE, projection, oz, 1); }
FlatBoundingBox OrderedTask::GetBoundingBox(const GeoBounds &bounds) const { if (!TaskSize()) { // undefined! return FlatBoundingBox(FlatGeoPoint(0,0),FlatGeoPoint(0,0)); } FlatGeoPoint ll = task_projection.ProjectInteger(bounds.GetSouthWest()); FlatGeoPoint lr = task_projection.ProjectInteger(bounds.GetSouthEast()); FlatGeoPoint ul = task_projection.ProjectInteger(bounds.GetNorthWest()); FlatGeoPoint ur = task_projection.ProjectInteger(bounds.GetNorthEast()); FlatGeoPoint fmin(std::min(ll.longitude, ul.longitude), std::min(ll.latitude, lr.latitude)); FlatGeoPoint fmax(std::max(lr.longitude, ur.longitude), std::max(ul.latitude, ur.latitude)); // note +/- 1 to ensure rounding keeps bb valid fmin.longitude -= 1; fmin.latitude -= 1; fmax.longitude += 1; fmax.latitude += 1; return FlatBoundingBox (fmin, fmax); }
/** * Checks if the size difference of any dimension is more than a * factor of two. This is used to check whether the terrain has to be * redrawn after zooming in. */ static bool IsLargeSizeDifference(const GeoBounds &a, const GeoBounds &b) { assert(a.IsValid()); assert(b.IsValid()); return a.GetWidth().Native() > Double(b.GetWidth().Native()) || a.GetHeight().Native() > Double(b.GetHeight().Native()); }
static void DrawPolygon(Canvas &canvas, const AirspacePolygon &airspace, const RasterPoint pt, unsigned radius) { if (IsAncientHardware()) { canvas.Rectangle(pt.x - radius, pt.y - radius, pt.x + radius, pt.y + radius); return; } GeoBounds bounds = airspace.GetGeoBounds(); GeoPoint center = bounds.GetCenter(); fixed geo_heigth = GeoPoint(center.longitude, bounds.north).Distance( GeoPoint(center.longitude, bounds.south)); fixed geo_width = GeoPoint(bounds.west, center.latitude).Distance( GeoPoint(bounds.east, center.latitude)); fixed geo_size = std::max(geo_heigth, geo_width); WindowProjection projection; projection.SetScreenSize(radius * 2, radius * 2); projection.SetScreenOrigin(pt.x, pt.y); projection.SetGeoLocation(center); projection.SetScale(fixed(radius * 2) / geo_size); projection.SetScreenAngle(Angle::Zero()); projection.UpdateScreenBounds(); const SearchPointVector &border = airspace.GetPoints(); std::vector<RasterPoint> pts; pts.reserve(border.size()); for (auto it = border.begin(), it_end = border.end(); it != it_end; ++it) pts.push_back(projection.GeoToScreen(it->get_location())); canvas.polygon(&pts[0], (unsigned)pts.size()); }
int main(int argc, char **argv) { Args args(argc, argv, "PATH"); const auto map_path = args.ExpectNext(); args.ExpectEnd(); ZZIP_DIR *dir = zzip_dir_open(map_path, nullptr); if (dir == nullptr) { fprintf(stderr, "Failed to open %s\n", map_path); return EXIT_FAILURE; } NullOperationEnvironment operation; RasterTileCache rtc; if (!LoadTerrainOverview(dir, rtc, operation)) { fprintf(stderr, "LoadOverview failed\n"); zzip_dir_close(dir); return EXIT_FAILURE; } GeoBounds bounds = rtc.GetBounds(); printf("bounds = %f|%f - %f|%f\n", (double)bounds.GetWest().Degrees(), (double)bounds.GetNorth().Degrees(), (double)bounds.GetEast().Degrees(), (double)bounds.GetSouth().Degrees()); SharedMutex mutex; do { UpdateTerrainTiles(dir, rtc, mutex, rtc.GetWidth() / 2, rtc.GetHeight() / 2, 1000); } while (rtc.IsDirty()); zzip_dir_close(dir); return EXIT_SUCCESS; }
const GeoBounds &GetBounds() const { assert(bounds.IsValid()); return bounds; }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const MapSettings &settings) { if (settings.trail_length == TRAIL_OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } fixed value_max, value_min; if (settings.snail_type == stAltitude) { value_max = fixed(1000); value_min = fixed(500); for (auto it = trace.begin(); it != trace.end(); ++it) { value_max = max(it->GetAltitude(), value_max); value_min = min(it->GetAltitude(), value_min); } } else { value_max = fixed(0.75); value_min = fixed(-2.0); for (auto it = trace.begin(); it != trace.end(); ++it) { value_max = max(it->GetVario(), value_max); value_min = min(it->GetVario(), value_min); } value_max = min(fixed(7.5), value_max); value_min = max(fixed(-5.0), value_min); } bool scaled_trail = settings.snail_scaling_enabled && projection.GetMapScale() <= fixed_int_constant(6000); const GeoBounds bounds = projection.GetScreenBounds().Scale(fixed_four); RasterPoint last_point; bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->get_location().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->get_location(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.snail_type == stAltitude) { unsigned index((it->GetAltitude() - value_min) / (value_max - value_min) * (TrailLook::NUMSNAILCOLORS - 1)); index = max(0u, min(TrailLook::NUMSNAILCOLORS - 1, index)); canvas.Select(look.hpSnail[index]); } else { const fixed colour_vario = negative(it->GetVario()) ? - it->GetVario() / value_min : it->GetVario() / value_max ; if (!scaled_trail) canvas.Select(look.hpSnail[GetSnailColorIndex(colour_vario)]); else canvas.Select(look.hpSnailVario[GetSnailColorIndex(colour_vario)]); } canvas.line_piece(last_point, pt); } last_point = pt; last_valid = true; } canvas.line(last_point, pos); }
bool IsValid() const { return bounds.IsValid(); }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const TrailSettings &settings) { if (settings.length == TrailSettings::Length::OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } fixed value_max, value_min; GetMinMax(value_min, value_max, settings.type, trace); bool scaled_trail = settings.scaling_enabled && projection.GetMapScale() <= fixed_int_constant(6000); const GeoBounds bounds = projection.GetScreenBounds().Scale(fixed_four); RasterPoint last_point; bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->GetLocation().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->GetLocation(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.type == TrailSettings::Type::ALTITUDE) { unsigned index((it->GetAltitude() - value_min) / (value_max - value_min) * (TrailLook::NUMSNAILCOLORS - 1)); index = max(0u, min(TrailLook::NUMSNAILCOLORS - 1, index)); canvas.Select(look.trail_pens[index]); canvas.DrawLinePiece(last_point, pt); } else { const fixed colour_vario = negative(it->GetVario()) ? - it->GetVario() / value_min : it->GetVario() / value_max ; unsigned color_index = GetSnailColorIndex(colour_vario); if (negative(it->GetVario()) && (settings.type == TrailSettings::Type::VARIO_1_DOTS || settings.type == TrailSettings::Type::VARIO_2_DOTS)) { canvas.SelectNullPen(); canvas.Select(look.trail_brushes[color_index]); canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else { if (!scaled_trail) canvas.Select(look.trail_pens[color_index]); else canvas.Select(look.scaled_trail_pens[color_index]); canvas.DrawLinePiece(last_point, pt); } } } last_point = pt; last_valid = true; } if (last_valid) canvas.DrawLine(last_point, pos); }
void TrailRenderer::Draw(Canvas &canvas, const TraceComputer &trace_computer, const WindowProjection &projection, unsigned min_time, bool enable_traildrift, const RasterPoint pos, const NMEAInfo &basic, const DerivedInfo &calculated, const TrailSettings &settings) { if (settings.length == TrailSettings::Length::OFF) return; if (!LoadTrace(trace_computer, min_time, projection)) return; if (!calculated.wind_available) enable_traildrift = false; GeoPoint traildrift; if (enable_traildrift) { GeoPoint tp1 = FindLatitudeLongitude(basic.location, calculated.wind.bearing, calculated.wind.norm); traildrift = basic.location - tp1; } auto minmax = GetMinMax(settings.type, trace); auto value_min = minmax.first; auto value_max = minmax.second; bool scaled_trail = settings.scaling_enabled && projection.GetMapScale() <= 6000; const GeoBounds bounds = projection.GetScreenBounds().Scale(4); RasterPoint last_point = RasterPoint(0, 0); bool last_valid = false; for (auto it = trace.begin(), end = trace.end(); it != end; ++it) { const GeoPoint gp = enable_traildrift ? it->GetLocation().Parametric(traildrift, it->CalculateDrift(basic.time)) : it->GetLocation(); if (!bounds.IsInside(gp)) { /* the point is outside of the MapWindow; don't paint it */ last_valid = false; continue; } RasterPoint pt = projection.GeoToScreen(gp); if (last_valid) { if (settings.type == TrailSettings::Type::ALTITUDE) { unsigned index = GetAltitudeColorIndex(it->GetAltitude(), value_min, value_max); canvas.Select(look.trail_pens[index]); canvas.DrawLinePiece(last_point, pt); } else { unsigned color_index = GetSnailColorIndex(it->GetVario(), value_min, value_max); if (it->GetVario() < 0 && (settings.type == TrailSettings::Type::VARIO_1_DOTS || settings.type == TrailSettings::Type::VARIO_2_DOTS || settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES)) { canvas.SelectNullPen(); canvas.Select(look.trail_brushes[color_index]); canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else { // positive vario case if (settings.type == TrailSettings::Type::VARIO_DOTS_AND_LINES) { canvas.Select(look.trail_brushes[color_index]); canvas.Select(look.trail_pens[color_index]); //fixed-width pen canvas.DrawCircle((pt.x + last_point.x) / 2, (pt.y + last_point.y) / 2, look.trail_widths[color_index]); } else if (scaled_trail) // width scaled to vario canvas.Select(look.scaled_trail_pens[color_index]); else // fixed-width pen canvas.Select(look.trail_pens[color_index]); canvas.DrawLinePiece(last_point, pt); } } } last_point = pt; last_valid = true; } if (last_valid) canvas.DrawLine(last_point, pos); }
/** * Convert a #GeoBounds instance to a boost::geometry box. */ gcc_const static boost::geometry::model::box<DoublePoint2D> ToBox(const GeoBounds b) { return {GeoTo2D(b.GetSouthWest()), GeoTo2D(b.GetNorthEast())}; }
void SetBounds(const GeoBounds &_bounds) { assert(_bounds.IsValid()); bounds = _bounds; }
bool TopographyFile::Update(const WindowProjection &map_projection) { if (IsEmpty()) return false; if (map_projection.GetMapScale() > scale_threshold) /* not visible, don't update cache now */ return false; const GeoBounds screenRect = map_projection.GetScreenBounds(); if (cache_bounds.IsValid() && cache_bounds.IsInside(screenRect)) /* the cache is still fresh */ return false; cache_bounds = screenRect.Scale(2); rectObj deg_bounds = ConvertRect(cache_bounds); // Test which shapes are inside the given bounds and save the // status to file.status switch (msShapefileWhichShapes(&file, dir, deg_bounds, 0)) { case MS_FAILURE: ClearCache(); return false; case MS_DONE: /* screen is outside of map bounds */ return false; case MS_SUCCESS: break; } assert(file.status != nullptr); // Iterate through the shapefile entries const ShapeList **current = &first; auto it = shapes.begin(); for (int i = 0; i < file.numshapes; ++i, ++it) { if (!msGetBit(file.status, i)) { // If the shape is outside the bounds // delete the shape from the cache if (it->shape != nullptr) { assert(*current == it); /* remove from linked list (protected) */ { const ScopeLock lock(mutex); *current = it->next; ++serial; } /* now it's unreachable, and we can delete the XShape without holding a lock */ delete it->shape; it->shape = nullptr; } } else { // is inside the bounds if (it->shape == nullptr) { assert(*current != it); // shape isn't cached yet -> cache the shape it->shape = LoadShape(&file, center, i, label_field); it->next = *current; /* insert into linked list (protected) */ { const ScopeLock lock(mutex); *current = it; ++serial; } } current = &it->next; } } // end of list marker assert(*current == nullptr); return true; }
void Invalidate() { bounds.SetInvalid(); }
int main(int argc, char **argv) { plan_tests(38); GeoPoint g(Angle::Degrees(2), Angle::Degrees(4)); GeoBounds b(g); ok1(equals(b.GetEast(), 2)); ok1(equals(b.GetWest(), 2)); ok1(equals(b.GetNorth(), 4)); ok1(equals(b.GetSouth(), 4)); ok1(b.IsEmpty()); g.latitude = Angle::Degrees(6); g.longitude = Angle::Degrees(8); b.Extend(g); ok1(equals(b.GetEast(), 8)); ok1(equals(b.GetWest(), 2)); ok1(equals(b.GetNorth(), 6)); ok1(equals(b.GetSouth(), 4)); ok1(!b.IsEmpty()); g = b.GetCenter(); ok1(equals(g.latitude, 5)); ok1(equals(g.longitude, 5)); ok1(b.IsInside(Angle::Degrees(7), Angle::Degrees(4.5))); ok1(!b.IsInside(Angle::Degrees(9), Angle::Degrees(4.5))); ok1(!b.IsInside(Angle::Degrees(7), Angle::Degrees(1))); ok1(!b.IsInside(Angle::Degrees(9), Angle::Degrees(1))); b = b.Scale(2); ok1(equals(b.GetEast(), 11)); ok1(equals(b.GetWest(), -1)); ok1(equals(b.GetNorth(), 7)); ok1(equals(b.GetSouth(), 3)); b = b.Scale(0.5); ok1(equals(b.GetEast(), 8)); ok1(equals(b.GetWest(), 2)); ok1(equals(b.GetNorth(), 6)); ok1(equals(b.GetSouth(), 4)); GeoBounds c = MakeGeoBounds(2, 6, 8, 4); ok1(c.Overlaps(b)); ok1(c.IntersectWith(b)); ok1(equals(c.GetWest(), 2)); ok1(equals(c.GetNorth(), 6)); ok1(equals(c.GetEast(), 8)); ok1(equals(c.GetSouth(), 4)); GeoBounds d = MakeGeoBounds(2, 6, 7, 5); ok1(c.Overlaps(d)); ok1(c.IntersectWith(d)); ok1(equals(c.GetWest(), 2)); ok1(equals(c.GetNorth(), 6)); ok1(equals(c.GetEast(), 7)); ok1(equals(c.GetSouth(), 5)); d = MakeGeoBounds(8, 6, 1, 5); ok1(!c.Overlaps(d)); ok1(!c.IntersectWith(d)); return exit_status(); }