33#include <wx/graphics.h>
39#ifdef __OCPN__ANDROID__
45wxList ocpn_wx_spline_point_list;
47#include <wx/listimpl.cpp>
48WX_DEFINE_LIST(MySegList);
49WX_DEFINE_LIST(MySegListList);
59 double xmin, xmax, ymin, ymax;
61void CompOutCode(
double x,
double y, outcode *code,
66 *code = 1L << ((long)TOP);
67 else if (y < LINK->ymin)
68 *code = 1L << ((long)BOTTOM);
70 *code |= 1L << ((long)RIGHT);
71 else if (x < LINK->xmin)
72 *code |= 1L << ((long)LEFT);
75ClipResult cohen_sutherland_line_clip_d(
double *x0,
double *y0,
double *x1,
76 double *y1,
double xmin_,
double xmax_,
77 double ymin_,
double ymax_) {
82 ClipResult clip = Visible;
83 outcode outcode0, outcode1, outcodeOut;
85 double x = 0., y = 0.;
91 CompOutCode(*x0, *y0, &outcode0, &V);
92 CompOutCode(*x1, *y1, &outcode1, &V);
94 if (outcode0 == 0 && outcode1 == 0) {
96 }
else if ((outcode0 & outcode1) != 0) {
107 outcodeOut = outcode0;
109 outcodeOut = outcode1;
113 if (((1L << ((
long)TOP)) & outcodeOut) != 0) {
115 x = *x0 + (*x1 - *x0) * (V.ymax - *y0) / (*y1 - *y0);
117 }
else if (((1L << ((
long)BOTTOM)) & outcodeOut) != 0) {
119 x = *x0 + (*x1 - *x0) * (V.ymin - *y0) / (*y1 - *y0);
121 }
else if (((1L << ((
long)RIGHT)) & outcodeOut) != 0) {
123 y = *y0 + (*y1 - *y0) * (V.xmax - *x0) / (*x1 - *x0);
125 }
else if (((1L << ((
long)LEFT)) & outcodeOut) != 0) {
127 y = *y0 + (*y1 - *y0) * (V.xmin - *x0) / (*x1 - *x0);
132 if (outcodeOut == outcode0) {
135 CompOutCode(*x0, *y0, &outcode0, &V);
139 CompOutCode(*x1, *y1, &outcode1, &V);
146ClipResult cohen_sutherland_line_clip_i(
int *x0_,
int *y0_,
int *x1_,
int *y1_,
147 int xmin_,
int xmax_,
int ymin_,
150 double x0, y0, x1, y1;
156 cohen_sutherland_line_clip_d(&x0, &y0, &x1, &y1, (
double)xmin_,
157 (
double)xmax_, (
double)ymin_, (
double)ymax_);
165double round_msvc(
double x) {
return (floor(x + 0.5)); }
170 if (wxGetDisplaySize().x > 0) {
172 m_pixelMM = wxMax(.02, m_pixelMM);
176 value = val / coeff - offset;
184 extractIsoLine(rec_);
188 if (trace.size() == 0)
return;
194 std::list<Segment *>::iterator it;
195 for (it = trace.begin(); it != trace.end(); it++) {
198 m_seglist.Append(*it);
205 MySegList *ps = BuildContinuousSegment();
207 m_SegListList.Append(ps);
209 MySegList::Node *node;
214 node = m_seglist.GetFirst();
216 seg = node->GetData();
218 m_seglist.Erase(node);
219 node = m_seglist.GetFirst();
221 node = node->GetNext();
224 if (0 == m_seglist.GetCount()) bdone =
true;
235 std::list<Segment *>::iterator it;
236 for (it = trace.begin(); it != trace.end(); it++) {
242 m_SegListList.DeleteContents(
true);
243 m_SegListList.Clear();
246MySegList *IsoLine::BuildContinuousSegment(
void) {
247 MySegList::Node *node;
250 MySegList *ret_list =
new MySegList;
257 node = m_seglist.GetFirst();
258 Segment *seg0 = node->GetData();
260 segjoin2.Append(seg0);
267 node = m_seglist.GetFirst();
269 seg = node->GetData();
271 if ((!seg->bUsed) && (seg->py1 == tseg->py2) &&
272 (seg->px1 == tseg->px2))
275 segjoin2.Append(seg);
278 }
else if ((!seg->bUsed) && (seg->py2 == tseg->py2) &&
279 (seg->px2 == tseg->px2))
288 segjoin2.Append(seg);
293 node = node->GetNext();
306 node = m_seglist.GetFirst();
307 seg0 = node->GetData();
309 segjoin1.Append(seg0);
315 node = m_seglist.GetFirst();
317 seg = node->GetData();
319 if ((!seg->bUsed) && (seg->py2 == tseg->py1) &&
320 (seg->px2 == tseg->px1))
323 segjoin1.Append(seg);
326 }
else if ((!seg->bUsed) && (seg->py1 == tseg->py1) &&
327 (seg->px1 == tseg->px1))
336 segjoin1.Append(seg);
341 node = node->GetNext();
354 int n1 = segjoin1.GetCount();
355 for (
int i = n1 - 1; i > 0; i--) {
356 node = segjoin1.Item(i);
357 seg = node->GetData();
358 ret_list->Append(seg);
362 int n2 = segjoin2.GetCount();
363 for (
int i = 0; i < n2; i++) {
364 node = segjoin2.Item(i);
365 seg = node->GetData();
366 ret_list->Append(seg);
377 int nsegs = trace.size();
378 if (nsegs < 1)
return;
380 GetGlobalColor(_T (
"UITX1" ), &isoLineColor);
382#if wxUSE_GRAPHICS_CONTEXT
383 wxGraphicsContext *pgc =
nullptr;
387 wxPen ppISO(isoLineColor, 2);
389#if wxUSE_GRAPHICS_CONTEXT
391 pmdc =
dynamic_cast<wxMemoryDC *
>(dc);
392 pgc = wxGraphicsContext::Create(*pmdc);
414 wxPen ppISO(isoLineColor, 2);
415 pof->m_oDC->SetPen(ppISO);
420 std::list<Segment *>::iterator it;
425 for (it = trace.begin(); it != trace.end(); it++) {
431 double sx1 = seg->px1, sx2 = seg->px2;
434 else if (sx1 - sx2 > 180)
437 if ((sx1 + 180 < vp->
clon && sx2 + 180 > vp->
clon) ||
438 (sx1 + 180 > vp->
clon && sx2 + 180 < vp->
clon) ||
439 (sx1 - 180 < vp->
clon && sx2 - 180 > vp->
clon) ||
440 (sx1 - 180 > vp->
clon && sx2 - 180 < vp->
clon))
450#if wxUSE_GRAPHICS_CONTEXT
452 pgc->StrokeLine(ab.x, ab.y, cd.x, cd.y);
455 dc->DrawLine(ab.x, ab.y, cd.x, cd.y);
460 pof->m_oDC->DrawLine(ab.x, ab.y, cd.x, cd.y);
467#if wxUSE_GRAPHICS_CONTEXT
482 std::list<Segment *>::iterator it;
490 for (it = trace.begin(); it != trace.end(); it++, nb++) {
491 if (nb % density == 0) {
502 int w = imageLabel.GetWidth();
503 int h = imageLabel.GetHeight();
505 int label_offset = 6;
506 int xd = (ab.x + cd.x - (w + label_offset * 2)) / 2;
507 int yd = (ab.y + cd.y - h) / 2;
509 int x = xd - label_offset;
510 wxRect r(x, yd, w, h);
512 if (!prev.Intersects(r)) {
517 wxImage img(w, h, imageLabel.GetData(),
true);
518 dc->DrawBitmap(img, xd, yd,
false);
526 int density,
int first, wxString label,
527 wxColour &color,
TexFont &texfont)
530 std::list<Segment *>::iterator it;
535 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
541 for (it = trace.begin(); it != trace.end(); it++, nb++) {
542 if (nb % density == 0) {
554 texfont.GetTextExtent(label, &w, &h);
556 int label_offsetx = 6, label_offsety = 1;
557 int xd = (ab.x + cd.x - (w + label_offsetx * 2)) / 2;
558 int yd = (ab.y + cd.y - h) / 2;
559 int x = xd - label_offsetx, y = yd - label_offsety;
560 w += 2 * label_offsetx, h += 2 * label_offsety;
562 wxRect r(x, y, w, h);
564 if (!prev.Intersects(r)) {
569 pof->m_oDC->SetPen(*wxBLACK_PEN);
570 pof->m_oDC->SetBrush(color);
571 pof->m_oDC->DrawRectangle(x, y, w, h);
572 pof->m_oDC->DrawText(label, xd, yd);
577 glColor4ub(color.Red(), color.Green(), color.Blue(), color.Alpha());
582 glVertex2i(x + w, y);
583 glVertex2i(x + w, y + h);
584 glVertex2i(x, y + h);
589 glBegin(GL_LINE_LOOP);
591 glVertex2i(x + w, y);
592 glVertex2i(x + w, y + h);
593 glVertex2i(x, y + h);
596 glEnable(GL_TEXTURE_2D);
597 texfont.RenderString(label, xd, yd);
598 glDisable(GL_TEXTURE_2D);
611Segment::Segment(
int I,
int w,
int J,
char c1,
char c2,
char c3,
char c4,
613 traduitCode(I, w, J, c1, i, j);
614 traduitCode(I, w, J, c2, k, l);
615 traduitCode(I, w, J, c3, m, n);
616 traduitCode(I, w, J, c4, o, p);
618 intersectionAreteGrille(i, j, k, l, &px1, &py1, rec, pressure);
619 intersectionAreteGrille(m, n, o, p, &px2, &py2, rec, pressure);
622void Segment::intersectionAreteGrille(
int i,
int j,
int k,
int l,
double *x,
625 double xa, xb, ya, yb, pa, pb, dec;
629 rec->
getXY(i, j, &xa, &ya);
630 rec->
getXY(k, l, &xb, &yb);
634 dec = (pressure - pa) / (pb - pa);
637 if (fabs(dec) > 1) dec = 0.5;
647 dec = (pressure - pa) / (pb - pa);
650 if (fabs(dec) > 1) dec = 0.5;
651 *y = ya + (yb - ya) * dec;
654void Segment::traduitCode(
int I,
int w,
int J,
char c1,
int &i,
int &j) {
655 int Im1 = I ? I - 1 : w - 1;
683void IsoLine::extractIsoLine(
const GribRecord *rec) {
690 if (rec->getLonMax() + rec->
getDi() - rec->getLonMin() == 360) We++;
692 for (j = 1; j < H; j++)
696 for (i = 1; i < We; i++, a = b, c = d) {
705 if (a == GRIB_NOTDEF || b == GRIB_NOTDEF || c == GRIB_NOTDEF ||
709 if ((a < value && b < value && c < value && d < value) ||
710 (a > value && b > value && c > value && d > value))
719 if ((a <= value && b <= value && c <= value && d > value) ||
720 (a > value && b > value && c > value && d <= value))
721 trace.push_back(
new Segment(ni, W, j,
'c',
'd',
'b',
'd', rec, value));
722 else if ((a <= value && c <= value && d <= value && b > value) ||
723 (a > value && c > value && d > value && b <= value))
724 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'b',
'd', rec, value));
725 else if ((c <= value && d <= value && b <= value && a > value) ||
726 (c > value && d > value && b > value && a <= value))
727 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'a',
'c', rec, value));
728 else if ((a <= value && b <= value && d <= value && c > value) ||
729 (a > value && b > value && d > value && c <= value))
730 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'c',
'd', rec, value));
734 else if ((a <= value && b <= value && c > value && d > value) ||
735 (a > value && b > value && c <= value && d <= value))
736 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'b',
'd', rec, value));
737 else if ((a <= value && c <= value && b > value && d > value) ||
738 (a > value && c > value && b <= value && d <= value))
739 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'c',
'd', rec, value));
743 else if (a <= value && d <= value && c > value && b > value) {
744 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'b',
'd', rec, value));
745 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'c',
'd', rec, value));
746 }
else if (a > value && d > value && c <= value && b <= value) {
747 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'a',
'c', rec, value));
748 trace.push_back(
new Segment(ni, W, j,
'b',
'd',
'c',
'd', rec, value));
761void ocpn_wx_quadratic_spline(
double a1,
double b1,
double a2,
double b2,
762 double a3,
double b3,
double a4,
double b4);
763void ocpn_wx_clear_stack();
764int ocpn_wx_spline_pop(
double *x1,
double *y1,
double *x2,
double *y2,
765 double *x3,
double *y3,
double *x4,
double *y4);
766void ocpn_wx_spline_push(
double x1,
double y1,
double x2,
double y2,
double x3,
767 double y3,
double x4,
double y4);
768static bool ocpn_wx_spline_add_point(
double x,
double y);
770#define half(z1, z2) ((z1 + z2) / 2.0)
775void ocpn_wx_quadratic_spline(
double a1,
double b1,
double a2,
double b2,
776 double a3,
double b3,
double a4,
double b4) {
778 double x1, y1, x2, y2, x3, y3, x4, y4;
780 ocpn_wx_clear_stack();
781 ocpn_wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
783 while (ocpn_wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
784 xmid = (double)half(x2, x3);
785 ymid = (double)half(y2, y3);
786 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
787 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
788 ocpn_wx_spline_add_point(x1, y1);
789 ocpn_wx_spline_add_point(xmid, ymid);
791 ocpn_wx_spline_push(xmid, ymid, (
double)half(xmid, x3),
792 (
double)half(ymid, y3), (
double)half(x3, x4),
793 (
double)half(y3, y4), x4, y4);
794 ocpn_wx_spline_push(x1, y1, (
double)half(x1, x2), (
double)half(y1, y2),
795 (
double)half(x2, xmid), (
double)half(y2, ymid), xmid,
804 double x1, y1, x2, y2, x3, y3, x4, y4;
807#define SPLINE_STACK_DEPTH 20
808static Stack ocpn_wx_spline_stack[SPLINE_STACK_DEPTH];
809static Stack *ocpn_wx_stack_top;
810static int ocpn_wx_stack_count;
812void ocpn_wx_clear_stack() {
813 ocpn_wx_stack_top = ocpn_wx_spline_stack;
814 ocpn_wx_stack_count = 0;
817void ocpn_wx_spline_push(
double x1,
double y1,
double x2,
double y2,
double x3,
818 double y3,
double x4,
double y4) {
819 ocpn_wx_stack_top->x1 = x1;
820 ocpn_wx_stack_top->y1 = y1;
821 ocpn_wx_stack_top->x2 = x2;
822 ocpn_wx_stack_top->y2 = y2;
823 ocpn_wx_stack_top->x3 = x3;
824 ocpn_wx_stack_top->y3 = y3;
825 ocpn_wx_stack_top->x4 = x4;
826 ocpn_wx_stack_top->y4 = y4;
828 ocpn_wx_stack_count++;
831int ocpn_wx_spline_pop(
double *x1,
double *y1,
double *x2,
double *y2,
832 double *x3,
double *y3,
double *x4,
double *y4) {
833 if (ocpn_wx_stack_count == 0)
return (0);
835 ocpn_wx_stack_count--;
836 *x1 = ocpn_wx_stack_top->x1;
837 *y1 = ocpn_wx_stack_top->y1;
838 *x2 = ocpn_wx_stack_top->x2;
839 *y2 = ocpn_wx_stack_top->y2;
840 *x3 = ocpn_wx_stack_top->x3;
841 *y3 = ocpn_wx_stack_top->y3;
842 *x4 = ocpn_wx_stack_top->x4;
843 *y4 = ocpn_wx_stack_top->y4;
847static bool ocpn_wx_spline_add_point(
double x,
double y) {
848 wxPoint *point =
new wxPoint;
851 ocpn_wx_spline_point_list.Append((wxObject *)point);
855void GenSpline(wxList *points) {
857 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
858 double x1, y1, x2, y2;
860 wxList::compatibility_iterator node = points->GetFirst();
865 p = (wxPoint *)node->GetData();
870 node = node->GetNext();
871 p = (wxPoint *)node->GetData();
875 cx1 = (double)((x1 + x2) / 2);
876 cy1 = (double)((y1 + y2) / 2);
877 cx2 = (double)((cx1 + x2) / 2);
878 cy2 = (double)((cy1 + y2) / 2);
880 ocpn_wx_spline_add_point(x1, y1);
882 while ((node = node->GetNext())
887 p = (wxPoint *)node->GetData();
892 cx4 = (double)(x1 + x2) / 2;
893 cy4 = (double)(y1 + y2) / 2;
894 cx3 = (double)(x1 + cx4) / 2;
895 cy3 = (double)(y1 + cy4) / 2;
897 ocpn_wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
901 cx2 = (double)(cx1 + x2) / 2;
902 cy2 = (double)(cy1 + y2) / 2;
905 ocpn_wx_spline_add_point(cx1, cy1);
906 ocpn_wx_spline_add_point(x2, y2);
910static void GenerateSpline(
int n, wxPoint points[])
913 for (
int i =0; i < n; i++)
915 list.Append((wxObject*)&points[i]);
921static void ClearSplineList()
923 wxList::compatibility_iterator node = ocpn_wx_spline_point_list.GetFirst();
926 wxPoint *point = (wxPoint *)node->GetData();
928 ocpn_wx_spline_point_list.Erase(node);
929 node = ocpn_wx_spline_point_list.GetFirst();
GRIB Data Visualization and Rendering Factory.
GRIB Display Settings Configuration Interface.
GRIB Isobar and Isoline Generation System.
Factory class for creating and managing GRIB data visualizations.
Represents a meteorological data grid from a GRIB (Gridded Binary) file.
double getDi() const
Returns the grid spacing in longitude (i) direction in degrees.
void getXY(int i, int j, double *x, double *y) const
Converts grid indices to longitude/latitude coordinates.
int getNi() const
Returns the number of points in the longitude (i) direction of the grid.
int getNj() const
Returns the number of points in the latitude (j) direction of the grid.
double getValue(int i, int j) const
Returns the data value at a specific grid point.
IsoLine(double val, double coeff, double offset, const GribRecord *rec)
Contains view parameters and status information for a chart display viewport.
double clon
Center longitude of the viewport in decimal degrees.
int m_projection_type
Chart projection type (PROJECTION_MERCATOR, etc.)
@ PI_PROJECTION_MERCATOR
Mercator projection, standard for navigation charts.
@ PI_PROJECTION_EQUIRECTANGULAR
Equirectangular/Plate Carrée projection, simple lat/lon grid.
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.
OpenGL Platform Abstraction Layer.