32#include <wx/glcanvas.h>
33#include <wx/graphics.h>
34#include <wx/progdlg.h>
47extern double g_ContentScaleFactor;
48float g_piGLMinSymbolLineWidth = 0.9;
50enum GRIB_OVERLAP { _GIN, _GON, _GOUT };
57 double lat_max,
double lon_min,
double lon_max,
59 if (((vp->
lon_min - Marge) > (lon_max + Marge)) ||
60 ((vp->
lon_max + Marge) < (lon_min - Marge)) ||
61 ((vp->
lat_max + Marge) < (lat_min - Marge)) ||
62 ((vp->
lat_min - Marge) > (lat_max + Marge)))
78 if (y < m_miny || y > m_maxy)
return FALSE;
83 if (x < m_maxx - 360.)
85 else if (x > m_minx + 360.)
88 if (x < m_minx || x > m_maxx)
return FALSE;
94static wxString MToString(
int DataCenterModel )
96 switch( DataCenterModel ) {
97 case NOAA_GFS:
return "NOAA_GFS";
98 case NOAA_NCEP_WW3:
return "NOAA_NCEP_WW3";
99 case NOAA_NCEP_SST:
return "NOAA_NCEP_SST";
100 case NOAA_RTOFS:
return "NOAA_RTOFS";
101 case FNMOC_WW3_GLB:
return "FNMOC_WW3";
102 case FNMOC_WW3_MED:
return "FNMOC_WW3";
103 case NORWAY_METNO:
return "NORWAY_METNO";
104 default :
return "OTHER_DATA_CENTER";
110static GLuint texture_format = 0;
114static GLboolean QueryExtension(
const char *extName )
126 extNameLen = strlen( extName );
128 p = (
char *) glGetString( GL_EXTENSIONS );
133 end = p + strlen( p );
136 int n = strcspn( p,
" " );
137 if( ( extNameLen == n ) && ( strncmp( extName, p, n ) == 0 ) ) {
145#if defined(__WXMSW__)
146#define systemGetProcAddress(ADDR) wglGetProcAddress(ADDR)
147#elif defined(__WXOSX__)
149#define systemGetProcAddress(ADDR) dlsym(RTLD_DEFAULT, ADDR)
151#define systemGetProcAddress(ADDR) glXGetProcAddress((const GLubyte *)ADDR)
156void LineBuffer::pushLine(
float x0,
float y0,
float x1,
float y1) {
157 buffer.push_back(x0);
158 buffer.push_back(y0);
159 buffer.push_back(x1);
160 buffer.push_back(y1);
163void LineBuffer::pushPetiteBarbule(
int b,
int l) {
164 int tilt = (l * 100) / 250;
165 pushLine(b, 0, b + tilt, -l);
168void LineBuffer::pushGrandeBarbule(
int b,
int l) {
169 int tilt = (l * 100) / 250;
170 pushLine(b, 0, b + tilt, -l);
173void LineBuffer::pushTriangle(
int b,
int l) {
174 int dim = (l * 100) / 250;
175 pushLine(b, 0, b + dim, -l);
176 pushLine(b + (dim * 2), 0, b + dim, -l);
179void LineBuffer::Finalize() {
180 count = buffer.size() / 4;
181 lines =
new float[buffer.size()];
183 for (
auto it = buffer.begin(); it != buffer.end(); it++) lines[i++] = *it;
186int adjustSpacing(
int dialogSetSpacing) {
192 int sizeMin = wxMin(sz.x, sz.y);
193 int space = ((double)dialogSetSpacing) * (sizeMin / 2) / 100;
198 return dialogSetSpacing;
206 : m_dlg(dlg), m_settings(dlg.m_OverlaySettings) {
207 if (wxGetDisplaySize().x > 0) {
214 wxMax(wxGetDisplaySize().x, wxGetDisplaySize().y);
216 m_pixel_mm = wxMax(.02, m_pixel_mm);
222 m_pGribTimelineRecordSet =
nullptr;
223 m_last_vp_scale = 0.;
226#if wxUSE_GRAPHICS_CONTEXT
229 m_Font_Message =
nullptr;
232 for (
int i = 0; i < GribOverlaySettings::SETTINGS_COUNT; i++)
233 m_pOverlay[i] =
nullptr;
235 m_particle_map =
nullptr;
236 m_particle_time_timer.Connect(
237 wxEVT_TIMER, wxTimerEventHandler(GRIBOverlayFactory::OnParticleTimer),
239 m_update_particle_particles =
false;
243 if (m_pixel_mm < 0.2) {
244 m_wind_arrow_size = 5.0 / m_pixel_mm;
246 wxMin(m_wind_arrow_size,
247 wxMax(wxGetDisplaySize().x, wxGetDisplaySize().y) / 20);
249 m_wind_arrow_size = 26;
252 double s = 2 * M_PI / 10.;
253 for (
double a = 0; a < 2 * M_PI; a += s)
254 m_wind_arrow_cach_cache[0].pushLine(r * sin(a), r * cos(a), r * sin(a + s),
257 int dec = -m_wind_arrow_size / 2;
258 int pointerLength = m_wind_arrow_size / 3;
261 for (i = 1; i < 14; i++) {
262 LineBuffer &arrow = m_wind_arrow_cach_cache[i];
264 arrow.pushLine(dec, 0, dec + m_wind_arrow_size, 0);
265 arrow.pushLine(dec, 0, dec + pointerLength, pointerLength / 2);
266 arrow.pushLine(dec, 0, dec + pointerLength,
267 -(pointerLength / 2));
270 int featherPosition = m_wind_arrow_size / 6;
273 dec + m_wind_arrow_size - featherPosition;
275 dec + m_wind_arrow_size;
277 int lpetite = m_wind_arrow_size / 5;
278 int lgrande = lpetite * 2;
281 m_wind_arrow_cach_cache[1].pushPetiteBarbule(b1, lpetite);
283 m_wind_arrow_cach_cache[2].pushGrandeBarbule(b2, lgrande);
285 m_wind_arrow_cach_cache[3].pushGrandeBarbule(b2, lgrande);
286 m_wind_arrow_cach_cache[3].pushPetiteBarbule(b2 - featherPosition, lpetite);
288 m_wind_arrow_cach_cache[4].pushGrandeBarbule(b2, lgrande);
289 m_wind_arrow_cach_cache[4].pushGrandeBarbule(b2 - featherPosition, lgrande);
291 m_wind_arrow_cach_cache[5].pushGrandeBarbule(b2, lgrande);
292 m_wind_arrow_cach_cache[5].pushGrandeBarbule(b2 - featherPosition, lgrande);
293 m_wind_arrow_cach_cache[5].pushPetiteBarbule(b2 - featherPosition * 2,
296 m_wind_arrow_cach_cache[6].pushGrandeBarbule(b2, lgrande);
297 m_wind_arrow_cach_cache[6].pushGrandeBarbule(b2 - featherPosition, lgrande);
298 m_wind_arrow_cach_cache[6].pushGrandeBarbule(b2 - featherPosition * 2,
301 m_wind_arrow_cach_cache[7].pushGrandeBarbule(b2, lgrande);
302 m_wind_arrow_cach_cache[7].pushGrandeBarbule(b2 - featherPosition, lgrande);
303 m_wind_arrow_cach_cache[7].pushGrandeBarbule(b2 - featherPosition * 2,
305 m_wind_arrow_cach_cache[7].pushPetiteBarbule(b2 - featherPosition * 3,
308 m_wind_arrow_cach_cache[8].pushGrandeBarbule(b2, lgrande);
309 m_wind_arrow_cach_cache[8].pushGrandeBarbule(b2 - featherPosition, lgrande);
310 m_wind_arrow_cach_cache[8].pushGrandeBarbule(b2 - featherPosition * 2,
312 m_wind_arrow_cach_cache[8].pushGrandeBarbule(b2 - featherPosition * 3,
315 m_wind_arrow_cach_cache[9].pushTriangle(b1 - featherPosition, lgrande);
317 m_wind_arrow_cach_cache[10].pushTriangle(b1 - featherPosition, lgrande);
318 m_wind_arrow_cach_cache[10].pushGrandeBarbule(b1 - featherPosition * 2,
321 m_wind_arrow_cach_cache[11].pushTriangle(b1 - featherPosition, lgrande);
322 m_wind_arrow_cach_cache[11].pushGrandeBarbule(b1 - featherPosition * 2,
324 m_wind_arrow_cach_cache[11].pushGrandeBarbule(b1 - featherPosition * 3,
327 m_wind_arrow_cach_cache[12].pushTriangle(b1 - featherPosition, lgrande);
328 m_wind_arrow_cach_cache[12].pushGrandeBarbule(b1 - featherPosition * 2,
330 m_wind_arrow_cach_cache[12].pushGrandeBarbule(b1 - featherPosition * 3,
332 m_wind_arrow_cach_cache[12].pushGrandeBarbule(b1 - featherPosition * 4,
335 m_wind_arrow_cach_cache[13].pushTriangle(b1 - featherPosition, lgrande);
336 m_wind_arrow_cach_cache[13].pushTriangle(b1 - featherPosition * 3, lgrande);
338 for (i = 0; i < 14; i++) m_wind_arrow_cach_cache[i].Finalize();
341 for (
int j = 0; j < 2; j++) {
347 if (m_pixel_mm > 0.2) {
348 arrowSize = 5.0 / m_pixel_mm;
350 arrowSize, wxMax(wxGetDisplaySize().x, wxGetDisplaySize().y) / 20);
351 dec1 = arrowSize / 6;
352 dec2 = arrowSize / 8;
358 dec = -arrowSize / 2;
360 m_single_arrow[j].pushLine(dec, 0, dec + arrowSize, 0);
361 m_single_arrow[j].pushLine(dec - 2, 0, dec + dec1, dec1 + 1);
362 m_single_arrow[j].pushLine(dec - 2, 0, dec + dec1, -(dec1 + 1));
363 m_single_arrow[j].Finalize();
365 m_double_arrow[j].pushLine(dec, -dec2, dec + arrowSize, -dec2);
366 m_double_arrow[j].pushLine(dec, dec2, dec + arrowSize, +dec2);
368 m_double_arrow[j].pushLine(dec - 2, 0, dec + dec1, dec1 + 1);
369 m_double_arrow[j].pushLine(dec - 2, 0, dec + dec1, -(dec1 + 1));
370 m_double_arrow[j].Finalize();
374GRIBOverlayFactory::~GRIBOverlayFactory() {
380 delete m_Font_Message;
383void GRIBOverlayFactory::Reset() {
384 m_pGribTimelineRecordSet =
nullptr;
389void GRIBOverlayFactory::SetMessageFont() {
398 if (m_Font_Message)
delete m_Font_Message;
399 m_Font_Message =
new wxFont(fo);
402void GRIBOverlayFactory::SetGribTimelineRecordSet(
405 m_pGribTimelineRecordSet = pGribTimelineRecordSet;
408void GRIBOverlayFactory::ClearCachedData() {
410 for (
int i = 0; i < GribOverlaySettings::SETTINGS_COUNT; i++) {
411 delete m_pOverlay[i];
412 m_pOverlay[i] =
nullptr;
420bool GRIBOverlayFactory::RenderGLGribOverlay(wxGLContext *pcontext,
422 if (g_bpause)
return false;
426 if (!m_oDC || !m_oDC->UsesGL()) {
431#ifndef USE_ANDROID_GLES2
432 glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0]);
434 glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &parms[0]);
436 g_piGLMinSymbolLineWidth = wxMax(parms[0], 1);
442 m_oDC->SetDC(
nullptr);
446 bool rv = DoRenderGribOverlay(vp);
453bool GRIBOverlayFactory::RenderGribOverlay(wxDC &dc,
PlugIn_ViewPort *vp) {
454 if (!m_oDC || m_oDC->UsesGL()) {
464#if wxUSE_GRAPHICS_CONTEXT
466 pmdc =
dynamic_cast<wxMemoryDC*
>(&dc);
467 wxGraphicsContext *pgc = wxGraphicsContext::Create( *pmdc );
472 bool rv = DoRenderGribOverlay(vp);
477void GRIBOverlayFactory::SettingsIdToGribId(
int i,
int &idx,
int &idy,
482 case GribOverlaySettings::WIND:
485 case GribOverlaySettings::WIND_GUST:
490 case GribOverlaySettings::PRESSURE:
495 case GribOverlaySettings::WAVE:
500 case GribOverlaySettings::CURRENT:
505 case GribOverlaySettings::PRECIPITATION:
510 case GribOverlaySettings::CLOUD:
515 case GribOverlaySettings::AIR_TEMPERATURE:
520 case GribOverlaySettings::SEA_TEMPERATURE:
525 case GribOverlaySettings::CAPE:
530 case GribOverlaySettings::COMP_REFL:
539 if (!m_pGribTimelineRecordSet) {
547 m_tex_font_numbers.Build(*m_Font_Message);
549 if (m_oDC) m_oDC->SetFont(*m_Font_Message);
552 m_message_hiden.Empty();
555 if (m_pdc && vp->
view_scale_ppm != m_last_vp_scale) ClearCachedData();
561 wxArrayPtrVoid **pIA = m_pGribTimelineRecordSet->
m_IsobarArray;
563 for (
int overlay = 1; overlay >= 0; overlay--) {
564 for (
int i = 0; i < GribOverlaySettings::SETTINGS_COUNT; i++) {
565 if (i == GribOverlaySettings::WIND) {
567 if (m_dlg.m_bDataPlot[i]) RenderGribOverlayMap(i, pGR, vp);
569 if (m_dlg.m_bDataPlot[i]) {
570 RenderGribBarbedArrows(i, pGR, vp);
571 RenderGribIsobar(i, pGR, pIA, vp);
572 RenderGribNumbers(i, pGR, vp);
573 RenderGribParticles(i, pGR, vp);
575 if (m_settings.Settings[i].m_iBarbedVisibility)
576 RenderGribBarbedArrows(i, pGR, vp);
581 if (i == GribOverlaySettings::PRESSURE) {
583 if (m_dlg.m_bDataPlot[i]) {
584 RenderGribIsobar(i, pGR, pIA, vp);
585 RenderGribNumbers(i, pGR, vp);
587 if (m_settings.Settings[i].m_iIsoBarVisibility)
588 RenderGribIsobar(i, pGR, pIA, vp);
593 if (m_dlg.InDataPlot(i) && !m_dlg.m_bDataPlot[i])
continue;
596 RenderGribOverlayMap(i, pGR, vp);
598 RenderGribBarbedArrows(i, pGR, vp);
599 RenderGribIsobar(i, pGR, pIA, vp);
600 RenderGribDirectionArrows(i, pGR, vp);
601 RenderGribNumbers(i, pGR, vp);
602 RenderGribParticles(i, pGR, vp);
607 if (!m_message_hiden.IsEmpty()) m_message_hiden.Append(
"\n");
608 m_message_hiden.Append(_(
"Warning : Data at Geopotential Height"))
610 .Append(m_settings.GetAltitudeFromIndex(
612 m_settings.Settings[GribOverlaySettings::PRESSURE].m_Units))
614 .Append(m_settings.GetUnitSymbol(GribOverlaySettings::PRESSURE))
617 if (m_dlg.ProjectionEnabled()) {
620 DrawProjectedPosition(x, y);
622 if (!m_message_hiden.IsEmpty()) m_message_hiden.Append(
"\n");
623 m_message_hiden.Append(m_message);
627 if (m_dlg.m_highlight_latmax - m_dlg.m_highlight_latmin > 0.01 &&
628 m_dlg.m_highlight_lonmax - m_dlg.m_highlight_lonmin > 0.01) {
630 GetCanvasPixLL(vp, &p1, m_dlg.m_highlight_latmin, m_dlg.m_highlight_lonmin);
631 GetCanvasPixLL(vp, &p2, m_dlg.m_highlight_latmax, m_dlg.m_highlight_lonmax);
633 m_pdc->SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
635 wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),
636 wxBRUSHSTYLE_CROSSDIAG_HATCH));
637 m_pdc->DrawRectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
641 m_oDC->SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
643 wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),
644 wxBRUSHSTYLE_CROSSDIAG_HATCH));
645 m_oDC->DrawRectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
653static inline bool isClearSky(
int settings,
double v) {
654 return ((settings == GribOverlaySettings::PRECIPITATION) ||
655 (settings == GribOverlaySettings::CLOUD)) &&
660void GRIBOverlayFactory::GetCalibratedGraphicColor(
int settings,
double val_in,
661 unsigned char *data) {
662 unsigned char r, g, b, a;
663 a = m_settings.m_iOverlayTransparency;
665 if (val_in != GRIB_NOTDEF) {
666 val_in = m_settings.CalibrateValue(settings, val_in);
669 if ((settings == GribOverlaySettings::PRECIPITATION ||
670 settings == GribOverlaySettings::CLOUD) &&
673 if ((settings == GribOverlaySettings::COMP_REFL) && val_in < 5) a = 0;
675 GetGraphicColor(settings, val_in, r, g, b);
677 r = 255, g = 255, b = 255, a = 0;
685bool GRIBOverlayFactory::CreateGribGLTexture(
GribOverlay *pGO,
int settings,
688 pGR->GetLonMin() == 0 && pGR->GetLonMax() + pGR->
GetDi() >= 360.;
691 int tw, th, samples = 1;
694 if (pGR->
GetNi() > 1024 || pGR->
GetNj() > 1024) {
700 dw = (tw > 1022) ? 1022. / tw : 1.;
701 dh = (th > 1022) ? 1022. / th : 1.;
702 delta = wxMin(dw, dh);
710 tw = samples * (pGR->
GetNi() - 1) + 1 + 2 * !repeat;
711 th = samples * (pGR->
GetNj() - 1) + 1 + 2;
712 if (tw >= 512 || th >= 512 || samples == 16)
break;
717 if (tw > 1024 || th > 1024)
return false;
719 pGO->m_iTexDataDim[0] = tw;
720 pGO->m_iTexDataDim[1] = th;
722#ifdef USE_ANDROID_GLES2
731 if (((xp != 0) && !(xp & (xp - 1))))
743 if (((xp != 0) && !(xp & (xp - 1))))
759 auto *data =
new unsigned char[tw * th * 4];
761 for (
int j = 0; j < pGR->
GetNj(); j++) {
762 for (
int i = 0; i < pGR->
GetNi(); i++) {
764 int y = (j + 1) * delta;
765 int x = (i + !repeat) * delta;
766 int doff = 4 * (y * tw + x);
767 GetCalibratedGraphicColor(settings, v, data + doff);
770 }
else if (samples == 1) {
771 for (
int j = 0; j < pGR->
GetNj(); j++) {
772 for (
int i = 0; i < pGR->
GetNi(); i++) {
776 int doff = 4 * (y * tw + x);
777 GetCalibratedGraphicColor(settings, v, data + doff);
781 for (
int j = 0; j < pGR->
GetNj(); j++) {
782 for (
int i = 0; i < pGR->
GetNi(); i++) {
783 double v00 = pGR->
GetValue(i, j), v01 = GRIB_NOTDEF;
784 double v10 = GRIB_NOTDEF, v11 = GRIB_NOTDEF;
785 if (i < pGR->GetNi() - 1) {
787 if (j < pGR->GetNj() - 1) v11 = pGR->
GetValue(i + 1, j + 1);
789 if (j < pGR->GetNj() - 1) v10 = pGR->
GetValue(i, j + 1);
791 for (
int ys = 0; ys < samples; ys++) {
792 int y = j * samples + ys + 1;
793 double yd = (double)ys / samples;
795 double a0 = 1, a1 = 1;
796 if (v10 == GRIB_NOTDEF) {
798 if (v00 == GRIB_NOTDEF)
802 }
else if (v00 == GRIB_NOTDEF)
805 v0 = (1 - yd) * v00 + yd * v10;
806 if (v11 == GRIB_NOTDEF) {
808 if (v01 == GRIB_NOTDEF)
812 }
else if (v01 == GRIB_NOTDEF)
815 v1 = (1 - yd) * v01 + yd * v11;
817 for (
int xs = 0; xs < samples; xs++) {
818 int x = i * samples + xs + !repeat;
819 double xd = (double)xs / samples;
821 if (v1 == GRIB_NOTDEF)
822 v = v0, a = (1 - xd) * a0;
823 else if (v0 == GRIB_NOTDEF)
826 v = (1 - xd) * v0 + xd * v1;
827 a = (1 - xd) * a0 + xd * a1;
830 int doff = 4 * (y * tw + x);
831 GetCalibratedGraphicColor(settings, v, data + doff);
834 if (i == pGR->
GetNi() - 1)
break;
836 if (j == pGR->
GetNj() - 1)
break;
843 memcpy(data, data + 4 * tw * 1, 4 * tw);
844 memcpy(data + 4 * tw * (th - 1), data + 4 * tw * (th - 2), 4 * tw);
845 for (
int x = 0; x < tw; x++) {
848 doff = 4 * ((th - 1) * tw + x);
853 for (
int y = 0; y < th; y++) {
854 int doff = 4 * y * tw, soff = doff + 4;
855 memcpy(data + doff, data + soff, 4);
857 doff = 4 * (y * tw + tw - 1), soff = doff - 4;
858 memcpy(data + doff, data + soff, 4);
863 glGenTextures(1, &texture);
864 glBindTexture(texture_format, texture);
866 glTexParameteri(texture_format, GL_TEXTURE_WRAP_S,
867 repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
868 glTexParameteri(texture_format, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
869 glTexParameteri(texture_format, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
870 glTexParameteri(texture_format, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
873 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
875 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
876 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
877 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
878 glPixelStorei(GL_UNPACK_ROW_LENGTH, tw);
880 glTexImage2D(texture_format, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE,
885 glTexImage2D(texture_format, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE,
891 pGO->m_iTexture = texture;
892 pGO->m_iTextureDim[0] = tw;
893 pGO->m_iTextureDim[1] = th;
899wxImage GRIBOverlayFactory::CreateGribImage(
int settings,
GribRecord *pGR,
902 const wxPoint &porg) {
908 int width = abs(pmax.x - pmin.x);
909 int height = abs(pmax.y - pmin.y);
913 if (width > m_ParentSize.GetWidth() || height > m_ParentSize.GetHeight())
917 wxImage gr_image(width, height);
918 gr_image.InitAlpha();
921 for (
int ipix = 0; ipix < (width - grib_pixel_size + 1);
922 ipix += grib_pixel_size) {
923 for (
int jpix = 0; jpix < (height - grib_pixel_size + 1);
924 jpix += grib_pixel_size) {
931 if (v != GRIB_NOTDEF) {
932 v = m_settings.CalibrateValue(settings, v);
933 wxColour c = GetGraphicColor(settings, v);
937 isClearSky(settings, v) ? 0 : m_settings.m_iOverlayTransparency;
939 unsigned char r = c.Red();
940 unsigned char g = c.Green();
941 unsigned char b = c.Blue();
943 for (
int xp = 0; xp < grib_pixel_size; xp++)
944 for (
int yp = 0; yp < grib_pixel_size; yp++) {
945 gr_image.SetRGB(ipix + xp, jpix + yp, r, g, b);
946 gr_image.SetAlpha(ipix + xp, jpix + yp, a);
949 for (
int xp = 0; xp < grib_pixel_size; xp++)
950 for (
int yp = 0; yp < grib_pixel_size; yp++)
951 gr_image.SetAlpha(ipix + xp, jpix + yp, 0);
956 return gr_image.Blur(4);
968 {0,
"#d90000"}, {1,
"#d92a00"}, {2,
"#d96e00"}, {3,
"#d9b200"},
969 {4,
"#d4d404"}, {5,
"#a6d906"}, {7,
"#06d9a0"}, {9,
"#00d9b0"},
970 {12,
"#00d9c0"}, {15,
"#00aed0"}, {18,
"#0083e0"}, {21,
"#0057e0"},
971 {24,
"#0000f0"}, {27,
"#0400f0"}, {30,
"#1c00f0"}, {36,
"#4800f0"},
972 {42,
"#6900f0"}, {48,
"#a000f0"}, {56,
"#f000f0"}};
975 {0,
"#00d900"}, {1,
"#2ad900"}, {2,
"#6ed900"}, {3,
"#b2d900"},
976 {4,
"#d4d400"}, {5,
"#d9a600"}, {7,
"#d90000"}, {9,
"#d90040"},
977 {12,
"#d90060"}, {15,
"#ae0080"}, {18,
"#8300a0"}, {21,
"#5700c0"},
978 {24,
"#0000d0"}, {27,
"#0400e0"}, {30,
"#0800e0"}, {36,
"#a000e0"},
979 {42,
"#c004c0"}, {48,
"#c008a0"}, {56,
"#c0a008"}};
983 {0,
"#288CFF"}, {3,
"#00AFFF"}, {6,
"#00DCE1"}, {9,
"#00F7B0"},
984 {12,
"#00EA9C"}, {15,
"#82F059"}, {18,
"#F0F503"}, {21,
"#FFED00"},
985 {24,
"#FFDB00"}, {27,
"#FFC700"}, {30,
"#FFB400"}, {33,
"#FF9800"},
986 {36,
"#FF7E00"}, {39,
"#F77800"}, {42,
"#EC7814"}, {45,
"#E4711E"},
987 {48,
"#E06128"}, {51,
"#DC5132"}, {54,
"#D5453C"}, {57,
"#CD3A46"},
988 {60,
"#BE2C50"}, {63,
"#B41A5A"}, {66,
"#AA1464"}, {70,
"#962878"},
993 {0,
"#283282"}, {5,
"#273c8c"}, {10,
"#264696"}, {14,
"#2350a0"},
994 {18,
"#1f5aaa"}, {22,
"#1a64b4"}, {26,
"#136ec8"}, {29,
"#0c78e1"},
995 {32,
"#0382e6"}, {35,
"#0091e6"}, {38,
"#009ee1"}, {41,
"#00a6dc"},
996 {44,
"#00b2d7"}, {47,
"#00bed2"}, {50,
"#28c8c8"}, {53,
"#78d2aa"},
997 {56,
"#8cdc78"}, {59,
"#a0eb5f"}, {62,
"#c8f550"}, {65,
"#f3fb02"},
998 {68,
"#ffed00"}, {71,
"#ffdd00"}, {74,
"#ffc900"}, {78,
"#ffab00"},
999 {82,
"#ff8100"}, {86,
"#f1780c"}, {90,
"#e26a23"}, {95,
"#d5453c"},
1005 {-2,
"#cc04ae"}, {2,
"#8f06e4"}, {6,
"#486afa"}, {10,
"#00ffff"},
1006 {15,
"#00d54b"}, {19,
"#59d800"}, {23,
"#f2fc00"}, {27,
"#ff1500"},
1007 {32,
"#ff0000"}, {36,
"#d80000"}, {40,
"#a90000"}, {44,
"#870000"},
1008 {48,
"#690000"}, {52,
"#550000"}, {56,
"#330000"}};
1011static ColorMap PrecipitationMap[] = {
1012 {0,
"#ffffff"}, {.01,
"#c8f0ff"}, {.02,
"#b4e6ff"}, {.05,
"#8cd3ff"},
1013 {.07,
"#78caff"}, {.1,
"#6ec1ff"}, {.2,
"#64b8ff"}, {.5,
"#50a6ff"},
1014 {.7,
"#469eff"}, {1.0,
"#3c96ff"}, {2.0,
"#328eff"}, {5.0,
"#1e7eff"},
1015 {7.0,
"#1476f0"}, {10,
"#0a6edc"}, {20,
"#0064c8"}, {50,
"#0052aa"}};
1018static ColorMap CloudMap[] = {{0,
"#ffffff"}, {1,
"#f0f0e6"}, {10,
"#e6e6dc"},
1019 {20,
"#dcdcd2"}, {30,
"#c8c8b4"}, {40,
"#aaaa8c"},
1020 {50,
"#969678"}, {60,
"#787864"}, {70,
"#646450"},
1021 {80,
"#5a5a46"}, {90,
"#505036"}};
1023static ColorMap REFCMap[] = {{0,
"#ffffff"}, {5,
"#06E8E4"}, {10,
"#009BE9"},
1024 {15,
"#0400F3"}, {20,
"#00F924"}, {25,
"#06C200"},
1025 {30,
"#009100"}, {35,
"#FAFB00"}, {40,
"#EBB608"},
1026 {45,
"#FF9400"}, {50,
"#FD0002"}, {55,
"#D70000"},
1027 {60,
"#C20300"}, {65,
"#F900FE"}, {70,
"#945AC8"}};
1030 {0,
"#0046c8"}, {5,
"#0050f0"}, {10,
"#005aff"}, {15,
"#0069ff"},
1031 {20,
"#0078ff"}, {30,
"#000cff"}, {45,
"#00a1ff"}, {60,
"#00b6fa"},
1032 {100,
"#00c9ee"}, {150,
"#00e0da"}, {200,
"#00e6b4"}, {300,
"#82e678"},
1033 {500,
"#9bff3b"}, {700,
"#ffdc00"}, {1000,
"#ffb700"}, {1500,
"#f37800"},
1034 {2000,
"#d4440c"}, {2500,
"#c8201c"}, {3000,
"#ad0430"},
1038 {0,
"#6271B7"}, {3,
"#3961A9"}, {6,
"#4A94A9"}, {9,
"#4D8D7B"},
1039 {12,
"#53A553"}, {15,
"#53A553"}, {18,
"#359F35"}, {21,
"#A79D51"},
1040 {24,
"#9F7F3A"}, {27,
"#A16C5C"}, {30,
"#A16C5C"}, {33,
"#813A4E"},
1041 {36,
"#AF5088"}, {39,
"#AF5088"}, {42,
"#754A93"}, {45,
"#754A93"},
1042 {48,
"#6D61A3"}, {51,
"#44698D"}, {54,
"#44698D"}, {57,
"#5C9098"},
1043 {60,
"#7D44A5"}, {63,
"#7D44A5"}, {66,
"#7D44A5"}, {69,
"#E7D7D7"},
1044 {72,
"#E7D7D7"}, {75,
"#E7D7D7"}, {78,
"#DBD483"}, {81,
"#DBD483"},
1045 {84,
"#DBD483"}, {87,
"#CDC470"}, {90,
"#CDC470"}, {93,
"#CDC470"},
1046 {96,
"#CDC470"}, {99,
"#808080"}};
1049static ColorMap *ColorMaps[] = {CurrentMap, GenericMap, WindMap, AirTempMap, SeaTempMap, PrecipitationMap, CloudMap};
1053 GENERIC_GRAPHIC_INDEX,
1055 AIRTEMP__GRAPHIC_INDEX,
1056 SEATEMP_GRAPHIC_INDEX,
1057 PRECIPITATION_GRAPHIC_INDEX,
1058 CLOUD_GRAPHIC_INDEX,
1059 CURRENT_GRAPHIC_INDEX,
1065static void InitColor(
ColorMap *map,
size_t maplen) {
1067 for (
size_t i = 0; i < maplen; i++) {
1070 map[i].g = c.Green();
1071 map[i].b = c.Blue();
1075void GRIBOverlayFactory::InitColorsTable() {
1076 InitColor(CurrentMap, (
sizeof CurrentMap) / (
sizeof *CurrentMap));
1077 InitColor(GenericMap, (
sizeof GenericMap) / (
sizeof *GenericMap));
1078 InitColor(WindMap, (
sizeof WindMap) / (
sizeof *WindMap));
1079 InitColor(AirTempMap, (
sizeof AirTempMap) / (
sizeof *AirTempMap));
1080 InitColor(SeaTempMap, (
sizeof SeaTempMap) / (
sizeof *SeaTempMap));
1081 InitColor(PrecipitationMap,
1082 (
sizeof PrecipitationMap) / (
sizeof *PrecipitationMap));
1083 InitColor(CloudMap, (
sizeof CloudMap) / (
sizeof *CloudMap));
1084 InitColor(CAPEMap, (
sizeof CAPEMap) / (
sizeof *CAPEMap));
1085 InitColor(REFCMap, (
sizeof REFCMap) / (
sizeof *REFCMap));
1086 InitColor(WindyMap, (
sizeof WindyMap) / (
sizeof *WindyMap));
1089void GRIBOverlayFactory::GetGraphicColor(
int settings,
double val_in,
1090 unsigned char &r,
unsigned char &g,
1092 int colormap_index = m_settings.Settings[settings].m_iOverlayMapColors;
1097 double min = m_settings.GetMin(settings), max = m_settings.GetMax(settings);
1100 val_in /= max - min;
1102 switch (colormap_index) {
1103 case CURRENT_GRAPHIC_INDEX:
1105 maplen = (
sizeof CurrentMap) / (
sizeof *CurrentMap);
1107 case GENERIC_GRAPHIC_INDEX:
1109 maplen = (
sizeof GenericMap) / (
sizeof *GenericMap);
1111 case WIND_GRAPHIC_INDEX:
1113 maplen = (
sizeof WindMap) / (
sizeof *WindMap);
1115 case AIRTEMP__GRAPHIC_INDEX:
1117 maplen = (
sizeof AirTempMap) / (
sizeof *AirTempMap);
1119 case SEATEMP_GRAPHIC_INDEX:
1121 maplen = (
sizeof SeaTempMap) / (
sizeof *SeaTempMap);
1123 case PRECIPITATION_GRAPHIC_INDEX:
1124 map = PrecipitationMap;
1125 maplen = (
sizeof PrecipitationMap) / (
sizeof *PrecipitationMap);
1127 case CLOUD_GRAPHIC_INDEX:
1129 maplen = (
sizeof CloudMap) / (
sizeof *CloudMap);
1131 case CAPE_GRAPHIC_INDEX:
1133 maplen = (
sizeof CAPEMap) / (
sizeof *CAPEMap);
1135 case REFC_GRAPHIC_INDEX:
1137 maplen = (
sizeof REFCMap) / (
sizeof *REFCMap);
1139 case WINDY_GRAPHIC_INDEX:
1141 maplen = (
sizeof WindyMap) / (
sizeof *WindyMap);
1148 double cmax = map[maplen - 1].val;
1150 for (
int i = 1; i < maplen; i++) {
1151 double nmapvala = map[i - 1].val / cmax;
1152 double nmapvalb = map[i].val / cmax;
1153 if (nmapvalb > val_in || i == maplen - 1) {
1154 if (m_gradual_colors) {
1155 double d = (val_in - nmapvala) / (nmapvalb - nmapvala);
1156 r = (1 - d) * map[i - 1].r + d * map[i].r;
1157 g = (1 - d) * map[i - 1].g + d * map[i].g;
1158 b = (1 - d) * map[i - 1].b + d * map[i].b;
1170wxColour GRIBOverlayFactory::GetGraphicColor(
int settings,
double val_in) {
1171 unsigned char r, g, b;
1172 GetGraphicColor(settings, val_in, r, g, b);
1176wxString GRIBOverlayFactory::GetLabelString(
double value,
int settings) {
1178 wxString f =
"%.*f";
1181 case GribOverlaySettings::PRESSURE:
1183 if (m_settings.Settings[settings].m_Units == 2)
1185 else if (m_settings.Settings[settings].m_Units == 0 &&
1186 m_settings.Settings[settings].m_bAbbrIsoBarsNumbers) {
1187 value -= floor(value / 100.) * 100.;
1191 case GribOverlaySettings::WAVE:
1192 case GribOverlaySettings::CURRENT:
1193 case GribOverlaySettings::AIR_TEMPERATURE:
1194 case GribOverlaySettings::SEA_TEMPERATURE:
1197 case GribOverlaySettings::PRECIPITATION:
1198 p = value < 100. ? 2 : value < 10. ? 1 : 0;
1199 p += m_settings.Settings[settings].m_Units == 1 ? 1 : 0;
1204 return wxString::Format(f, p, value);
1208wxImage &GRIBOverlayFactory::GetLabel(
double value,
int settings,
1209 wxColour back_color) {
1210 std::map<double, wxImage>::iterator it;
1211 it = m_label_cache.find(value);
1212 if (it != m_label_cache.end())
return m_label_cache[value];
1214 wxString labels = GetLabelString(value, settings);
1216 wxColour text_color;
1217 GetGlobalColor(_T (
"UBLCK" ), &text_color);
1218 wxPen penText(text_color);
1220 wxBrush backBrush(back_color);
1222 wxFont mfont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
1223 wxFONTWEIGHT_NORMAL);
1227 sdc.GetTextExtent(labels, &w, &h,
nullptr,
nullptr, &mfont);
1229 int label_offset = 5;
1231 wxBitmap bm(w + label_offset * 2, h + 2);
1236 mdc.SetPen(penText);
1237 mdc.SetBrush(backBrush);
1238 mdc.SetTextForeground(text_color);
1239 mdc.SetTextBackground(back_color);
1244 mdc.DrawRectangle(xd, yd, w + (label_offset * 2), h + 2);
1245 mdc.DrawText(labels, label_offset + xd, yd + 1);
1247 mdc.SelectObject(wxNullBitmap);
1249 m_label_cache[value] = bm.ConvertToImage();
1251 m_label_cache[value].InitAlpha();
1253 return m_label_cache[value];
1256double square(
double x) {
return x * x; }
1258void GRIBOverlayFactory::RenderGribBarbedArrows(
int settings,
GribRecord **pGR,
1260 if (!m_settings.Settings[settings].m_bBarbedArrows)
return;
1266 SettingsIdToGribId(settings, idx, idy, polar);
1267 if (idx < 0 || idy < 0)
return;
1272 if (!pGRX || !pGRY)
return;
1275 GetGlobalColor(_T (
"YELO2" ), &colour);
1281 glEnable(GL_LINE_SMOOTH);
1283 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1284 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
1290 glEnableClientState(GL_VERTEX_ARRAY);
1294 if (m_settings.Settings[settings].m_bBarbArrFixSpac) {
1297 adjustSpacing(m_settings.Settings[settings].m_iBarbArrSpacing);
1299 int total_spacing = space_pixels + arrowSize;
1305 double center_lat, center_lon;
1309 wxPoint offset_point(center.x + total_spacing, center.y + total_spacing);
1310 double offset_lat, offset_lon;
1314 double lat_spacing = fabs(center_lat - offset_lat);
1315 double lon_spacing = fabs(center_lon - offset_lon);
1319 double start_lat = floor(vp->
lat_min / lat_spacing) * lat_spacing;
1320 double start_lon = floor(vp->
lon_min / lon_spacing) * lon_spacing;
1323 double end_lat = vp->
lat_max + lat_spacing;
1324 double end_lon = vp->
lon_max + lon_spacing;
1327 for (
double lat = start_lat; lat <= end_lat; lat += lat_spacing) {
1328 for (
double lon = start_lon; lon <= end_lon; lon += lon_spacing) {
1336 DrawWindArrowWithBarbs(settings, p.x, p.y, vkn * 3.6 / 1.852,
1337 (ang - 90) * M_PI / 180, (lat < 0.), colour,
1344 double minspace = wxMax(m_settings.Settings[settings].m_iBarbArrSpacing,
1345 m_wind_arrow_size * 1.2);
1346 double minspace2 = square(minspace);
1349 int imax = pGRX->
GetNi();
1350 int jmax = pGRX->
GetNj();
1352 wxPoint firstpx(-1000, -1000);
1353 wxPoint oldpx(-1000, -1000);
1354 wxPoint oldpy(-1000, -1000);
1356 for (
int i = 0; i < imax; i++) {
1361 pGRX->
getXY(i, pGRX->
GetNj() / 2, &lonl, &latl);
1365 if (pl.x <= firstpx.x &&
1366 square(pl.x - firstpx.x) + square(pl.y - firstpx.y) <
1370 if (square(pl.x - oldpx.x) + square(pl.y - oldpx.y) < minspace2)
continue;
1373 if (i == 0) firstpx = pl;
1376 for (
int j = 0; j < jmax; j++) {
1377 double lat = pGRX->
GetY(j);
1379 if (!PointInLLBox(vp, lon, lat))
continue;
1384 if (square(p.x - oldpy.x) + square(p.y - oldpy.y) < minspace2)
continue;
1388 if (lon > 180) lon -= 360;
1393 if (vx != GRIB_NOTDEF && vy != GRIB_NOTDEF) {
1395 vkn = sqrt(vx * vx + vy * vy);
1396 ang = atan2(vy, -vx);
1397 DrawWindArrowWithBarbs(settings, p.x, p.y, vkn * 3.6 / 1.852, ang,
1405 if (!m_pdc) glDisableClientState(GL_VERTEX_ARRAY);
1409void GRIBOverlayFactory::RenderGribIsobar(
int settings,
GribRecord **pGR,
1410 wxArrayPtrVoid **pIsobarArray,
1412 if (!m_settings.Settings[settings].m_bIsoBars)
return;
1417 SettingsIdToGribId(settings, idx, idy, polar);
1418 if (idx < 0)
return;
1420 GribRecord *pGRA = pGR[idx], *pGRM =
nullptr;
1424 wxColour back_color;
1425 GetGlobalColor(_T (
"DILG1" ), &back_color);
1428 if (!pIsobarArray[idx]) {
1430 if (idy >= 0 && !polar && pGR[idy]) {
1431 pGRM = GribRecord::MagnitudeRecord(*pGR[idx], *pGR[idy]);
1432 if (!pGRM->IsOk()) {
1433 m_message_hiden.Append(_(
"IsoBar Unable to compute record magnitude"));
1440 pIsobarArray[idx] =
new wxArrayPtrVoid;
1443 wxGenericProgressDialog *progressdialog =
nullptr;
1444 wxDateTime start = wxDateTime::Now();
1446 double min = m_settings.GetMin(settings);
1447 double max = m_settings.GetMax(settings);
1450 double factor = (settings == GribOverlaySettings::PRESSURE &&
1451 m_settings.Settings[settings].m_Units == 2)
1455 for (
double press = min; press <= max;
1456 press += (m_settings.Settings[settings].m_iIsoBarSpacing * factor)) {
1458 progressdialog->Update(press - min);
1460 wxDateTime now = wxDateTime::Now();
1461 if ((now - start).GetSeconds() > 3 && press - min < (max - min) / 2) {
1462 progressdialog =
new wxGenericProgressDialog(
1463 _(
"Building Isobar map"), _(
"Wind"), max - min + 1,
nullptr,
1464 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME);
1469 m_settings.CalibrationFactor(settings, press,
true),
1470 m_settings.CalibrationOffset(settings), pGRA);
1472 pIsobarArray[idx]->Add(piso);
1474 delete progressdialog;
1480 for (
unsigned int i = 0; i < pIsobarArray[idx]->GetCount(); i++) {
1481 auto *piso = (
IsoLine *)pIsobarArray[idx]->Item(i);
1482 piso->drawIsoLine(
this, m_pdc, vp,
true);
1489 piso->drawIsoLineLabels(
this, m_pdc, vp, density, first,
1490 GetLabel(piso->getValue(), settings, back_color));
1492 piso->drawIsoLineLabelsGL(
this, vp, density, first,
1493 GetLabelString(piso->getValue(), settings),
1494 back_color, m_tex_font_numbers);
1498void GRIBOverlayFactory::FillGrid(
GribRecord *pGR) {
1500 int imax = pGR->
GetNi();
1501 int jmax = pGR->
GetNj();
1503 for (
int i = 0; i < imax; i++) {
1504 for (
int j = 1; j < jmax - 1; j++) {
1505 if (pGR->
GetValue(i, j) == GRIB_NOTDEF) {
1508 if (pGR->
GetValue(i, j - 1) != GRIB_NOTDEF) {
1512 if (pGR->
GetValue(i, j + 1) != GRIB_NOTDEF) {
1516 if (div > 1) pGR->SetValue(i, j, acc / div);
1521 for (
int j = 0; j < jmax; j++) {
1522 for (
int i = 1; i < imax - 1; i++) {
1523 if (pGR->
GetValue(i, j) == GRIB_NOTDEF) {
1526 if (pGR->
GetValue(i - 1, j) != GRIB_NOTDEF) {
1530 if (pGR->
GetValue(i + 1, j) != GRIB_NOTDEF) {
1534 if (div > 1) pGR->SetValue(i, j, acc / div);
1539 pGR->SetFilled(
true);
1542void GRIBOverlayFactory::RenderGribDirectionArrows(
int settings,
1545 if (!m_settings.Settings[settings].m_bDirectionArrows)
return;
1550 SettingsIdToGribId(settings, idx, idy, polar);
1551 if (idx < 0 || idy < 0)
return;
1555 if (!pGRX || !pGRY)
return;
1556 if (!pGRX->IsFilled()) FillGrid(pGRX);
1557 if (!pGRY->IsFilled()) FillGrid(pGRY);
1562 arrowSizeIdx = m_settings.Settings[settings].m_iDirectionArrowSize;
1563 if (arrowSizeIdx == 0) {
1564 if (m_pixel_mm > 0.2)
1567 arrowSize = 5. / m_pixel_mm;
1573 GetGlobalColor(_T (
"DILG3" ), &colour);
1577 if (m_pixel_mm > 0.2) {
1579 glEnable(GL_LINE_SMOOTH);
1581 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1582 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
1584 if (m_settings.Settings[settings].m_iDirectionArrowForm == 0)
1590 glEnableClientState(GL_VERTEX_ARRAY);
1594 if (m_settings.Settings[settings].m_bDirArrFixSpac) {
1597 adjustSpacing(m_settings.Settings[settings].m_iBarbArrSpacing);
1598 int arrow_size = 16;
1599 int total_spacing = space_pixels + arrow_size;
1605 double center_lat, center_lon;
1609 wxPoint offset_point(center.x + total_spacing, center.y + total_spacing);
1610 double offset_lat, offset_lon;
1614 double lat_spacing = fabs(center_lat - offset_lat);
1615 double lon_spacing = fabs(center_lon - offset_lon);
1619 double start_lat = floor(vp->
lat_min / lat_spacing) * lat_spacing;
1620 double start_lon = floor(vp->
lon_min / lon_spacing) * lon_spacing;
1623 double end_lat = vp->
lat_max + lat_spacing;
1624 double end_lon = vp->
lon_max + lon_spacing;
1627 for (
double lat = start_lat; lat <= end_lat; lat += lat_spacing) {
1628 for (
double lon = start_lon; lon <= end_lon; lon += lon_spacing) {
1640 if (dir == GRIB_NOTDEF || sh == GRIB_NOTDEF)
continue;
1644 scale = wxMax(1.0, sh);
1647 dir = (dir - 90) * M_PI / 180.;
1650 if (m_settings.Settings[settings].m_iDirectionArrowForm == 0)
1651 DrawSingleArrow(p.x, p.y, dir + vp->
rotation, colour, arrowWidth,
1652 arrowSizeIdx,
scale);
1653 else if (m_settings.Settings[settings].m_iDirectionArrowForm == 1)
1654 DrawDoubleArrow(p.x, p.y, dir + vp->
rotation, colour, arrowWidth,
1655 arrowSizeIdx,
scale);
1657 DrawSingleArrow(p.x, p.y, dir + vp->
rotation, colour,
1658 wxMax(1, wxMin(8, (
int)(sh + 0.5))), arrowSizeIdx,
1667 wxMax(m_settings.Settings[settings].m_iDirArrSpacing,
1668 m_settings.Settings[settings].m_iDirectionArrowSize * 1.2);
1669 double minspace2 = square(minspace);
1672 int imax = pGRX->
GetNi();
1673 int jmax = pGRX->
GetNj();
1675 wxPoint firstpx(-1000, -1000);
1676 wxPoint oldpx(-1000, -1000);
1677 wxPoint oldpy(-1000, -1000);
1679 for (
int i = 0; i < imax; i++) {
1681 pGRX->
getXY(i, pGRX->
GetNj() / 2, &lonl, &latl);
1686 if (pl.x <= firstpx.x &&
1687 square(pl.x - firstpx.x) + square(pl.y - firstpx.y) <
1691 if (square(pl.x - oldpx.x) + square(pl.y - oldpx.y) < minspace2)
continue;
1694 if (i == 0) firstpx = pl;
1696 for (
int j = 0; j < jmax; j++) {
1698 pGRX->
getXY(i, j, &lon, &lat);
1703 if (square(p.x - oldpy.x) + square(p.y - oldpy.y) >= minspace2) {
1706 if (lon > 180) lon -= 360;
1708 if (PointInLLBox(vp, lon, lat)) {
1709 double sh, dir, wdh;
1715 if (dir == GRIB_NOTDEF || sh == GRIB_NOTDEF)
continue;
1723 wdh = (8 / 2.5 * sh) + 0.5;
1724 scale = wxMax(1.0, sh);
1727 dir = (dir - 90) * M_PI / 180.;
1730 if (m_settings.Settings[settings].m_iDirectionArrowForm == 0)
1731 DrawSingleArrow(p.x, p.y, dir + vp->
rotation, colour, arrowWidth,
1732 arrowSizeIdx,
scale);
1733 else if (m_settings.Settings[settings].m_iDirectionArrowForm == 1)
1734 DrawDoubleArrow(p.x, p.y, dir + vp->
rotation, colour, arrowWidth,
1735 arrowSizeIdx,
scale);
1737 DrawSingleArrow(p.x, p.y, dir + vp->
rotation, colour,
1738 wxMax(1, wxMin(8, (
int)wdh)), arrowSizeIdx,
1747 if (!m_pdc) glDisableClientState(GL_VERTEX_ARRAY);
1751void GRIBOverlayFactory::RenderGribOverlayMap(
int settings,
GribRecord **pGR,
1753 if (!m_settings.Settings[settings].m_bOverlayMap)
return;
1755 const int grib_pixel_size = 4;
1758 SettingsIdToGribId(settings, idx, idy, polar);
1759 if (idx < 0 || !pGR[idx])
return;
1761 GribRecord *pGRA = pGR[idx], *pGRM =
nullptr;
1764 if (idy >= 0 && !polar && pGR[idy]) {
1765 pGRM = GribRecord::MagnitudeRecord(*pGR[idx], *pGR[idy]);
1766 if (!pGRM->IsOk()) {
1767 m_message_hiden.Append(
1768 _(
"OverlayMap Unable to compute record magnitude"));
1775 if (!pGRA->IsFilled()) FillGrid(pGRA);
1783 if (Intersect(vp, pGRA->GetLatMin(), pGRA->GetLatMax(), pGRA->GetLonMin(),
1784 pGRA->GetLonMax(), 0.) != _GOUT)
1786 if (Intersect(vp, pGRA->GetLatMin(), pGRA->GetLatMax(),
1787 pGRA->GetLonMin() - 360., pGRA->GetLonMax() - 360.,
1793 if (!m_pOverlay[settings]) m_pOverlay[settings] =
new GribOverlay;
1801 texture_format = GL_TEXTURE_2D;
1803 if (!texture_format)
1805 m_message_hiden.Append(
1806 _(
"Overlays not supported by this graphics hardware (Disable "
1809 if (!pGO->m_iTexture) CreateGribGLTexture(pGO, settings, pGRA);
1811 if (pGO->m_iTexture)
1812 DrawGLTexture(pGO, pGRA, vp);
1814 m_message_hiden.IsEmpty()
1816 .Append(_(
"Overlays too wide and can't be displayed:"))
1818 .Append(GribOverlaySettings::NameFromIndex(settings))
1819 : m_message_hiden.Append(
",").Append(
1820 GribOverlaySettings::NameFromIndex(settings));
1826 m_message_hiden.Append(_(
1827 "overlays suppressed if not north-up in DC mode (enable OpenGL)"));
1829 if (!pGO->m_pDCBitmap) {
1831 CreateGribImage(settings, pGRA, vp, grib_pixel_size, porg);
1832 if (bl_image.IsOk()) {
1834 pGO->m_pDCBitmap =
new wxBitmap(bl_image);
1835 auto *gr_mask =
new wxMask(*(pGO->m_pDCBitmap), wxColour(0, 0, 0));
1836 pGO->m_pDCBitmap->SetMask(gr_mask);
1840 if (pGO->m_pDCBitmap)
1841 m_pdc->DrawBitmap(*(pGO->m_pDCBitmap), porg.x, porg.y,
true);
1843 m_message_hiden.IsEmpty()
1846 "Please Zoom or Scale Out to view invisible overlays:"))
1848 .Append(GribOverlaySettings::NameFromIndex(settings))
1849 : m_message_hiden.Append(
",").Append(
1850 GribOverlaySettings::NameFromIndex(settings));
1858void GRIBOverlayFactory::RenderGribNumbers(
int settings,
GribRecord **pGR,
1860 if (!m_settings.Settings[settings].m_bNumbers)
return;
1865 SettingsIdToGribId(settings, idx, idy, polar);
1866 if (idx < 0)
return;
1868 GribRecord *pGRA = pGR[idx], *pGRM =
nullptr;
1873 if (idy >= 0 && !polar && pGR[idy]) {
1874 pGRM = GribRecord::MagnitudeRecord(*pGR[idx], *pGR[idy]);
1875 if (!pGRM->IsOk()) {
1876 m_message_hiden.Append(
1877 _(
"GribNumbers Unable to compute record magnitude"));
1886 m_tex_font_numbers.GetTextExtent(wxString(
"1234"), &wstring,
nullptr);
1888 if (m_settings.Settings[settings].m_bNumFixSpac) {
1891 int space = adjustSpacing(m_settings.Settings[settings].m_iNumbersSpacing);
1901 if (ptl.x >= pbr.x) {
1904 pbr.x = m_ParentSize.GetWidth();
1907 for (
int i = wxMax(ptl.x, 0); i < wxMin(pbr.x, m_ParentSize.GetWidth());
1908 i += (space + wstring)) {
1909 for (
int j = wxMax(ptl.y, 0); j < wxMin(pbr.y, m_ParentSize.GetHeight());
1910 j += (space + wstring)) {
1911 double lat, lon, val;
1914 if (val != GRIB_NOTDEF) {
1915 double value = m_settings.CalibrateValue(settings, val);
1916 wxColour back_color = GetGraphicColor(settings, value);
1918 DrawNumbers(wxPoint(i, j), value, settings, back_color);
1925 wxMax(m_settings.Settings[settings].m_iNumbersSpacing, wstring * 1.2);
1926 double minspace2 = square(minspace);
1929 int imax = pGRA->
GetNi();
1930 int jmax = pGRA->
GetNj();
1932 wxPoint firstpx(-1000, -1000);
1933 wxPoint oldpx(-1000, -1000);
1934 wxPoint oldpy(-1000, -1000);
1936 for (
int i = 0; i < imax; i++) {
1938 pGRA->
getXY(i, pGRA->
GetNj() / 2, &lonl, &latl);
1943 if (pl.x <= firstpx.x &&
1944 square(pl.x - firstpx.x) + square(pl.y - firstpx.y) <
1948 if (square(pl.x - oldpx.x) + square(pl.y - oldpx.y) >= minspace2) {
1950 if (i == 0) firstpx = pl;
1952 for (
int j = 0; j < jmax; j++) {
1954 pGRA->
getXY(i, j, &lon, &lat);
1959 if (square(p.x - oldpy.x) + square(p.y - oldpy.y) >= minspace2) {
1962 if (lon > 180) lon -= 360;
1964 if (PointInLLBox(vp, lon, lat)) {
1967 if (mag != GRIB_NOTDEF) {
1968 double value = m_settings.CalibrateValue(settings, mag);
1969 wxColour back_color = GetGraphicColor(settings, value);
1971 DrawNumbers(p, value, settings, back_color);
1983void GRIBOverlayFactory::DrawNumbers(wxPoint p,
double value,
int settings,
1984 wxColour back_color) {
1986 wxImage &label = GetLabel(value, settings, back_color);
1988 int w = label.GetWidth(), h = label.GetHeight();
1989 for (
int y = 0; y < h; y++)
1990 for (
int x = 0; x < w; x++)
1991 label.SetAlpha(x, y, m_settings.m_iOverlayTransparency);
1993 m_pdc->DrawBitmap(label, p.x, p.y,
true);
1999 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2000 glColor4ub(back_color.Red(), back_color.Green(), back_color.Blue(),
2001 m_settings.m_iOverlayTransparency);
2005 wxString label = GetLabelString(value, settings);
2007 m_tex_font_numbers.GetTextExtent(label, &w, &h);
2009 int label_offsetx = 5, label_offsety = 1;
2010 int x = p.x - label_offsetx, y = p.y - label_offsety;
2011 w += 2 * label_offsetx, h += 2 * label_offsety;
2016 glVertex2i(x + w, y);
2017 glVertex2i(x + w, y + h);
2018 glVertex2i(x, y + h);
2021 glColor4ub(0, 0, 0, m_settings.m_iOverlayTransparency);
2023 glBegin(GL_LINE_LOOP);
2025 glVertex2i(x + w, y);
2026 glVertex2i(x + w, y + h);
2027 glVertex2i(x, y + h);
2030 glEnable(GL_TEXTURE_2D);
2031 m_tex_font_numbers.RenderString(label, p.x, p.y);
2032 glDisable(GL_TEXTURE_2D);
2038 wxFont font(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
2039 wxFONTWEIGHT_NORMAL);
2042 wxString label = GetLabelString(value, settings);
2044 m_oDC->SetFont(font);
2046 m_oDC->GetTextExtent(label, &w, &h);
2048 int label_offsetx = 5, label_offsety = 1;
2049 int x = p.x - label_offsetx, y = p.y - label_offsety;
2050 w += 2 * label_offsetx, h += 2 * label_offsety;
2052 m_oDC->SetBrush(wxBrush(back_color));
2053 m_oDC->DrawRoundedRectangle(x, y, w, h, 0);
2056 m_oDC->SetPen(wxPen(wxColour(0, 0, 0), 1));
2057 m_oDC->DrawLine(x, y, x + w, y);
2058 m_oDC->DrawLine(x + w, y, x + w, y + h);
2059 m_oDC->DrawLine(x + w, y + h, x, y + h);
2060 m_oDC->DrawLine(x, y + h, x, y);
2062 m_oDC->DrawText(label, p.x, p.y);
2069void GRIBOverlayFactory::RenderGribParticles(
int settings,
GribRecord **pGR,
2071 if (!m_settings.Settings[settings].m_bParticles)
return;
2077 SettingsIdToGribId(settings, idx, idy, polar);
2078 if (idx < 0 || idy < 0)
return;
2083 if (!pGRX || !pGRY)
return;
2088 if (m_particle_map && m_particle_map->m_Setting != settings) ClearParticles();
2090 if (!m_particle_map) m_particle_map =
new ParticleMap(settings);
2092 std::vector<Particle> &particles = m_particle_map->m_Particles;
2094 const int max_duration = 50;
2095 const int run_count = 6;
2097 double density = m_settings.Settings[settings].m_dParticleDensity;
2100 int history_size = 27 / sqrt(density);
2101 history_size = wxMin(history_size, MAX_PARTICLE_HISTORY);
2103 std::vector<Particle>::iterator it;
2105 if (m_particle_map->history_size != history_size) {
2106 for (
unsigned int i = 0; i < particles.size(); i++) {
2108 if (m_particle_map->history_size > history_size &&
2109 particle.m_HistoryPos >= history_size) {
2110 particle = particles[particles.size() - 1];
2111 particles.pop_back();
2116 particle.m_HistorySize = particle.m_HistoryPos + 1;
2118 m_particle_map->history_size = history_size;
2126 for (it = particles.begin(); it != particles.end(); it++)
2127 for (
int i = 0; i < it->m_HistorySize; i++) {
2129 float(&p)[2] = n.m_Pos;
2130 if (p[0] == -10000)
continue;
2134 n.m_Screen[0] = ps.x;
2135 n.m_Screen[1] = ps.y;
2147 for (it = particles.begin(); it != particles.end(); it++)
2148 for (
int i = 0; i < it->m_HistorySize; i++) {
2150 float(&p)[2] = n.m_Pos;
2151 if (p[0] == -10000)
continue;
2153 n.m_Screen[0] += p1.x;
2154 n.m_Screen[1] += p1.y;
2162 if (m_update_particle_particles) {
2163 for (
unsigned int i = 0; i < particles.size(); i++) {
2167 if (++particle.m_Run < run_count)
continue;
2172 particle = particles[particles.size() - 1];
2173 particles.pop_back();
2180 float(&pp)[2] = particle.m_History[particle.m_HistoryPos].m_Pos;
2183 if (++particle.m_HistorySize > history_size)
2184 particle.m_HistorySize = history_size;
2186 if (++particle.m_HistoryPos >= history_size) particle.m_HistoryPos = 0;
2189 float(&p)[2] = n.m_Pos;
2190 double vkn = 0, ang;
2192 if (particle.
m_Duration < max_duration - history_size &&
2195 vkn > 0 && vkn < 100) {
2196 vkn = m_settings.CalibrateValue(settings, vkn);
2198 if (settings == GribOverlaySettings::CURRENT)
2199 d = vkn * run_count;
2201 d = vkn * run_count / 4;
2213 float angr = ang / 180 * M_PI;
2214 p[0] = pp[0] + sinf(angr) * d / 60;
2215 p[1] = pp[1] + cosf(angr) * d / 60;
2217 float angr = ang / 180 * M_PI;
2218 float latr = pp[1] * M_PI / 180;
2220 float sD = sinf(D), cD = cosf(D);
2221 float sy = sinf(latr), cy = cosf(latr);
2222 float sa = sinf(angr), ca = cosf(angr);
2224 p[0] = pp[0] + asinf(sa * sD / cy) * 180 / M_PI;
2225 p[1] = asinf(sy * cD + cy * sD * ca) * 180 / M_PI;
2230 n.m_Screen[0] = ps.x;
2231 n.m_Screen[1] = ps.y;
2233 wxColor c = GetGraphicColor(settings, vkn);
2235 n.m_Color[0] = c.Red();
2236 n.m_Color[1] = c.Green();
2237 n.m_Color[2] = c.Blue();
2243 m_update_particle_particles =
false;
2245 int total_particles = density * pGRX->
GetNi() * pGRX->
GetNj();
2248 if (total_particles > 60000) total_particles = 60000;
2251 int remove_particles = ((int)particles.size() - total_particles) / 16;
2252 for (
int i = 0; i < remove_particles; i++) particles.pop_back();
2256 int new_particles = (total_particles - (int)particles.size()) / 64;
2258 for (
int npi = 0; npi < new_particles; npi++) {
2261 for (
int i = 0; i < 20; i++) {
2263 p[0] =
static_cast<float>(rand()) /
static_cast<float>(RAND_MAX) *
2264 (pGRX->GetLonMax() - pGRX->GetLonMin()) +
2266 p[1] =
static_cast<float>(rand()) /
static_cast<float>(RAND_MAX) *
2267 (pGRX->GetLatMax() - pGRX->GetLatMin()) +
2271 vkn > 0 && vkn < 100)
2272 vkn = m_settings.CalibrateValue(settings, vkn);
2278 if (settings != GribOverlaySettings::CURRENT || vkn > 1 - (
double)i / 20)
2284 np.m_HistoryPos = 0;
2285 np.m_HistorySize = 1;
2287 if (run == run_count) run = 0;
2289 memcpy(np.m_History[np.m_HistoryPos].m_Pos, p,
sizeof p);
2293 np.m_History[np.m_HistoryPos].m_Screen[0] = ps.x;
2294 np.m_History[np.m_HistoryPos].m_Screen[1] = ps.y;
2296 wxColour c = GetGraphicColor(settings, vkn);
2297 np.m_History[np.m_HistoryPos].m_Color[0] = c.Red();
2298 np.m_History[np.m_HistoryPos].m_Color[1] = c.Green();
2299 np.m_History[np.m_HistoryPos].m_Color[2] = c.Blue();
2301 particles.push_back(np);
2307 glEnable(GL_LINE_SMOOTH);
2309 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2310 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
2315 unsigned char *&ca = m_particle_map->color_array;
2316 float *&va = m_particle_map->vertex_array;
2317 float *&caf = m_particle_map->color_float_array;
2319 if (m_particle_map->array_size < particles.size() && !m_pdc) {
2320 m_particle_map->array_size = 2 * particles.size();
2325 ca =
new unsigned char[m_particle_map->array_size * MAX_PARTICLE_HISTORY *
2327 caf =
new float[m_particle_map->array_size * MAX_PARTICLE_HISTORY * 8];
2328 va =
new float[m_particle_map->array_size * MAX_PARTICLE_HISTORY * 4];
2332 for (std::vector<Particle>::iterator particle = particles.begin();
2333 particle != particles.end(); particle++) {
2334 wxUint8 alpha = 250;
2336 int i = particle->m_HistoryPos;
2338 bool lip_valid =
false;
2339 float *lp =
nullptr, lip[2];
2344 float(&dp)[2] = particle->m_History[i].m_Pos;
2345 if (dp[0] != -10000) {
2346 float(&sp)[2] = particle->m_History[i].m_Screen;
2347 wxUint8(&ci)[3] = particle->m_History[i].m_Color;
2349 wxUint8 c[4] = {ci[0], ci[1], (
unsigned char)(ci[2] + 240 - alpha / 2),
2352 cf[0] = ci[0] / 256.;
2353 cf[1] = ci[1] / 256.;
2354 cf[2] = ((
unsigned char)(ci[2] + 240 - alpha / 2)) / 256.;
2355 cf[3] = alpha / 256.;
2357 if (lp && fabsf(lp[0] - sp[0]) < vp->
pix_width) {
2362 float d = (float)particle->m_Run / run_count;
2363 for (
int j = 0; j < 2; j++) sip[j] = d * lp[j] + (1 - d) * sp[j];
2365 if (lip_valid && fabsf(lip[0] - sip[0]) < vp->
pix_width) {
2367 m_pdc->SetPen(wxPen(wxColour(c[0], c[1], c[2]), 2));
2368 m_pdc->DrawLine(sip[0], sip[1], lip[0], lip[1]);
2370 memcpy(ca + 4 * cnt, c,
sizeof lc);
2371 memcpy(caf + 4 * cnt, cf,
sizeof lcf);
2372 memcpy(va + 2 * cnt, lip,
sizeof sp);
2374 memcpy(ca + 4 * cnt, lc,
sizeof c);
2375 memcpy(caf + 4 * cnt, lcf,
sizeof cf);
2376 memcpy(va + 2 * cnt, sip,
sizeof sp);
2381 memcpy(lip, sip,
sizeof lip);
2385 memcpy(lc, c,
sizeof lc);
2386 memcpy(lcf, cf,
sizeof lcf);
2392 i = history_size - 1;
2393 if (i >= particle->m_HistorySize)
break;
2396 if (i == particle->m_HistoryPos)
break;
2398 alpha -= 240 / history_size;
2404 m_oDC->DrawGLLineArray(cnt, va, caf, ca,
false);
2413 if (!m_pdc) glFlush();
2416 int time = sw.Time();
2420 m_particle_time_timer.Start(wxMax(50 - time, 2 * time), wxTIMER_ONE_SHOT);
2423 static int total_time;
2425 static int total_count;
2426 if(++total_count == 100) {
2427 printf(
"time: %.2f\n", (
double)total_time / total_count);
2428 total_time = total_count = 0;
2433void GRIBOverlayFactory::OnParticleTimer(wxTimerEvent &event) {
2434 m_update_particle_particles =
true;
2443void GRIBOverlayFactory::DrawProjectedPosition(
int x,
int y) {
2446 dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
2447 dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
2448 dc.DrawRectangle(x, y, 20, 20);
2449 dc.DrawLine(x, y, x + 20, y + 20);
2450 dc.DrawLine(x, y + 20, x + 20, y);
2453 m_oDC->SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
2454 m_oDC->SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
2455 m_oDC->DrawRectangle(x - 10, y - 10, 20, 20);
2456 m_oDC->StrokeLine(x - 10, y - 10, x + 10, y + 10);
2457 m_oDC->StrokeLine(x - 10, y + 10, x + 10, y - 10);
2462void GRIBOverlayFactory::DrawMessageWindow(wxString msg,
int x,
int y,
2464 if (msg.empty())
return;
2466 int ScaleBare_H = 30;
2471 dc.SetPen(*wxTRANSPARENT_PEN);
2473 dc.SetBrush(wxColour(243, 229, 47));
2475 dc.GetMultiLineTextExtent(msg, &w, &h);
2479 int label_offset = 10;
2480 int wdraw = w + (label_offset * 2);
2481 dc.DrawRectangle(0, yp, wdraw, h);
2482 dc.DrawLabel(msg, wxRect(label_offset, yp, wdraw, h),
2483 wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
2486 m_oDC->SetFont(*mfont);
2487 m_oDC->SetPen(*wxTRANSPARENT_PEN);
2489 m_oDC->SetBrush(wxColour(243, 229, 47));
2491 m_oDC->GetTextExtent(msg, &w, &h);
2494 int label_offset = 10;
2495 int wdraw = w + (label_offset * 2);
2496 wdraw *= g_ContentScaleFactor;
2497 h *= g_ContentScaleFactor;
2500 m_oDC->DrawRectangle(0, yp, wdraw, h);
2501 m_oDC->DrawText(msg, label_offset, yp);
2530void GRIBOverlayFactory::DrawDoubleArrow(
int x,
int y,
double ang,
2531 wxColour arrowColor,
int arrowWidth,
2532 int arrowSizeIdx,
double scale) {
2534 wxPen pen(arrowColor, 2);
2536 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
2537#if wxUSE_GRAPHICS_CONTEXT
2538 if (m_hi_def_graphics && m_gdc) m_gdc->SetPen(pen);
2542 wxPen pen(arrowColor, arrowWidth);
2547 DrawLineBuffer(m_double_arrow[arrowSizeIdx], x, y, ang,
scale);
2550void GRIBOverlayFactory::DrawSingleArrow(
int x,
int y,
double ang,
2551 wxColour arrowColor,
int arrowWidth,
2552 int arrowSizeIdx,
double scale) {
2554 wxPen pen(arrowColor, arrowWidth);
2556 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
2557#if wxUSE_GRAPHICS_CONTEXT
2558 if (m_hi_def_graphics && m_gdc) m_gdc->SetPen(pen);
2562 wxPen pen(arrowColor, arrowWidth);
2567 DrawLineBuffer(m_single_arrow[arrowSizeIdx], x, y, ang,
scale);
2570void GRIBOverlayFactory::DrawWindArrowWithBarbs(
int settings,
int x,
int y,
2571 double vkn,
double ang,
2572 bool south, wxColour arrowColor,
2573 double rotate_angle) {
2574 if (m_settings.Settings[settings].m_iBarbedColour == 1)
2575 arrowColor = GetGraphicColor(settings, vkn);
2581 float penWidth = .6 / m_pixel_mm;
2583 float penWidth = .4 / m_pixel_mm;
2585 penWidth = wxMin(penWidth, 3.0);
2588 wxPen pen(arrowColor, 2);
2590 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
2592#if wxUSE_GRAPHICS_CONTEXT
2593 if (m_hi_def_graphics && m_gdc) m_gdc->SetPen(pen);
2599 wxPen pen(arrowColor, penWidth);
2615 cacheidx = (int)(vkn + 2.5) / 5;
2617 cacheidx = (int)(vkn + 5) / 10 + 4;
2621 ang += rotate_angle;
2623 DrawLineBuffer(m_wind_arrow_cach_cache[cacheidx], x, y, ang, 1.0, south,
2624 m_draw_barbed_arrow_head);
2627void GRIBOverlayFactory::DrawLineBuffer(
LineBuffer &buffer,
int x,
int y,
2628 double ang,
double scale,
bool south,
2631 float six = sinf(ang), cox = cosf(ang), siy, coy;
2633 siy = -six, coy = -cox;
2635 siy = six, coy = cox;
2638 int count = buffer.count;
2643 wxASSERT(
sizeof vertexes /
sizeof *vertexes >= (
unsigned)count * 4);
2644 for (
int i = 0; i < 2 * count; i++) {
2646 if (!head && i > 1) j += 4;
2647 float *k = buffer.lines + 2 * j;
2648 vertexes[2 * i + 0] = k[0] * cox *
scale + k[1] * siy *
scale + x;
2649 vertexes[2 * i + 1] = k[0] * six *
scale - k[1] * coy *
scale + y;
2653 for (
int i = 0; i < count; i++) {
2654 float *l = vertexes + 4 * i;
2655#if wxUSE_GRAPHICS_CONTEXT
2656 if (m_hi_def_graphics && m_gdc)
2657 m_gdc->StrokeLine(l[0], l[1], l[2], l[3]);
2660 m_pdc->DrawLine(l[0], l[1], l[2], l[3]);
2665 for (
int i = 0; i < count; i++) {
2666 float *l = vertexes + 4 * i;
2667 if (m_hi_def_graphics)
2668 m_oDC->StrokeLine(l[0], l[1], l[2], l[3]);
2670 m_oDC->DrawLine(l[0], l[1], l[2], l[3]);
2685 double uv[],
double x,
double y,
2686 double width,
double height) {
2689 glEnable(texture_format);
2692 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2694 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
2699 coords[1] = -height;
2701 coords[3] = -height;
2707 extern int pi_texture_2D_shader_program;
2708 glUseProgram(pi_texture_2D_shader_program);
2711 GLint mPosAttrib = glGetAttribLocation(pi_texture_2D_shader_program,
"aPos");
2712 GLint mUvAttrib = glGetAttribLocation(pi_texture_2D_shader_program,
"aUV");
2715 GLint texUni = glGetUniformLocation(pi_texture_2D_shader_program,
"uTex");
2716 glUniform1i(texUni, 0);
2719 glBindBuffer(GL_ARRAY_BUFFER, 0);
2720 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2723 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords);
2725 glEnableVertexAttribArray(mPosAttrib);
2728 glVertexAttribPointer(mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, uv);
2730 glEnableVertexAttribArray(mUvAttrib);
2736 mat4x4_rotate_Z(Q, I, angle);
2743 glGetUniformLocation(pi_texture_2D_shader_program,
"TransformMatrix");
2744 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)Q);
2747 glActiveTexture(GL_TEXTURE0);
2754 GLushort indices1[] = {0,1,3,2};
2755 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
2778 glVertexAttribPointer(mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, co1);
2779 glVertexAttribPointer(mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, tco1);
2781 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2783 glDisable(GL_BLEND);
2784 glDisable(texture_format);
2788 glUniformMatrix4fv(matloc, 1, GL_FALSE, (
const GLfloat *)I);
2794 glColor4f(1, 1, 1, 1);
2795 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
2797 if (texture_format != GL_TEXTURE_2D) {
2798 for (
int i = 0; i < 4; i++) {
2799 uv[i * 2] *= pGR->
GetNi();
2800 uv[(i * 2) + 1] *= pGR->
GetNj();
2805 glTexCoord2d(uv[0], uv[1]), glVertex2f(x - width, y - height);
2806 glTexCoord2d(uv[2], uv[3]), glVertex2f(x, y - height);
2807 glTexCoord2d(uv[4], uv[5]), glVertex2f(x, y);
2808 glTexCoord2d(uv[6], uv[7]), glVertex2f(x - width, y);
2816 glEnable(texture_format);
2817 glBindTexture(texture_format, pGO->m_iTexture);
2820 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2822 double lat_min = pGR->GetLatMin(), lon_min = pGR->GetLonMin();
2824 bool repeat = pGR->GetLonMin() == 0 && pGR->GetLonMax() + pGR->
GetDi() == 360;
2847 xsquares = wxMax(xsquares, 2);
2848 ysquares = wxMax(ysquares, 2);
2851 double xs = vp->
pix_width / double(xsquares),
2854 typedef double mx[2][2];
2856 mx *lva =
new mx[xsquares + 1];
2857 int tw = pGO->m_iTextureDim[0], th = pGO->m_iTextureDim[1];
2858 double latstep = fabs(pGR->
GetDj()) / (th - 2 - 1) * (pGR->
GetNj() - 1);
2859 double lonstep = pGR->
GetDi() / (tw - 2 * !repeat - 1) * (pGR->
GetNi() - 1);
2861 double potNormX = (double)pGO->m_iTexDataDim[0] / tw;
2862 double potNormY = (double)pGO->m_iTexDataDim[1] / th;
2864 double clon = (lon_min + pGR->GetLonMax()) / 2;
2866 for (
double y = 0; y < vp->
pix_height + ys / 2; y += ys) {
2869 for (
double x = 0; x < vp->
pix_width + xs / 2; x += xs) {
2875 if (clon - lon > 180)
2877 else if (lon - clon > 180)
2882 (((lon - lon_min) / lonstep - repeat + 1.5) / tw) * potNormX;
2883 lva[i][j][1] = (((lat - lat_min) / latstep + 1.5) / th) * potNormY;
2885 if (pGR->
GetDj() < 0) lva[i][j][1] = 1 - lva[i][j][1];
2887 if (x > 0 && y > 0) {
2888 double u0 = lva[i - 1][!j][0], v0 = lva[i - 1][!j][1];
2889 double u1 = lva[i][!j][0], v1 = lva[i][!j][1];
2890 double u2 = lva[i][j][0], v2 = lva[i][j][1];
2891 double u3 = lva[i - 1][j][0], v3 = lva[i - 1][j][1];
2896 else if (u0 - u1 > .5)
2900 else if (u0 - u2 > .5)
2904 else if (u0 - u3 > .5)
2909 ((u0 >= 0 || u1 >= 0 || u2 >= 0 || u3 >= 0) &&
2910 (u0 <= 1 || u1 <= 1 || u2 <= 1 || u3 <= 1))) &&
2911 (v0 >= 0 || v1 >= 0 || v2 >= 0 || v3 >= 0) &&
2912 (v0 <= 1 || v1 <= 1 || v2 <= 1 || v3 <= 1)) {
2924 DrawSingleGLTexture(pGO, pGR, uv, x, y, xs, ys);
2935 glDisable(GL_BLEND);
2936 glDisable(texture_format);
void GetProjectedLatLon(int &x, int &y, PlugIn_ViewPort *vp)
Gets the projected position of vessel based on current course, speed and forecast time.
Container for rendered GRIB data visualizations in texture or bitmap form.
GribRecord * m_GribRecordPtrArray[Idx_COUNT]
Array of pointers to GRIB records representing different meteorological parameters.
A meteorological data grid from a GRIB (Gridded Binary) file.
int GetNj() const
Returns the number of points in the latitude (j) direction of the grid.
static bool GetInterpolatedValues(double &M, double &A, const GribRecord *GRX, const GribRecord *GRY, double px, double py, bool numericalInterpolation=true)
Gets spatially interpolated wind or current vector values at a specific latitude/longitude point.
void getXY(int i, int j, double *x, double *y) const
Converts grid indices to longitude/latitude coordinates.
double GetY(int j) const
Converts grid index j to latitude in degrees.
double GetValue(int i, int j) const
Returns the data value at a specific grid point.
double GetInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
int GetNi() const
Returns the number of points in the longitude (i) direction of the grid.
double GetDj() const
Returns the grid spacing in latitude (j) direction in degrees.
double GetDi() const
Returns the grid spacing in longitude (i) direction in degrees.
A specialized GribRecordSet that represents temporally interpolated weather data with isobar renderin...
wxArrayPtrVoid * m_IsobarArray[Idx_COUNT]
Array of cached isobar calculations for each data type (wind, pressure, etc).
Assembles input characters to lines.
Contains view parameters and status information for a chart display viewport.
double view_scale_ppm
Display scale in pixels per meter.
int pix_width
Viewport width in pixels.
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.
int pix_height
Viewport height in pixels.
double clat
Center latitude of the viewport in decimal degrees.
double skew
Display skew angle in radians.
double rotation
Display rotation angle in radians.
bool bValid
True if this viewport is valid and can be used for rendering.
double lon_min
Minimum longitude of the viewport.
double lat_min
Minimum latitude of the viewport.
int m_projection_type
Chart projection type (PROJECTION_MERCATOR, etc.)
GRIB Data Visualization and Rendering Factory.
@ Idx_COMP_REFL
Composite radar reflectivity in dBZ (decibel relative to Z)
@ Idx_PRECIP_TOT
Precipitation data in millimeters per hour.
@ Idx_AIR_TEMP
Air temperature at 2m in Kelvin (K)
@ Idx_PRESSURE
Surface pressure in Pascal (Pa)
@ Idx_WVDIR
Wave direction.
@ Idx_CLOUD_TOT
Total cloud cover in % (percent, range 0-100%)
@ Idx_WIND_GUST
Wind gust speed at surface in m/s.
@ Idx_WIND_VX
Surface wind velocity X component in m/s.
@ Idx_HTSIGW
Significant wave height in meters.
@ Idx_SEACURRENT_VY
Sea current velocity Y component in m/s.
@ Idx_SEA_TEMP
Sea surface temperature in Kelvin (K)
@ Idx_WIND_VY
Surface wind velocity Y component in m/s.
@ Idx_SEACURRENT_VX
Sea current velocity X component in m/s.
@ Idx_CAPE
Convective Available Potential Energy in J/kg (Joules per kilogram)
GRIB Weather Data Control Interface.
@ PI_PROJECTION_MERCATOR
Mercator projection, standard for navigation charts.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
int GetCanvasCount()
Gets total number of chart canvases.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
wxFont GetOCPNGUIScaledFont_PlugIn(wxString item)
Gets a uniquely scaled font copy for responsive UI elements.
void PositionBearingDistanceMercator_Plugin(double lat, double lon, double brg, double dist, double *dlat, double *dlon)
Calculates destination point given starting point, bearing and distance.
double PlugInGetDisplaySizeMM()
Gets physical display size in millimeters.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.
int GetChartbarHeight()
Gets height of chart bar in pixels.
wxWindow * GetCanvasByIndex(int canvasIndex)
Gets chart canvas window by index.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
void GetCanvasLLPix(PlugIn_ViewPort *vp, wxPoint p, double *plat, double *plon)
Converts canvas physical pixel coordinates to lat/lon.
OpenGL Platform Abstraction Layer.
Manager for particle animation system.
Individual particle for wind/current animation.
int m_Duration
Duration this particle should exist in animation cycles.
Graphics abstraction layer on top of wxDC or OpenGL.