1 /******************************************************************************
2 * $Id: wmm_pi.cpp,v 1.0 2011/02/26 01:54:37 nohal Exp $
3 *
4 * Project: OpenCPN
5 * Purpose: WMM Plugin
6 * Author: Pavel Kalian
7 *
8 ***************************************************************************
9 * Copyright (C) 2011-2019 by Pavel Kalian *
10 * $EMAIL$ *
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program; if not, write to the *
24 * Free Software Foundation, Inc., *
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
26 ***************************************************************************
27 */
28
29
30 #include "wx/wxprec.h"
31
32 #ifndef WX_PRECOMP
33 #include "wx/wx.h"
34 #endif //precompiled headers
35
36 #ifndef __OCPN__ANDROID__
37 #include <GL/gl.h>
38 #include <GL/glu.h>
39 #else
40 #include "qopengl.h" // this gives us the qt runtime gles2.h
41 #include "GL/gl_private.h"
42 #include "qdebug.h"
43 #endif
44
45 float g_piGLMinSymbolLineWidth;
46
WMMLogMessage1(wxString s)47 void WMMLogMessage1(wxString s) { wxLogMessage(_T("WMM: ") + s); }
WMMLogMessage(const char * s)48 extern "C" void WMMLogMessage(const char *s) { WMMLogMessage1(wxString::FromAscii(s)); }
49
50 #include "wmm_pi.h"
51
52 // the class factories, used to create and destroy instances of the PlugIn
53
create_pi(void * ppimgr)54 extern "C" DECL_EXP opencpn_plugin* create_pi(void *ppimgr)
55 {
56 return new wmm_pi(ppimgr);
57 }
58
destroy_pi(opencpn_plugin * p)59 extern "C" DECL_EXP void destroy_pi(opencpn_plugin* p)
60 {
61 delete p;
62 }
63
64 wmm_pi *g_pi;
65
66 bool g_compact;
67
68 //---------------------------------------------------------------------------------------------------------
69 //
70 // WMM PlugIn Implementation
71 //
72 //---------------------------------------------------------------------------------------------------------
73
74 #include "icons.h"
75
EnablePlotChanged(wxCommandEvent & event)76 void WmmUIDialog::EnablePlotChanged( wxCommandEvent& event )
77 {
78 if(m_cbEnablePlot->GetValue())
79 m_wmm_pi.RecomputePlot();
80 m_wmm_pi.SetShowPlot(m_cbEnablePlot->GetValue());
81 RequestRefresh( m_wmm_pi.m_parent_window );
82 }
83
PlotSettings(wxCommandEvent & event)84 void WmmUIDialog::PlotSettings( wxCommandEvent& event )
85 {
86 m_wmm_pi.ShowPlotSettings();
87 }
88
About(wxCommandEvent & event)89 void WmmPlotSettingsDialog::About( wxCommandEvent& event )
90 {
91 wxString msg0(
92 _("\n\
93 World Magnetic Model Plotting allows users to cross reference the\
94 magnetic variation values printed on many raster charts.\n\n\
95 Variation is the angle between true and magnetic north.\n\
96 Inclination or dip, is the vertical angle of the magnetic field.\n\
97 \t(+- 90 at the magnetic poles)\n\
98 Field Strength is the magnetic field in nano tesla from\n\
99 \t20000 to 66000\n\n\
100 The plotted lines are similar to a topographic map. The \
101 space between them can be adjusted; more space takes \
102 less time to calculate.\n\n\
103 The Step size and Pole accuracy sliders allow a trade off \
104 for speed vs computation time.\n\n\
105 The World Magnetic Model Plugin was written by Pavel Kalian \
106 and extended by Sean D'Epagnier to support plotting."));
107
108 wxMessageDialog dlg( this, msg0, _("WMM Plugin"), wxOK );
109
110 dlg.ShowModal();
111 }
112
113 //---------------------------------------------------------------------------------------------------------
114 //
115 // PlugIn initialization and de-init
116 //
117 //---------------------------------------------------------------------------------------------------------
118
wmm_pi(void * ppimgr)119 wmm_pi::wmm_pi(void *ppimgr)
120 : opencpn_plugin_18(ppimgr),
121 m_bShowPlot(false),
122 m_DeclinationMap(DECLINATION_PLOT, MagneticModel, TimedMagneticModel, &Ellip),
123 m_InclinationMap(INCLINATION_PLOT, MagneticModel, TimedMagneticModel, &Ellip),
124 m_FieldStrengthMap(FIELD_STRENGTH_PLOT, MagneticModel, TimedMagneticModel, &Ellip),
125 m_bComputingPlot(false)
126 {
127 // Create the PlugIn icons
128 initialize_images();
129
130 g_pi = this;
131 }
132
Init(void)133 int wmm_pi::Init(void)
134 {
135 AddLocaleCatalog( PLUGIN_CATALOG_NAME );
136
137 // Set some default private member parameters
138 m_wmm_dialog_x = 0;
139 m_wmm_dialog_y = 0;
140
141 MagneticModel = NULL;
142 TimedMagneticModel = NULL;
143
144 ::wxDisplaySize(&m_display_width, &m_display_height);
145
146 // Get a pointer to the opencpn display canvas, to use as a parent for the POI Manager dialog
147 m_parent_window = GetOCPNCanvasWindow();
148
149 // Get a pointer to the opencpn configuration object
150 m_pconfig = GetOCPNConfigObject();
151
152 // And load the configuration items
153 LoadConfig();
154
155 #ifdef __OCPN__ANDROID__
156 g_compact = true;
157 m_bShowPlotOptions = false;
158 m_iViewType = 1;
159 #endif
160
161
162 m_buseable = true;
163
164 m_LastVal = wxEmptyString;
165
166 //pFontSmall = new wxFont( 10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD );
167 pFontSmall = OCPNGetFont( _("WMM_Live_Overlay"), 10);
168
169 m_shareLocn =*GetpSharedDataLocation() +
170 _T("plugins") + wxFileName::GetPathSeparator() +
171 _T("wmm_pi") + wxFileName::GetPathSeparator() +
172 _T("data") + wxFileName::GetPathSeparator();
173
174 // WMM initialization
175
176 /* Memory allocation */
177 int NumTerms, epochs = 1, nMax = 0;
178 wxString cof_filename = m_shareLocn + "WMM.COF";
179
180 if(!MAG_robustReadMagModels(const_cast<char*>((const char*)cof_filename.mb_str()), &MagneticModels)) {
181 WMMLogMessage1(_T("initialization error"));
182 m_buseable = false;
183 } else {
184 WMMLogMessage1(wxString::Format(_T("WMM model data loaded from file %s."), cof_filename.c_str()));
185 for(int i = 0; i < epochs; i++) {
186 if(MagneticModels[i]->nMax > nMax) {
187 nMax = MagneticModels[i]->nMax;
188 }
189 }
190 NumTerms = ((nMax + 1) * (nMax + 2) / 2);
191
192 TimedMagneticModel = MAG_AllocateModelMemory(NumTerms); /* For storing the time modified WMM Model parameters */
193
194 for(int i = 0; i < epochs; i++) {
195 if(MagneticModels[i] == NULL || TimedMagneticModel == NULL) {
196 WMMLogMessage1(_T("initialization error MAG_Error(2)"));
197 m_buseable = false;
198 }
199 }
200
201 MagneticModel = MagneticModels[0];
202
203 MAG_SetDefaults(&Ellip, &Geoid); /* Set default values and constants */
204 /* Check for Geographic Poles */
205
206 /* Set EGM96 Geoid parameters */
207 Geoid.GeoidHeightBuffer = GeoidHeightBuffer;
208 Geoid.Geoid_Initialized = 1;
209 /* Set EGM96 Geoid parameters END */
210 }
211
212 int ret_flag = (WANTS_OVERLAY_CALLBACK |
213 WANTS_OPENGL_OVERLAY_CALLBACK |
214 WANTS_CURSOR_LATLON |
215 WANTS_TOOLBAR_CALLBACK |
216 WANTS_NMEA_EVENTS |
217 WANTS_PREFERENCES |
218 WANTS_CONFIG |
219 WANTS_PLUGIN_MESSAGING
220 );
221
222 if(m_bShowIcon){
223 // This PlugIn needs a toolbar icon, so request its insertion
224 m_leftclick_tool_id = InsertPlugInTool(_T(""), _img_wmm, _img_wmm, wxITEM_NORMAL,
225 _("WMM"), _T(""), NULL, WMM_TOOL_POSITION, 0, this);
226
227 SetIconType(); // SVGs allowed if not showing live icon
228
229 ret_flag |= INSTALLS_TOOLBAR_TOOL;
230 }
231
232 m_pWmmDialog = NULL;
233 m_oDC = NULL;
234
235 #ifdef ocpnUSE_GL
236 // Set the minimum line width
237 GLint parms[2];
238 #ifndef USE_ANDROID_GLES2
239 glGetIntegerv( GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0] );
240 #else
241 glGetIntegerv( GL_ALIASED_LINE_WIDTH_RANGE, &parms[0] );
242 #endif
243 g_piGLMinSymbolLineWidth = wxMax(parms[0], 1);
244 #endif
245
246 return ret_flag;
247 }
248
DeInit(void)249 bool wmm_pi::DeInit(void)
250 {
251 // Record the dialog position
252 if (NULL != m_pWmmDialog)
253 {
254 wxPoint p = m_pWmmDialog->GetPosition();
255 SetWmmDialogX(p.x);
256 SetWmmDialogY(p.y);
257
258 m_pWmmDialog->Close();
259 delete m_pWmmDialog;
260 m_pWmmDialog = NULL;
261 }
262 SaveConfig();
263 if(MagneticModel) {
264 MAG_FreeMagneticModelMemory(MagneticModel);
265 }
266 if(TimedMagneticModel) {
267 MAG_FreeMagneticModelMemory(TimedMagneticModel);
268 }
269
270 RemovePlugInTool(m_leftclick_tool_id);
271
272 /*if (Geoid.GeoidHeightBuffer)
273 {
274 free(Geoid.GeoidHeightBuffer);
275 Geoid.GeoidHeightBuffer = NULL;
276 }*/
277
278 //delete pFontSmall;
279
280 if(m_oDC)
281 delete m_oDC;
282
283 return true;
284 }
285
GetAPIVersionMajor()286 int wmm_pi::GetAPIVersionMajor()
287 {
288 return MY_API_VERSION_MAJOR;
289 }
290
GetAPIVersionMinor()291 int wmm_pi::GetAPIVersionMinor()
292 {
293 return MY_API_VERSION_MINOR;
294 }
295
GetPlugInVersionMajor()296 int wmm_pi::GetPlugInVersionMajor()
297 {
298 return PLUGIN_VERSION_MAJOR;
299 }
300
GetPlugInVersionMinor()301 int wmm_pi::GetPlugInVersionMinor()
302 {
303 return PLUGIN_VERSION_MINOR;
304 }
305
GetPlugInBitmap()306 wxBitmap *wmm_pi::GetPlugInBitmap()
307 {
308 return _img_wmm_pi;
309 }
310
GetCommonName()311 wxString wmm_pi::GetCommonName()
312 {
313 return _("WMM");
314 }
315
316
GetShortDescription()317 wxString wmm_pi::GetShortDescription()
318 {
319 return _("World Magnetic Model PlugIn for OpenCPN");
320 }
321
GetLongDescription()322 wxString wmm_pi::GetLongDescription()
323 {
324 return _("World Magnetic Model PlugIn for OpenCPN\n\
325 Implements the NOAA World Magnetic Model\n\
326 More information:\n\
327 https://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml\n\
328 The bundled WMM2020 model expires on December 31, 2025.\n\
329 After then, if new version of the plugin will not be released\n\
330 in time, get a new WMM.COF from NOAA and place it to the\n\
331 location you can find in the OpenCPN logfile.");
332 }
333
334
GetToolbarToolCount(void)335 int wmm_pi::GetToolbarToolCount(void)
336 {
337 return 1;
338 }
339
SetColorScheme(PI_ColorScheme cs)340 void wmm_pi::SetColorScheme(PI_ColorScheme cs)
341 {
342 if (NULL == m_pWmmDialog)
343 return;
344 DimeWindow(m_pWmmDialog);
345 }
346
SetIconType()347 void wmm_pi::SetIconType()
348 {
349 if(m_bShowLiveIcon){
350 SetToolbarToolBitmaps(m_leftclick_tool_id, _img_wmm, _img_wmm);
351 SetToolbarToolBitmapsSVG(m_leftclick_tool_id, _T(""), _T(""), _T(""));
352 m_LastVal.Empty();
353 }
354 else{
355 wxString normalIcon = m_shareLocn + _T("wmm_pi.svg");
356 wxString toggledIcon = m_shareLocn + _T("wmm_pi.svg");
357 wxString rolloverIcon = m_shareLocn + _T("wmm_pi.svg");
358
359 SetToolbarToolBitmapsSVG(m_leftclick_tool_id, normalIcon, rolloverIcon, toggledIcon);
360 }
361
362 }
363
364
RearrangeWindow()365 void wmm_pi::RearrangeWindow()
366 {
367 if (NULL == m_pWmmDialog)
368 return;
369 if (m_iViewType == 1)
370 {
371 m_pWmmDialog->sbScursor->Hide(m_pWmmDialog->gScursor, true);
372 m_pWmmDialog->sbSboat->Hide(m_pWmmDialog->gSboat, true);
373 }
374 else
375 {
376 m_pWmmDialog->sbScursor->Show(m_pWmmDialog->gScursor, true, true);
377 m_pWmmDialog->sbSboat->Show(m_pWmmDialog->gSboat, true, true);
378 }
379
380 m_pWmmDialog->m_cbEnablePlot->Show(m_bShowPlotOptions);
381 m_pWmmDialog->m_bPlotSettings->Show(m_bShowPlotOptions);
382
383 if (!m_bShowAtCursor)
384 {
385 m_pWmmDialog->bSframe->Hide(m_pWmmDialog->sbScursor, true);
386 }
387 else
388 {
389 m_pWmmDialog->bSframe->Show(m_pWmmDialog->sbScursor, true, true);
390 if (m_iViewType == 1)
391 m_pWmmDialog->sbScursor->Hide(m_pWmmDialog->gScursor, true);
392 }
393
394 SetColorScheme(PI_ColorScheme());
395
396 m_pWmmDialog->Fit();
397
398 #ifdef __WXMSW__
399 //UGLY!!!!!!! On Windows XP the transparent window is not refreshed properly in OpenGL mode at least on the Atom powered netbooks, so we have to disable transparency.
400 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
401 bool gl = true;
402 if(pConf)
403 {
404 pConf->SetPath(_T("/Settings"));
405 pConf->Read(_T("OpenGL"), &gl, false);
406 pConf = NULL;
407 }
408 if (!(gl && wxPlatformInfo::Get().GetOSMajorVersion() == 5 && wxPlatformInfo::Get().GetOSMinorVersion() == 1))
409 #endif
410 if (m_pWmmDialog->CanSetTransparent())
411 m_pWmmDialog->SetTransparent(m_iOpacity);
412 }
413
OnToolbarToolCallback(int id)414 void wmm_pi::OnToolbarToolCallback(int id)
415 {
416 if( !m_buseable )
417 return;
418 if(NULL == m_pWmmDialog)
419 {
420 m_pWmmDialog = new WmmUIDialog(*this, m_parent_window);
421 wxFont *pFont = OCPNGetFont(_T("Dialog"), 0);
422 m_pWmmDialog->SetFont(*pFont);
423
424 m_pWmmDialog->Move(wxPoint(m_wmm_dialog_x, m_wmm_dialog_y));
425 }
426
427 RearrangeWindow();
428 /*m_pWmmDialog->SetMaxSize(m_pWmmDialog->GetSize());
429 m_pWmmDialog->SetMinSize(m_pWmmDialog->GetSize());*/
430 m_pWmmDialog->Show(!m_pWmmDialog->IsShown());
431 m_pWmmDialog->Layout(); // Some platforms need a re-Layout at this point (gtk, at least)
432 if (m_pWmmDialog->IsShown())
433 SendPluginMessage(_T("WMM_WINDOW_SHOWN"), wxEmptyString);
434 else
435 SendPluginMessage(_T("WMM_WINDOW_HIDDEN"), wxEmptyString);
436
437 wxPoint p = m_pWmmDialog->GetPosition();
438 m_pWmmDialog->Move(0,0); // workaround for gtk autocentre dialog behavior
439 m_pWmmDialog->Move(p);
440
441 #ifdef __OCPN__ANDROID__
442 m_pWmmDialog->CentreOnScreen();
443 m_pWmmDialog->Move(-1,0);
444 #endif
445
446 }
447
RenderOverlayBoth(pi_ocpnDC * dc,PlugIn_ViewPort * vp)448 void wmm_pi::RenderOverlayBoth(pi_ocpnDC *dc, PlugIn_ViewPort *vp)
449 {
450 if(!m_bShowPlot)
451 return;
452
453 m_DeclinationMap.Plot(dc, vp, wxColour(255, 0, 90, 220));
454 m_InclinationMap.Plot(dc, vp, wxColour(60, 255, 30, 220));
455 m_FieldStrengthMap.Plot(dc, vp, wxColour(0, 60, 255, 220));
456 }
457
RenderOverlay(wxDC & dc,PlugIn_ViewPort * vp)458 bool wmm_pi::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp)
459 {
460 if(!m_bShowPlot)
461 return true;
462
463 if(!m_oDC)
464 m_oDC = new pi_ocpnDC();
465
466 m_oDC->SetVP(vp);
467 m_oDC->SetDC(&dc);
468
469 RenderOverlayBoth(m_oDC, vp);
470
471 return true;
472 }
473
RenderGLOverlay(wxGLContext * pcontext,PlugIn_ViewPort * vp)474 bool wmm_pi::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp)
475 {
476 if(!m_bShowPlot)
477 return true;
478
479 if(!m_oDC)
480 m_oDC = new pi_ocpnDC();
481
482 m_oDC->SetVP(vp);
483 m_oDC->SetDC(NULL);
484
485 #ifndef USE_ANDROID_GLES2
486 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_HINT_BIT );
487
488 glEnable( GL_LINE_SMOOTH );
489 glEnable( GL_BLEND );
490 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
491 glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
492 #endif
493
494 RenderOverlayBoth(m_oDC, vp);
495
496 #ifndef USE_ANDROID_GLES2
497 glPopAttrib();
498 #endif
499
500 return true;
501 }
502
RecomputePlot()503 void wmm_pi::RecomputePlot()
504 {
505 if(m_bCachedPlotOk)
506 return;
507
508 if(m_bComputingPlot)
509 return;
510 m_bComputingPlot = true;
511
512 if(!m_DeclinationMap.Recompute(m_MapDate) ||
513 !m_InclinationMap.Recompute(m_MapDate) ||
514 !m_FieldStrengthMap.Recompute(m_MapDate)) {
515 m_bShowPlot = false;
516 if(m_pWmmDialog)
517 m_pWmmDialog->m_cbEnablePlot->SetValue(false);
518 } else
519 m_bCachedPlotOk = true;
520
521 m_bComputingPlot = false;
522 }
523
SetCursorLatLon(double lat,double lon)524 void wmm_pi::SetCursorLatLon(double lat, double lon)
525 {
526 if(!m_pWmmDialog)
527 return;
528
529 if (!m_bShowAtCursor)
530 return; //We don't want to waste CPU cycles that much...
531 if (lat < -90 || lat > 90 || lon < -180 || lon > 180 || NULL == m_pWmmDialog || !m_pWmmDialog->IsShown())
532 return;
533 if (!m_buseable)
534 {
535 m_pWmmDialog->m_tbD->SetValue(_("Error, see log."));
536 return;
537 }
538 CoordGeodetic.lambda = lon;
539 CoordGeodetic.phi = lat;
540 CoordGeodetic.HeightAboveEllipsoid = 0;
541 CoordGeodetic.HeightAboveGeoid = 0;
542 CoordGeodetic.UseGeoid = 0;
543 UserDate.Year = wxDateTime::GetCurrentYear();
544 UserDate.Month = wxDateTime::GetCurrentMonth() + 1; //WHY is it 0 based????????
545 UserDate.Day = wxDateTime::Now().GetDay();
546 char err[255];
547 MAG_DateToYear(&UserDate, err);
548 MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18, WMM Technical report*/
549 MAG_TimelyModifyMagneticModel(UserDate, MagneticModel, TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM Technical report */
550 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel, &GeoMagneticElements); /* Computes the geoMagnetic field elements and their time change*/
551 MAG_CalculateGridVariation(CoordGeodetic,&GeoMagneticElements);
552 //WMM_PrintUserData(GeoMagneticElements,CoordGeodetic, UserDate, TimedMagneticModel, &Geoid); /* Print the results */
553 m_pWmmDialog->m_tcF->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.F));
554 m_pWmmDialog->m_tcH->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.H));
555 m_pWmmDialog->m_tcX->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.X));
556 m_pWmmDialog->m_tcY->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.Y));
557 m_pWmmDialog->m_tcZ->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.Z));
558 m_pWmmDialog->m_tcD->SetValue(wxString::Format(_T("%-5.1lf\u00B0 (%s)"), GeoMagneticElements.Decl, AngleToText(GeoMagneticElements.Decl).c_str()));
559 m_pWmmDialog->m_tcI->SetValue(wxString::Format(_T("%-5.1lf\u00B0"), GeoMagneticElements.Incl));
560
561 m_cursorVariation = GeoMagneticElements;
562 SendCursorVariation();
563 }
564
SetPositionFix(PlugIn_Position_Fix & pfix)565 void wmm_pi::SetPositionFix(PlugIn_Position_Fix &pfix)
566 {
567 if(!m_buseable) {
568 return;
569 }
570 CoordGeodetic.lambda = pfix.Lon;
571 CoordGeodetic.phi = pfix.Lat;
572 CoordGeodetic.HeightAboveEllipsoid = 0;
573 CoordGeodetic.UseGeoid = 0;
574 UserDate.Year = wxDateTime::GetCurrentYear();
575 UserDate.Month = wxDateTime::GetCurrentMonth() + 1; //WHY is it 0 based????????
576 UserDate.Day = wxDateTime::Now().GetDay();
577 char err[255];
578 MAG_DateToYear(&UserDate, err);
579 MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18, WMM Technical report*/
580 MAG_TimelyModifyMagneticModel(UserDate, MagneticModel, TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM Technical report */
581 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel, &GeoMagneticElements); /* Computes the geoMagnetic field elements and their time change*/
582 MAG_CalculateGridVariation(CoordGeodetic,&GeoMagneticElements);
583 //WMM_PrintUserData(GeoMagneticElements,CoordGeodetic, UserDate, TimedMagneticModel, &Geoid); /* Print the results */
584
585 m_boatVariation = GeoMagneticElements;
586 SendBoatVariation();
587
588 wxString NewVal = wxString::Format(_T("%.1f"), GeoMagneticElements.Decl);
589 double scale = GetOCPNGUIToolScaleFactor_PlugIn();
590 scale = wxRound(scale * 4.0) / 4.0;
591 scale = wxMax(1.0, scale); // Let the upstream processing handle minification.
592
593 if( m_bShowIcon && m_bShowLiveIcon && ((m_LastVal != NewVal) || (scale != m_scale)) )
594 {
595 m_scale = scale;
596 m_LastVal = NewVal;
597 int w = _img_wmm_live->GetWidth() * scale;
598 int h = _img_wmm_live->GetHeight() * scale;
599 wxMemoryDC dc;
600 wxBitmap icon;
601
602 // Is SVG available?
603 wxBitmap live = GetBitmapFromSVGFile(m_shareLocn + _T("wmm_live.svg"), w, h);
604 if( ! live.IsOk() ){
605 icon = wxBitmap(_img_wmm_live->GetWidth(), _img_wmm_live->GetHeight());
606 dc.SelectObject(icon);
607 dc.DrawBitmap(*_img_wmm_live, 0, 0, true);
608 }
609 else{
610 icon = wxBitmap(w, h);
611 dc.SelectObject(icon);
612 wxColour col;
613 dc.SetBackground( *wxTRANSPARENT_BRUSH );
614 dc.Clear();
615
616 dc.DrawBitmap(live, 0, 0, true);
617 }
618
619 wxColour cf;
620 GetGlobalColor(_T("CHWHT"), &cf);
621 dc.SetTextForeground(cf);
622 if(pFontSmall->IsOk()){
623 if(live.IsOk()){
624 int point_size = wxMax(10, 10 * scale);
625 pFontSmall->SetPointSize(point_size);
626
627 // Validate and adjust the font size...
628 // No smaller than 8 pt.
629 int w;
630 wxScreenDC sdc;
631 sdc.GetTextExtent(NewVal, &w, NULL, NULL, NULL, pFontSmall);
632
633 while( (w > (icon.GetWidth() * 8 / 10) ) && (point_size >= 8) ){
634 point_size--;
635 pFontSmall->SetPointSize(point_size);
636 sdc.GetTextExtent(NewVal, &w, NULL, NULL, NULL, pFontSmall);
637 }
638 }
639 dc.SetFont(*pFontSmall);
640 }
641 wxSize s = dc.GetTextExtent(NewVal);
642 dc.DrawText(NewVal, (icon.GetWidth() - s.GetWidth()) / 2, (icon.GetHeight() - s.GetHeight()) / 2);
643 dc.SelectObject(wxNullBitmap);
644
645 if(live.IsOk()){
646 // By using a DC to modify the bitmap, we have lost the original bitmap's alpha channel
647 // Recover it by copying from the original to the target, bit by bit
648 wxImage imo = live.ConvertToImage();
649 wxImage im = icon.ConvertToImage();
650
651 if(!imo.HasAlpha())
652 imo.InitAlpha();
653 if(!im.HasAlpha())
654 im.InitAlpha();
655
656 unsigned char *alive = imo.GetAlpha();
657 unsigned char *target = im.GetAlpha();
658
659 for(int i=0 ; i < h ; i ++){
660 for(int j=0 ; j < w ; j++){
661 int index = (i * w) + j;
662 target[index] = alive[index];
663 }
664 }
665 icon = wxBitmap(im);
666 }
667
668 SetToolbarToolBitmaps(m_leftclick_tool_id, &icon, &icon);
669 }
670
671 if (NULL == m_pWmmDialog || !m_pWmmDialog->IsShown())
672 return;
673 if (!m_buseable)
674 {
675 m_pWmmDialog->m_tbD->SetValue(_("Error, see log."));
676 return;
677 }
678 m_pWmmDialog->m_tbF->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.F));
679 m_pWmmDialog->m_tbH->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.H));
680 m_pWmmDialog->m_tbX->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.X));
681 m_pWmmDialog->m_tbY->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.Y));
682 m_pWmmDialog->m_tbZ->SetValue(wxString::Format(_T("%-9.1lf nT"), GeoMagneticElements.Z));
683 m_pWmmDialog->m_tbD->SetValue(wxString::Format(_T("%-5.1lf\u00B0 (%s)"), GeoMagneticElements.Decl, AngleToText(GeoMagneticElements.Decl).c_str()));
684 m_pWmmDialog->m_tbI->SetValue(wxString::Format(_T("%-5.1lf\u00B0"), GeoMagneticElements.Incl));
685 }
686
687 //Demo implementation of response mechanism
SetPluginMessage(wxString & message_id,wxString & message_body)688 void wmm_pi::SetPluginMessage(wxString &message_id, wxString &message_body)
689 {
690 if(message_id == _T("WMM_VARIATION_REQUEST"))
691 {
692 wxJSONReader r;
693 wxJSONValue v;
694 r.Parse(message_body, &v);
695 double lat = v[_T("Lat")].AsDouble();
696 double lon = v[_T("Lon")].AsDouble();
697 int year = v[_T("Year")].AsInt();
698 int month = v[_T("Month")].AsInt();
699 int day = v[_T("Day")].AsInt();
700 SendVariationAt(lat, lon, year, month, day);
701 }
702 else if(message_id == _T("WMM_VARIATION_BOAT_REQUEST"))
703 {
704 SendBoatVariation();
705 }
706 else if(message_id == _T("WMM_VARIATION_CURSOR_REQUEST"))
707 {
708 SendCursorVariation();
709 }
710 }
711
SendVariationAt(double lat,double lon,int year,int month,int day)712 void wmm_pi::SendVariationAt(double lat, double lon, int year, int month, int day)
713 {
714 wxJSONValue v;
715 v[_T("Lat")] = lat;
716 v[_T("Lon")] = lon;
717 v[_T("Year")] = year;
718 v[_T("Month")] = month;
719 v[_T("Day")] = day;
720 CoordGeodetic.lambda = lon;
721 CoordGeodetic.phi = lat;
722 CoordGeodetic.HeightAboveEllipsoid = 0;
723 CoordGeodetic.UseGeoid = 0;
724 UserDate.Year = year;
725 UserDate.Month = month;
726 UserDate.Day = day;
727 char err[255];
728 MAG_DateToYear(&UserDate, err);
729 MAG_GeodeticToSpherical(Ellip, CoordGeodetic, &CoordSpherical); /*Convert from geodeitic to Spherical Equations: 17-18, WMM Technical report*/
730 MAG_TimelyModifyMagneticModel(UserDate, MagneticModel, TimedMagneticModel); /* Time adjust the coefficients, Equation 19, WMM Technical report */
731 MAG_Geomag(Ellip, CoordSpherical, CoordGeodetic, TimedMagneticModel, &GeoMagneticElements); /* Computes the geoMagnetic field elements and their time change*/
732 MAG_CalculateGridVariation(CoordGeodetic,&GeoMagneticElements);
733 v[_T("Decl")] = GeoMagneticElements.Decl;
734 v[_T("Decldot")] = GeoMagneticElements.Decldot;
735 v[_T("F")] = GeoMagneticElements.F;
736 v[_T("Fdot")] = GeoMagneticElements.Fdot;
737 v[_T("GV")] = GeoMagneticElements.GV;
738 v[_T("GVdot")] = GeoMagneticElements.GVdot;
739 v[_T("H")] = GeoMagneticElements.H;
740 v[_T("Hdot")] = GeoMagneticElements.Hdot;
741 v[_T("Incl")] = GeoMagneticElements.Incl;
742 v[_T("Incldot")] = GeoMagneticElements.Incldot;
743 v[_T("X")] = GeoMagneticElements.X;
744 v[_T("Xdot")] = GeoMagneticElements.Xdot;
745 v[_T("Y")] = GeoMagneticElements.Y;
746 v[_T("Ydot")] = GeoMagneticElements.Ydot;
747 v[_T("Z")] = GeoMagneticElements.Z;
748 v[_T("Zdot")] = GeoMagneticElements.Zdot;
749 wxJSONWriter w;
750 wxString out;
751 w.Write(v, out);
752 SendPluginMessage(wxString(_T("WMM_VARIATION")), out);
753 }
754
SendBoatVariation()755 void wmm_pi::SendBoatVariation()
756 {
757 wxJSONValue v;
758 v[_T("Decl")] = m_boatVariation.Decl;
759 v[_T("Decldot")] = m_boatVariation.Decldot;
760 v[_T("F")] = m_boatVariation.F;
761 v[_T("Fdot")] = m_boatVariation.Fdot;
762 v[_T("GV")] = m_boatVariation.GV;
763 v[_T("GVdot")] = m_boatVariation.GVdot;
764 v[_T("H")] = m_boatVariation.H;
765 v[_T("Hdot")] = m_boatVariation.Hdot;
766 v[_T("Incl")] = m_boatVariation.Incl;
767 v[_T("Incldot")] = m_boatVariation.Incldot;
768 v[_T("X")] = m_boatVariation.X;
769 v[_T("Xdot")] = m_boatVariation.Xdot;
770 v[_T("Y")] = m_boatVariation.Y;
771 v[_T("Ydot")] = m_boatVariation.Ydot;
772 v[_T("Z")] = m_boatVariation.Z;
773 v[_T("Zdot")] = m_boatVariation.Zdot;
774 wxJSONWriter w;
775 wxString out;
776 w.Write(v, out);
777 SendPluginMessage(wxString(_T("WMM_VARIATION_BOAT")), out);
778 }
779
SendCursorVariation()780 void wmm_pi::SendCursorVariation()
781 {
782 wxJSONValue v;
783 v[_T("Decl")] = m_cursorVariation.Decl;
784 v[_T("Decldot")] = m_cursorVariation.Decldot;
785 v[_T("F")] = m_cursorVariation.F;
786 v[_T("Fdot")] = m_cursorVariation.Fdot;
787 v[_T("GV")] = m_cursorVariation.GV;
788 v[_T("GVdot")] = m_cursorVariation.GVdot;
789 v[_T("H")] = m_cursorVariation.H;
790 v[_T("Hdot")] = m_cursorVariation.Hdot;
791 v[_T("Incl")] = m_cursorVariation.Incl;
792 v[_T("Incldot")] = m_cursorVariation.Incldot;
793 v[_T("X")] = m_cursorVariation.X;
794 v[_T("Xdot")] = m_cursorVariation.Xdot;
795 v[_T("Y")] = m_cursorVariation.Y;
796 v[_T("Ydot")] = m_cursorVariation.Ydot;
797 v[_T("Z")] = m_cursorVariation.Z;
798 v[_T("Zdot")] = m_cursorVariation.Zdot;
799 wxJSONWriter w;
800 wxString out;
801 w.Write(v, out);
802 SendPluginMessage(wxString(_T("WMM_VARIATION_CURSOR")), out);
803 }
804
AngleToText(double angle)805 wxString wmm_pi::AngleToText(double angle)
806 {
807 int deg = (int)fabs(angle);
808 int min = (fabs(angle) - deg) * 60;
809 if (angle < 0)
810 return wxString::Format(_T("%u\u00B0%u' W"), deg, min);
811 else
812 return wxString::Format(_T("%u\u00B0%u' E"), deg, min);
813 }
814
LoadConfig(void)815 bool wmm_pi::LoadConfig(void)
816 {
817 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
818
819 if(pConf)
820 {
821 pConf->SetPath ( _T( "/Settings/WMM" ) );
822 pConf->Read ( _T( "ViewType" ), &m_iViewType, 1 );
823 pConf->Read ( _T( "ShowPlotOptions" ), &m_bShowPlotOptions, 1 );
824 pConf->Read ( _T( "ShowAtCursor" ), &m_bShowAtCursor, 1 );
825 pConf->Read ( _T( "ShowLiveIcon" ), &m_bShowLiveIcon, 1 );
826 pConf->Read ( _T( "ShowIcon" ), &m_bShowIcon, 1 );
827 pConf->Read ( _T( "Opacity" ), &m_iOpacity, 255 );
828
829 m_wmm_dialog_x = pConf->Read ( _T ( "DialogPosX" ), 20L );
830 m_wmm_dialog_y = pConf->Read ( _T ( "DialogPosY" ), 20L );
831
832 if((m_wmm_dialog_x < 0) || (m_wmm_dialog_x > m_display_width))
833 m_wmm_dialog_x = 5;
834 if((m_wmm_dialog_y < 0) || (m_wmm_dialog_y > m_display_height))
835 m_wmm_dialog_y = 5;
836
837 pConf->SetPath ( _T( "/Settings/WMM/Plot" ) );
838 pConf->Read ( _T( "Declination" ), &m_DeclinationMap.m_bEnabled, 1);
839 pConf->Read ( _T( "DeclinationSpacing" ), &m_DeclinationMap.m_Spacing, 10);
840 pConf->Read ( _T( "Inclination" ), &m_InclinationMap.m_bEnabled, 0);
841 pConf->Read ( _T( "InclinationSpacing" ), &m_InclinationMap.m_Spacing, 10);
842 pConf->Read ( _T( "FieldStrength" ), &m_FieldStrengthMap.m_bEnabled, 0);
843 pConf->Read ( _T( "FieldStrengthSpacing" ), &m_FieldStrengthMap.m_Spacing, 10000);
844
845 pConf->Read ( _T( "StepSize" ), &m_MapStep, 6);
846 pConf->Read ( _T( "PoleAccuracy" ), &m_MapPoleAccuracy, 2);
847 m_DeclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
848 m_InclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
849 m_FieldStrengthMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
850
851 m_MapDate = wxDateTime::Now(); /* always reset to current date */
852
853 m_bCachedPlotOk = false;
854
855 pConf->SetPath ( _T ( "/Directories" ) );
856 wxString s =wxFileName::GetPathSeparator();
857 wxString def = *GetpSharedDataLocation() + _T("plugins")
858 + s + _T("wmm_pi") + s + _T("data") + s;
859 //pConf->Read ( _T ( "WMMDataLocation" ), &m_wmm_dir, def);
860 m_wmm_dir = def;
861 return true;
862 }
863 else
864 return false;
865 }
866
SaveConfig(void)867 bool wmm_pi::SaveConfig(void)
868 {
869 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
870
871 if(pConf)
872 {
873 pConf->SetPath ( _T ( "/Settings/WMM" ) );
874 pConf->Write ( _T ( "ViewType" ), m_iViewType );
875 pConf->Write ( _T ( "ShowPlotOptions" ), m_bShowPlotOptions );
876 pConf->Write ( _T ( "ShowAtCursor" ), m_bShowAtCursor );
877 pConf->Write ( _T ( "ShowLiveIcon" ), m_bShowLiveIcon );
878 pConf->Write ( _T ( "ShowIcon" ), m_bShowIcon );
879 pConf->Write ( _T ( "Opacity" ), m_iOpacity );
880
881 pConf->Write ( _T ( "DialogPosX" ), m_wmm_dialog_x );
882 pConf->Write ( _T ( "DialogPosY" ), m_wmm_dialog_y );
883
884 pConf->SetPath ( _T( "/Settings/WMM/Plot" ) );
885 pConf->Write ( _T( "Declination" ), m_DeclinationMap.m_bEnabled);
886 pConf->Write ( _T( "DeclinationSpacing" ), m_DeclinationMap.m_Spacing);
887 pConf->Write ( _T( "Inclination" ), m_InclinationMap.m_bEnabled);
888 pConf->Write ( _T( "InclinationSpacing" ), m_InclinationMap.m_Spacing);
889 pConf->Write ( _T( "FieldStrength" ), m_FieldStrengthMap.m_bEnabled);
890 pConf->Write ( _T( "FieldStrengthSpacing" ), m_FieldStrengthMap.m_Spacing);
891 pConf->Write ( _T( "StepSize" ), m_MapStep);
892 pConf->Write ( _T( "PoleAccuracy" ), m_MapPoleAccuracy);
893
894 pConf->SetPath ( _T ( "/Directories" ) );
895 pConf->Write ( _T ( "WMMDataLocation" ), m_wmm_dir );
896
897 return true;
898 }
899 else
900 return false;
901 }
902
SetBackColor(wxWindow * ctrl,wxColour col)903 void SetBackColor( wxWindow* ctrl, wxColour col)
904 {
905 static int depth = 0; // recursion count
906 if ( depth == 0 ) { // only for the window root, not for every child
907
908 ctrl->SetBackgroundColour( col );
909 }
910
911 wxWindowList kids = ctrl->GetChildren();
912 for( unsigned int i = 0; i < kids.GetCount(); i++ ) {
913 wxWindowListNode *node = kids.Item( i );
914 wxWindow *win = node->GetData();
915
916 if( win->IsKindOf( CLASSINFO(wxListBox) ) )
917 ( (wxListBox*) win )->SetBackgroundColour( col );
918
919 else if( win->IsKindOf( CLASSINFO(wxTextCtrl) ) )
920 ( (wxTextCtrl*) win )->SetBackgroundColour( col );
921
922 // else if( win->IsKindOf( CLASSINFO(wxStaticText) ) )
923 // ( (wxStaticText*) win )->SetForegroundColour( uitext );
924
925 else if( win->IsKindOf( CLASSINFO(wxChoice) ) )
926 ( (wxChoice*) win )->SetBackgroundColour( col );
927
928 else if( win->IsKindOf( CLASSINFO(wxComboBox) ) )
929 ( (wxComboBox*) win )->SetBackgroundColour( col );
930
931 else if( win->IsKindOf( CLASSINFO(wxRadioButton) ) )
932 ( (wxRadioButton*) win )->SetBackgroundColour( col );
933
934 else if( win->IsKindOf( CLASSINFO(wxScrolledWindow) ) ) {
935 ( (wxScrolledWindow*) win )->SetBackgroundColour( col );
936 }
937
938
939 else if( win->IsKindOf( CLASSINFO(wxButton) ) ) {
940 ( (wxButton*) win )->SetBackgroundColour( col );
941 }
942
943 else {
944 ;
945 }
946
947 if( win->GetChildren().GetCount() > 0 ) {
948 depth++;
949 wxWindow * w = win;
950 SetBackColor( w, col );
951 depth--;
952 }
953 }
954 }
955
ShowPreferencesDialog(wxWindow * parent)956 void wmm_pi::ShowPreferencesDialog( wxWindow* parent )
957 {
958 WmmPrefsDialog *dialog = new WmmPrefsDialog( parent, wxID_ANY, _("WMM Preferences"), wxPoint( m_wmm_dialog_x, m_wmm_dialog_y), wxDefaultSize, wxDEFAULT_DIALOG_STYLE );
959 dialog->Fit();
960 wxColour cl;
961 GetGlobalColor(_T("DILG1"), &cl);
962 dialog->SetBackgroundColour(cl);
963
964 dialog->m_rbViewType->SetSelection(m_iViewType);
965 dialog->m_cbShowPlotOptions->SetValue(m_bShowPlotOptions);
966 dialog->m_cbShowAtCursor->SetValue(m_bShowAtCursor);
967 dialog->m_cbShowIcon->SetValue(m_bShowIcon);
968 dialog->m_cbLiveIcon->SetValue(m_bShowLiveIcon);
969 dialog->m_sOpacity->SetValue(m_iOpacity);
970
971 if(dialog->ShowModal() == wxID_OK)
972 {
973 m_iViewType = dialog->m_rbViewType->GetSelection();
974 m_bShowPlotOptions = dialog->m_cbShowPlotOptions->GetValue();
975 m_bShowAtCursor = dialog->m_cbShowAtCursor->GetValue();
976 m_bShowLiveIcon = dialog->m_cbLiveIcon->GetValue();
977 m_bShowIcon = dialog->m_cbShowIcon->GetValue();
978 m_iOpacity = dialog->m_sOpacity->GetValue();
979
980 RearrangeWindow();
981 SetIconType();
982
983 SaveConfig();
984 }
985 delete dialog;
986 }
987
ShowPlotSettings()988 void wmm_pi::ShowPlotSettings()
989 {
990 WmmPlotSettingsDialog *dialog = new WmmPlotSettingsDialog( m_parent_window );
991 wxFont *pFont = OCPNGetFont(_T("Dialog"), 0);
992 dialog->SetFont(*pFont);
993
994 dialog->Fit();
995 wxColour cl;
996 GetGlobalColor(_T("DILG1"), &cl);
997 dialog->SetBackgroundColour(cl);
998
999 dialog->m_cbDeclination->SetValue(m_DeclinationMap.m_bEnabled);
1000 dialog->m_scDeclinationSpacing->SetValue(m_DeclinationMap.m_Spacing);
1001 dialog->m_cbInclination->SetValue(m_InclinationMap.m_bEnabled);
1002 dialog->m_scInclinationSpacing->SetValue(m_InclinationMap.m_Spacing);
1003 dialog->m_cbFieldStrength->SetValue(m_FieldStrengthMap.m_bEnabled);
1004 dialog->m_scFieldStrengthSpacing->SetValue(m_FieldStrengthMap.m_Spacing);
1005 ///dialog->m_dpDate->SetValue(m_MapDate);
1006 dialog->m_sStep->SetValue(m_MapStep);
1007 dialog->m_sPoleAccuracy->SetValue(m_MapPoleAccuracy);
1008
1009 if(dialog->ShowModal() == wxID_OK)
1010 {
1011 m_DeclinationMap.m_bEnabled = dialog->m_cbDeclination->GetValue();
1012 m_DeclinationMap.m_Spacing = dialog->m_scDeclinationSpacing->GetValue();
1013 m_InclinationMap.m_bEnabled = dialog->m_cbInclination->GetValue();
1014 m_InclinationMap.m_Spacing = dialog->m_scInclinationSpacing->GetValue();
1015 m_FieldStrengthMap.m_bEnabled = dialog->m_cbFieldStrength->GetValue();
1016 m_FieldStrengthMap.m_Spacing = dialog->m_scFieldStrengthSpacing->GetValue();
1017 ///m_MapDate = dialog->m_dpDate->GetValue();
1018 m_MapStep = dialog->m_sStep->GetValue();
1019 m_MapPoleAccuracy = dialog->m_sPoleAccuracy->GetValue();
1020 m_DeclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
1021 m_InclinationMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
1022 m_FieldStrengthMap.ConfigureAccuracy(m_MapStep, m_MapPoleAccuracy);
1023
1024 m_bCachedPlotOk = false;
1025 if(m_pWmmDialog->m_cbEnablePlot->GetValue())
1026 RecomputePlot();
1027
1028 RequestRefresh( m_parent_window );
1029 RearrangeWindow();
1030
1031 SaveConfig();
1032 }
1033 delete dialog;
1034 }
1035