34#include <wx/progdlg.h>
39#ifndef __OCPN__ANDROID__
44#include "GL/gl_private.h"
47#include "GeomagnetismHeader.h"
48#include "MagneticPlotMap.h"
53double square(
double x) {
return x * x; }
56void ParamCache::Initialize(
double step) {
60 int size = 360 / step;
61 values =
new double[size];
67bool ParamCache::Read(
double lat,
double lon,
double &value) {
68 if (lat != m_lat)
return false;
70 if (lon > 360) lon -= 360;
71 if (lon < 0 || lon >= 360)
return false;
72 double div = lon / m_step;
73 if (div != floor(div))
return false;
75 value = values[(int)div];
80void MagneticPlotMap::ConfigureAccuracy(
int step,
int poleaccuracy) {
110 switch (poleaccuracy) {
112 m_PoleAccuracy = 5e-1;
115 m_PoleAccuracy = 1e-1;
118 m_PoleAccuracy = 1e-2;
121 m_PoleAccuracy = 1e-3;
124 m_PoleAccuracy = 1e-4;
130double MagneticPlotMap::CalcParameter(
double lat,
double lon) {
135 CoordGeodetic.lambda = lon;
136 CoordGeodetic.phi = lat;
137 CoordGeodetic.HeightAboveEllipsoid = 0;
138 CoordGeodetic.HeightAboveGeoid = 0;
139 CoordGeodetic.UseGeoid = 0;
143 MAG_GeodeticToSpherical(*Ellip, CoordGeodetic, &CoordSpherical);
146 MAG_Geomag(*Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel,
147 &GeoMagneticElements);
148 MAG_CalculateGridVariation(CoordGeodetic, &GeoMagneticElements);
152 case DECLINATION_PLOT:
153 ret = GeoMagneticElements.Decl >= 180 ? GeoMagneticElements.Decl - 360
154 : GeoMagneticElements.Decl;
156 case INCLINATION_PLOT:
157 ret = GeoMagneticElements.Incl;
159 case FIELD_STRENGTH_PLOT:
160 ret = GeoMagneticElements.F;
168void MagneticPlotMap::BuildParamCache(
ParamCache &cache,
double lat) {
170 for (
double lon = -180; lon < 180; lon += m_Step, i++)
171 cache.values[i] = CalcParameter(lat, lon);
178double MagneticPlotMap::CachedCalcParameter(
double lat,
double lon) {
180 if (!m_Cache[0].Read(lat, lon, value) && !m_Cache[1].Read(lat, lon, value))
181 value = CalcParameter(lat, lon);
191bool MagneticPlotMap::Interpolate(
double x1,
double x2,
double y1,
double y2,
192 bool lat,
double lonval,
double &rx,
194 if (fabs(x1 - x2) < m_PoleAccuracy) {
203 if (m_type == DECLINATION_PLOT) {
204 if (y1 - y2 > 180) y2 += 360;
205 if (y2 - y1 > 180) y1 += 360;
211 double fy1 = floor(y1), fy2 = floor(y2);
217 if (fabs(fy1 - fy2) >
232 for (
int i = 0;; i++) {
239 rx = (x1 * (y2 - ry) - x2 * (y1 - ry)) / (y2 - y1);
241 if (fabs(x1 - x2) < m_PoleAccuracy)
246 p = CalcParameter(rx, lonval);
248 p = CalcParameter(lonval, rx);
253 if (m_type == DECLINATION_PLOT &&
254 p - ry * m_Spacing < -180)
263 if (fabs(err) < 1e-3 || p == y1 || p == y2)
281void AddLineSeg(std::list<PlotLineSeg *> ®ion,
double lat1,
double lon1,
282 double lat2,
double lon2,
double contour1,
double contour2) {
283 if (contour1 != contour2)
287 region.push_back(seg);
302void MagneticPlotMap::PlotRegion(std::list<PlotLineSeg *> ®ion,
double lat1,
303 double lon1,
double lat2,
double lon2) {
304 double p1 = CachedCalcParameter(lat1, lon1);
305 double p2 = CachedCalcParameter(lat1, lon2);
306 double p3 = CachedCalcParameter(lat2, lon1);
307 double p4 = CachedCalcParameter(lat2, lon2);
309 if (std::isnan(p1) || std::isnan(p2) || std::isnan(p3) || std::isnan(p4))
312 double ry1, ry2, ry3, ry4 = 0.0;
313 double lon3, lon4, lat3, lat4 = 0.0;
316 if (!Interpolate(lon1, lon2, p1, p2,
false, lat1, lon3, ry1) ||
317 !Interpolate(lon1, lon2, p3, p4,
false, lat2, lon4, ry2)) {
318 lon3 = (lon1 + lon2) / 2;
319 PlotRegion(region, lat1, lon1, lat2, lon3);
320 PlotRegion(region, lat1, lon3, lat2, lon2);
325 if (!Interpolate(lat1, lat2, p1, p3,
true, lon1, lat3, ry3) ||
326 !Interpolate(lat1, lat2, p2, p4,
true, lon2, lat4, ry4)) {
327 lat3 = (lat1 + lat2) / 2;
328 PlotRegion(region, lat1, lon1, lat3, lon2);
329 PlotRegion(region, lat3, lon1, lat2, lon2);
334 ry1 *= m_Spacing, ry2 *= m_Spacing, ry3 *= m_Spacing, ry4 *= m_Spacing;
337 switch (((std::isnan(lat4) * 2 + std::isnan(lat3)) * 2 + std::isnan(lon4)) *
341 lon3 = (lon1 + lon2) / 2;
342 lat3 = (lat1 + lat2) / 2;
343 PlotRegion(region, lat1, lon1, lat3, lon3);
344 PlotRegion(region, lat1, lon3, lat3, lon2);
345 PlotRegion(region, lat3, lon1, lat2, lon3);
346 PlotRegion(region, lat3, lon3, lat2, lon2);
358 AddLineSeg(region, lat3, lon1, lat4, lon2, ry3, ry4);
361 AddLineSeg(region, lat2, lon4, lat4, lon2, ry2, ry4);
364 AddLineSeg(region, lat1, lon3, lat4, lon2, ry1, ry4);
367 AddLineSeg(region, lat3, lon1, lat2, lon4, ry2, ry3);
370 AddLineSeg(region, lat3, lon1, lat1, lon3, ry1, ry3);
373 AddLineSeg(region, lat1, lon3, lat2, lon4, ry1, ry2);
381bool MagneticPlotMap::Recompute(wxDateTime date) {
382 if (!m_bEnabled)
return true;
384 UserDate.Year = date.GetYear();
385 UserDate.Month = date.GetMonth();
386 UserDate.Day = date.GetDay();
389 MAG_DateToYear(&UserDate, err);
392 MAG_TimelyModifyMagneticModel(UserDate, MagneticModel, TimedMagneticModel);
397 wxGenericProgressDialog progressdialog(
398 _(
"Building Magnetic Map"),
399 m_type == DECLINATION_PLOT ? _(
"Variation")
400 : m_type == INCLINATION_PLOT ? _(
"Inclination")
401 : _(
"Field Strength"),
403 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
406 m_Cache[0].Initialize(m_Step);
407 m_Cache[1].Initialize(m_Step);
409 BuildParamCache(m_Cache[cachepage], -MAX_LAT);
411 for (
double lat = -MAX_LAT; lat + m_Step <= MAX_LAT; lat += m_Step) {
412 if (!progressdialog.Update(lat + 90)) {
416 cachepage = !cachepage;
417 BuildParamCache(m_Cache[cachepage], lat + m_Step);
419 int latind = floor((lat + MAX_LAT) / ZONE_SIZE);
420 if (latind > LATITUDE_ZONES - 1) latind = LATITUDE_ZONES - 1;
421 for (
double lon = -180; lon + m_Step <= 180; lon += m_Step) {
422 int lonind = floor((lon + 180) / ZONE_SIZE);
423 PlotRegion(m_map[latind][lonind], lat, lon, lat + m_Step, lon + m_Step);
432 double lat2,
double lon2) {
434 if (lon1 + 180 < VP.clon && lon2 + 180 > VP.clon)
return;
435 if (lon1 + 180 > VP.clon && lon2 + 180 < VP.clon)
return;
436 if (lon1 - 180 < VP.clon && lon2 - 180 > VP.clon)
return;
437 if (lon1 - 180 > VP.clon && lon2 - 180 < VP.clon)
return;
440 GetCanvasPixLL(&VP, &r1, lat1, lon1);
441 GetCanvasPixLL(&VP, &r2, lat2, lon2);
443 dc->DrawLine(r1.x, r1.y, r2.x, r2.y);
446 dc->DrawLine(r1.x, r1.y, r2.x, r2.y);
449 glVertex2i(r1.x, r1.y);
450 glVertex2i(r2.x, r2.y);
457void MagneticPlotMap::ClearMap() {
458 for (
int latind = 0; latind < LATITUDE_ZONES; latind++)
459 for (
int lonind = 0; lonind < LONGITUDE_ZONES; lonind++)
460 m_map[latind][lonind].clear();
465 double contour,
double lat,
double lon) {
468 GetCanvasPixLL(&VP, &r, lat, lon);
470 double dist_squared = square(r.x - lastx) + square(r.y - lasty);
472 if (dist_squared < 40000)
return;
478 msg.Printf(_T(
"%.0f"), contour);
481 dc->GetTextExtent(msg, &w, &h);
482 dc->DrawText(msg, r.x - w / 2, r.y - h / 2);
486 dc->GetTextExtent( msg, &w, &h);
487 dc->DrawText(msg, r.x - w/2, r.y - h/2);
489 glEnable( GL_BLEND );
490 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
493 m_TexFont.GetTextExtent( msg, &w, &h);
495 glEnable(GL_TEXTURE_2D);
496 m_TexFont.RenderString(msg, r.x - w/2, r.y - h/2);
497 glDisable(GL_TEXTURE_2D);
506 if (!m_bEnabled)
return;
508 wxFont font(15, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_ITALIC,
509 wxFONTWEIGHT_NORMAL);
511 dc->SetPen(wxPen(color, 3));
512 dc->SetTextForeground(color);
516 dc->SetPen(wxPen(color, 3));
517 dc->SetTextForeground(color);
521 glColor4ub(color.Red(), color.Green(), color.Blue(), color.Alpha());
522 m_TexFont.Build( font );
525 int startlatind = floor((vp->lat_min + MAX_LAT) / ZONE_SIZE);
526 if (startlatind < 0) startlatind = 0;
528 int endlatind = floor((vp->lat_max + MAX_LAT) / ZONE_SIZE);
529 if (endlatind > LATITUDE_ZONES - 1) endlatind = LATITUDE_ZONES - 1;
531 double lon_min = vp->lon_min;
534 else if (lon_min >= 180)
536 int startlonind = floor((lon_min + 180) / ZONE_SIZE);
537 if (startlonind < 0) startlonind = LONGITUDE_ZONES - 1;
538 if (startlonind > LONGITUDE_ZONES - 1) startlonind = 0;
540 double lon_max = vp->lon_max;
543 else if (lon_max >= 180)
545 int endlonind = floor((lon_max + 180) / ZONE_SIZE);
546 if (endlonind < 0) endlonind = LONGITUDE_ZONES - 1;
547 if (endlonind > LONGITUDE_ZONES - 1) endlonind = 0;
549 for (
int latind = startlatind; latind <= endlatind; latind++)
550 for (
int lonind = startlonind;; lonind++) {
551 if (lonind > LONGITUDE_ZONES - 1) lonind = 0;
552 for (std::list<PlotLineSeg *>::iterator it =
553 m_map[latind][lonind].begin();
554 it != m_map[latind][lonind].end(); it++) {
555 DrawLineSeg(dc, *vp, (*it)->lat1, (*it)->lon1, (*it)->lat2,
558 DrawContour(dc, *vp, (*it)->contour, ((*it)->lat1 + (*it)->lat2) / 2,
559 ((*it)->lon1 + (*it)->lon2) / 2);
561 if (lonind == endlonind)
break;
PlugIn Object Definition/API.