30#include <wx/progdlg.h>
40#include "GL/gl_private.h"
49double square(
double x) {
return x * x; }
52void ParamCache::Initialize(
double step) {
56 int size =
static_cast<int>(360 / step);
57 values =
new double[size];
63bool ParamCache::Read(
double lat,
double lon,
double &value) {
64 if (lat != m_lat)
return false;
66 if (lon > 360) lon -= 360;
67 if (lon < 0 || lon >= 360)
return false;
68 double div = lon / m_step;
69 if (div != floor(div))
return false;
71 value = values[(int)div];
76void MagneticPlotMap::ConfigureAccuracy(
int step,
int poleaccuracy) {
106 switch (poleaccuracy) {
108 m_PoleAccuracy = 5e-1;
111 m_PoleAccuracy = 1e-1;
114 m_PoleAccuracy = 1e-2;
117 m_PoleAccuracy = 1e-3;
120 m_PoleAccuracy = 1e-4;
126double MagneticPlotMap::CalcParameter(
double lat,
double lon) {
131 CoordGeodetic.lambda = lon;
132 CoordGeodetic.phi = lat;
133 CoordGeodetic.HeightAboveEllipsoid = 0;
134 CoordGeodetic.HeightAboveGeoid = 0;
135 CoordGeodetic.UseGeoid = 0;
139 MAG_GeodeticToSpherical(*Ellip, CoordGeodetic, &CoordSpherical);
142 MAG_Geomag(*Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel,
143 &GeoMagneticElements);
144 MAG_CalculateGridVariation(CoordGeodetic, &GeoMagneticElements);
148 case DECLINATION_PLOT:
149 ret = GeoMagneticElements.Decl >= 180 ? GeoMagneticElements.Decl - 360
150 : GeoMagneticElements.Decl;
152 case INCLINATION_PLOT:
153 ret = GeoMagneticElements.Incl;
155 case FIELD_STRENGTH_PLOT:
156 ret = GeoMagneticElements.F;
164void MagneticPlotMap::BuildParamCache(
ParamCache &cache,
double lat) {
166 for (
double lon = -180; lon < 180; lon += m_Step, i++)
167 cache.values[i] = CalcParameter(lat, lon);
174double MagneticPlotMap::CachedCalcParameter(
double lat,
double lon) {
176 if (!m_Cache[0].
Read(lat, lon, value) && !m_Cache[1].
Read(lat, lon, value))
177 value = CalcParameter(lat, lon);
187bool MagneticPlotMap::Interpolate(
double x1,
double x2,
double y1,
double y2,
188 bool lat,
double lonval,
double &rx,
190 if (fabs(x1 - x2) < m_PoleAccuracy) {
199 if (m_type == DECLINATION_PLOT) {
200 if (y1 - y2 > 180) y2 += 360;
201 if (y2 - y1 > 180) y1 += 360;
207 double fy1 = floor(y1), fy2 = floor(y2);
213 if (fabs(fy1 - fy2) >
228 for (
int i = 0;; i++) {
235 rx = (x1 * (y2 - ry) - x2 * (y1 - ry)) / (y2 - y1);
237 if (fabs(x1 - x2) < m_PoleAccuracy)
242 p = CalcParameter(rx, lonval);
244 p = CalcParameter(lonval, rx);
249 if (m_type == DECLINATION_PLOT &&
250 p - ry * m_Spacing < -180)
259 if (fabs(err) < 1e-3 || p == y1 || p == y2)
277void AddLineSeg(std::list<PlotLineSeg *> ®ion,
double lat1,
double lon1,
278 double lat2,
double lon2,
double contour1,
double contour2) {
279 if (contour1 != contour2)
282 auto *seg =
new PlotLineSeg(lat1, lon1, lat2, lon2, contour1);
283 region.push_back(seg);
298void MagneticPlotMap::PlotRegion(std::list<PlotLineSeg *> ®ion,
double lat1,
299 double lon1,
double lat2,
double lon2) {
300 double p1 = CachedCalcParameter(lat1, lon1);
301 double p2 = CachedCalcParameter(lat1, lon2);
302 double p3 = CachedCalcParameter(lat2, lon1);
303 double p4 = CachedCalcParameter(lat2, lon2);
305 if (std::isnan(p1) || std::isnan(p2) || std::isnan(p3) || std::isnan(p4))
308 double ry1, ry2, ry3, ry4 = 0.0;
309 double lon3, lon4, lat3, lat4 = 0.0;
312 if (!Interpolate(lon1, lon2, p1, p2,
false, lat1, lon3, ry1) ||
313 !Interpolate(lon1, lon2, p3, p4,
false, lat2, lon4, ry2)) {
314 lon3 = (lon1 + lon2) / 2;
315 PlotRegion(region, lat1, lon1, lat2, lon3);
316 PlotRegion(region, lat1, lon3, lat2, lon2);
321 if (!Interpolate(lat1, lat2, p1, p3,
true, lon1, lat3, ry3) ||
322 !Interpolate(lat1, lat2, p2, p4,
true, lon2, lat4, ry4)) {
323 lat3 = (lat1 + lat2) / 2;
324 PlotRegion(region, lat1, lon1, lat3, lon2);
325 PlotRegion(region, lat3, lon1, lat2, lon2);
330 ry1 *= m_Spacing, ry2 *= m_Spacing, ry3 *= m_Spacing, ry4 *= m_Spacing;
333 switch (((std::isnan(lat4) * 2 + std::isnan(lat3)) * 2 + std::isnan(lon4)) *
337 lon3 = (lon1 + lon2) / 2;
338 lat3 = (lat1 + lat2) / 2;
339 PlotRegion(region, lat1, lon1, lat3, lon3);
340 PlotRegion(region, lat1, lon3, lat3, lon2);
341 PlotRegion(region, lat3, lon1, lat2, lon3);
342 PlotRegion(region, lat3, lon3, lat2, lon2);
354 AddLineSeg(region, lat3, lon1, lat4, lon2, ry3, ry4);
357 AddLineSeg(region, lat2, lon4, lat4, lon2, ry2, ry4);
360 AddLineSeg(region, lat1, lon3, lat4, lon2, ry1, ry4);
363 AddLineSeg(region, lat3, lon1, lat2, lon4, ry2, ry3);
366 AddLineSeg(region, lat3, lon1, lat1, lon3, ry1, ry3);
369 AddLineSeg(region, lat1, lon3, lat2, lon4, ry1, ry2);
377bool MagneticPlotMap::Recompute(wxDateTime date) {
378 if (!m_bEnabled)
return true;
380 UserDate.Year = date.GetYear();
381 UserDate.Month = date.GetMonth();
382 UserDate.Day = date.GetDay();
385 MAG_DateToYear(&UserDate, err);
388 MAG_TimelyModifyMagneticModel(UserDate, MagneticModel, TimedMagneticModel);
393 wxGenericProgressDialog progressdialog(
394 _(
"Building Magnetic Map"),
395 m_type == DECLINATION_PLOT ? _(
"Variation")
396 : m_type == INCLINATION_PLOT ? _(
"Inclination")
397 : _(
"Field Strength"),
399 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
402 m_Cache[0].Initialize(m_Step);
403 m_Cache[1].Initialize(m_Step);
405 BuildParamCache(m_Cache[cachepage], -MAX_LAT);
407 for (
double lat = -MAX_LAT; lat + m_Step <= MAX_LAT; lat += m_Step) {
408 if (!progressdialog.Update(lat + 90)) {
412 cachepage = !cachepage;
413 BuildParamCache(m_Cache[cachepage], lat + m_Step);
415 int latind = floor((lat + MAX_LAT) / ZONE_SIZE);
416 if (latind > LATITUDE_ZONES - 1) latind = LATITUDE_ZONES - 1;
417 for (
double lon = -180; lon + m_Step <= 180; lon += m_Step) {
418 int lonind = floor((lon + 180) / ZONE_SIZE);
419 PlotRegion(m_map[latind][lonind], lat, lon, lat + m_Step, lon + m_Step);
428 double lat2,
double lon2) {
430 if (lon1 + 180 < VP.
clon && lon2 + 180 > VP.
clon)
return;
431 if (lon1 + 180 > VP.
clon && lon2 + 180 < VP.
clon)
return;
432 if (lon1 - 180 < VP.
clon && lon2 - 180 > VP.
clon)
return;
433 if (lon1 - 180 > VP.
clon && lon2 - 180 < VP.
clon)
return;
439 dc->DrawLine(r1.x, r1.y, r2.x, r2.y);
442 dc->DrawLine(r1.x, r1.y, r2.x, r2.y);
445 glVertex2i(r1.x, r1.y);
446 glVertex2i(r2.x, r2.y);
453void MagneticPlotMap::ClearMap() {
454 for (
int latind = 0; latind < LATITUDE_ZONES; latind++)
455 for (
int lonind = 0; lonind < LONGITUDE_ZONES; lonind++)
456 m_map[latind][lonind].clear();
461 double contour,
double lat,
double lon) {
466 double dist_squared = square(r.x - lastx) + square(r.y - lasty);
468 if (dist_squared < 40000)
return;
474 msg.Printf(
"%.0f", contour);
477 dc->GetTextExtent(msg, &w, &h);
478 dc->DrawText(msg, r.x - w / 2, r.y - h / 2);
482 dc->GetTextExtent( msg, &w, &h);
483 dc->DrawText(msg, r.x - w/2, r.y - h/2);
485 glEnable( GL_BLEND );
486 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
489 m_TexFont.GetTextExtent( msg, &w, &h);
491 glEnable(GL_TEXTURE_2D);
492 m_TexFont.RenderString(msg, r.x - w/2, r.y - h/2);
493 glDisable(GL_TEXTURE_2D);
502 if (!m_bEnabled)
return;
504 wxFont font(15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_ITALIC,
505 wxFONTWEIGHT_NORMAL);
507 dc->SetPen(wxPen(color, 3));
508 dc->SetTextForeground(color);
512 dc->SetPen(wxPen(color, 3));
513 dc->SetTextForeground(color);
517 glColor4ub(color.Red(), color.Green(), color.Blue(), color.Alpha());
518 m_TexFont.Build( font );
521 int startlatind = floor((vp->
lat_min + MAX_LAT) / ZONE_SIZE);
522 if (startlatind < 0) startlatind = 0;
524 int endlatind = floor((vp->
lat_max + MAX_LAT) / ZONE_SIZE);
525 if (endlatind > LATITUDE_ZONES - 1) endlatind = LATITUDE_ZONES - 1;
530 else if (lon_min >= 180)
532 int startlonind = floor((lon_min + 180) / ZONE_SIZE);
533 if (startlonind < 0) startlonind = LONGITUDE_ZONES - 1;
534 if (startlonind > LONGITUDE_ZONES - 1) startlonind = 0;
539 else if (lon_max >= 180)
541 int endlonind = floor((lon_max + 180) / ZONE_SIZE);
542 if (endlonind < 0) endlonind = LONGITUDE_ZONES - 1;
543 if (endlonind > LONGITUDE_ZONES - 1) endlonind = 0;
545 for (
int latind = startlatind; latind <= endlatind; latind++)
546 for (
int lonind = startlonind;; lonind++) {
547 if (lonind > LONGITUDE_ZONES - 1) lonind = 0;
548 for (
auto it = m_map[latind][lonind].begin();
549 it != m_map[latind][lonind].end(); it++) {
550 DrawLineSeg(dc, *vp, (*it)->lat1, (*it)->lon1, (*it)->lat2,
553 DrawContour(dc, *vp, (*it)->contour, ((*it)->lat1 + (*it)->lat2) / 2,
554 ((*it)->lon1 + (*it)->lon2) / 2);
556 if (lonind == endlonind)
break;
Contains view parameters and status information for a chart display viewport.
double lon_max
Maximum longitude of the viewport.
double clon
Center longitude of the viewport in decimal degrees.
double lat_max
Maximum latitude of the viewport.
double lon_min
Minimum longitude of the viewport.
double lat_min
Minimum latitude of the viewport.
NavmsgFilter Read(const std::string &name)
Read filter with given name from disk.
WMM plugin magnetic plotmap utility.
PlugIn Object Definition/API.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.
Graphics abstraction layer on top of wxDC or OpenGL.