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;
 
  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) {
 
  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;
 
  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;
 
  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;
 
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.
PlugIn Object Definition/API.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.