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