35#include <wx/graphics.h>
47wxList ocpn_wx_spline_point_list;
49#include <wx/listimpl.cpp>
50WX_DEFINE_LIST(MySegList);
51WX_DEFINE_LIST(MySegListList);
61 double xmin, xmax, ymin, ymax;
63void CompOutCode(
double x,
double y, outcode *code,
68 *code = 1L << ((long)TOP);
69 else if (y < LINK->ymin)
70 *code = 1L << ((long)BOTTOM);
72 *code |= 1L << ((long)RIGHT);
73 else if (x < LINK->xmin)
74 *code |= 1L << ((long)LEFT);
77ClipResult cohen_sutherland_line_clip_d(
double *x0,
double *y0,
double *x1,
78 double *y1,
double xmin_,
double xmax_,
79 double ymin_,
double ymax_) {
84 ClipResult clip = Visible;
85 outcode outcode0, outcode1, outcodeOut;
87 double x = 0., y = 0.;
93 CompOutCode(*x0, *y0, &outcode0, &V);
94 CompOutCode(*x1, *y1, &outcode1, &V);
96 if (outcode0 == 0 && outcode1 == 0) {
98 }
else if ((outcode0 & outcode1) != 0) {
109 outcodeOut = outcode0;
111 outcodeOut = outcode1;
115 if (((1L << ((
long)TOP)) & outcodeOut) != 0) {
117 x = *x0 + (*x1 - *x0) * (V.ymax - *y0) / (*y1 - *y0);
119 }
else if (((1L << ((
long)BOTTOM)) & outcodeOut) != 0) {
121 x = *x0 + (*x1 - *x0) * (V.ymin - *y0) / (*y1 - *y0);
123 }
else if (((1L << ((
long)RIGHT)) & outcodeOut) != 0) {
125 y = *y0 + (*y1 - *y0) * (V.xmax - *x0) / (*x1 - *x0);
127 }
else if (((1L << ((
long)LEFT)) & outcodeOut) != 0) {
129 y = *y0 + (*y1 - *y0) * (V.xmin - *x0) / (*x1 - *x0);
134 if (outcodeOut == outcode0) {
137 CompOutCode(*x0, *y0, &outcode0, &V);
141 CompOutCode(*x1, *y1, &outcode1, &V);
148ClipResult cohen_sutherland_line_clip_i(
int *x0_,
int *y0_,
int *x1_,
int *y1_,
149 int xmin_,
int xmax_,
int ymin_,
152 double x0, y0, x1, y1;
158 cohen_sutherland_line_clip_d(&x0, &y0, &x1, &y1, (
double)xmin_,
159 (
double)xmax_, (
double)ymin_, (
double)ymax_);
167double round_msvc(
double x) {
return (floor(x + 0.5)); }
172 if (wxGetDisplaySize().x > 0) {
174 m_pixelMM = wxMax(.02, m_pixelMM);
178 value = val / coeff - offset;
186 extractIsoLine(rec_);
190 if (trace.size() == 0)
return;
196 std::list<Segment *>::iterator it;
197 for (it = trace.begin(); it != trace.end(); it++) {
200 m_seglist.Append(*it);
207 MySegList *ps = BuildContinuousSegment();
209 m_SegListList.Append(ps);
211 MySegList::Node *node;
216 node = m_seglist.GetFirst();
218 seg = node->GetData();
220 m_seglist.Erase(node);
221 node = m_seglist.GetFirst();
223 node = node->GetNext();
226 if (0 == m_seglist.GetCount()) bdone =
true;
237 std::list<Segment *>::iterator it;
238 for (it = trace.begin(); it != trace.end(); it++) {
244 m_SegListList.DeleteContents(
true);
245 m_SegListList.Clear();
248MySegList *IsoLine::BuildContinuousSegment(
void) {
249 MySegList::Node *node;
252 MySegList *ret_list =
new MySegList;
259 node = m_seglist.GetFirst();
260 Segment *seg0 = node->GetData();
262 segjoin2.Append(seg0);
269 node = m_seglist.GetFirst();
271 seg = node->GetData();
273 if ((!seg->bUsed) && (seg->py1 == tseg->py2) &&
274 (seg->px1 == tseg->px2))
277 segjoin2.Append(seg);
280 }
else if ((!seg->bUsed) && (seg->py2 == tseg->py2) &&
281 (seg->px2 == tseg->px2))
290 segjoin2.Append(seg);
295 node = node->GetNext();
308 node = m_seglist.GetFirst();
309 seg0 = node->GetData();
311 segjoin1.Append(seg0);
317 node = m_seglist.GetFirst();
319 seg = node->GetData();
321 if ((!seg->bUsed) && (seg->py2 == tseg->py1) &&
322 (seg->px2 == tseg->px1))
325 segjoin1.Append(seg);
328 }
else if ((!seg->bUsed) && (seg->py1 == tseg->py1) &&
329 (seg->px1 == tseg->px1))
338 segjoin1.Append(seg);
343 node = node->GetNext();
356 int n1 = segjoin1.GetCount();
357 for (
int i = n1 - 1; i > 0; i--) {
358 node = segjoin1.Item(i);
359 seg = node->GetData();
360 ret_list->Append(seg);
364 int n2 = segjoin2.GetCount();
365 for (
int i = 0; i < n2; i++) {
366 node = segjoin2.Item(i);
367 seg = node->GetData();
368 ret_list->Append(seg);
379 int nsegs = trace.size();
380 if (nsegs < 1)
return;
382 GetGlobalColor(_T (
"UITX1" ), &isoLineColor);
384#if wxUSE_GRAPHICS_CONTEXT
385 wxGraphicsContext *pgc =
nullptr;
389 wxPen ppISO(isoLineColor, 2);
391#if wxUSE_GRAPHICS_CONTEXT
393 pmdc =
dynamic_cast<wxMemoryDC *
>(dc);
394 pgc = wxGraphicsContext::Create(*pmdc);
416 wxPen ppISO(isoLineColor, 2);
417 pof->m_oDC->SetPen(ppISO);
422 std::list<Segment *>::iterator it;
427 for (it = trace.begin(); it != trace.end(); it++) {
433 double sx1 = seg->px1, sx2 = seg->px2;
436 else if (sx1 - sx2 > 180)
439 if ((sx1 + 180 < vp->
clon && sx2 + 180 > vp->
clon) ||
440 (sx1 + 180 > vp->
clon && sx2 + 180 < vp->
clon) ||
441 (sx1 - 180 < vp->
clon && sx2 - 180 > vp->
clon) ||
442 (sx1 - 180 > vp->
clon && sx2 - 180 < vp->
clon))
452#if wxUSE_GRAPHICS_CONTEXT
454 pgc->StrokeLine(ab.x, ab.y, cd.x, cd.y);
457 dc->DrawLine(ab.x, ab.y, cd.x, cd.y);
462 pof->m_oDC->DrawLine(ab.x, ab.y, cd.x, cd.y);
469#if wxUSE_GRAPHICS_CONTEXT
484 std::list<Segment *>::iterator it;
492 for (it = trace.begin(); it != trace.end(); it++, nb++) {
493 if (nb % density == 0) {
504 int w = imageLabel.GetWidth();
505 int h = imageLabel.GetHeight();
507 int label_offset = 6;
508 int xd = (ab.x + cd.x - (w + label_offset * 2)) / 2;
509 int yd = (ab.y + cd.y - h) / 2;
511 int x = xd - label_offset;
512 wxRect r(x, yd, w, h);
514 if (!prev.Intersects(r)) {
519 wxImage img(w, h, imageLabel.GetData(),
true);
520 dc->DrawBitmap(img, xd, yd,
false);
528 int density,
int first, wxString label,
529 wxColour &color,
TexFont &texfont)
532 std::list<Segment *>::iterator it;
537 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
543 for (it = trace.begin(); it != trace.end(); it++, nb++) {
544 if (nb % density == 0) {
556 texfont.GetTextExtent(label, &w, &h);
558 int label_offsetx = 6, label_offsety = 1;
559 int xd = (ab.x + cd.x - (w + label_offsetx * 2)) / 2;
560 int yd = (ab.y + cd.y - h) / 2;
561 int x = xd - label_offsetx, y = yd - label_offsety;
562 w += 2 * label_offsetx, h += 2 * label_offsety;
564 wxRect r(x, y, w, h);
566 if (!prev.Intersects(r)) {
571 pof->m_oDC->SetPen(*wxBLACK_PEN);
572 pof->m_oDC->SetBrush(color);
573 pof->m_oDC->DrawRectangle(x, y, w, h);
574 pof->m_oDC->DrawText(label, xd, yd);
579 glColor4ub(color.Red(), color.Green(), color.Blue(), color.Alpha());
584 glVertex2i(x + w, y);
585 glVertex2i(x + w, y + h);
586 glVertex2i(x, y + h);
591 glBegin(GL_LINE_LOOP);
593 glVertex2i(x + w, y);
594 glVertex2i(x + w, y + h);
595 glVertex2i(x, y + h);
598 glEnable(GL_TEXTURE_2D);
599 texfont.RenderString(label, xd, yd);
600 glDisable(GL_TEXTURE_2D);
613Segment::Segment(
int I,
int w,
int J,
char c1,
char c2,
char c3,
char c4,
615 traduitCode(I, w, J, c1, i, j);
616 traduitCode(I, w, J, c2, k, l);
617 traduitCode(I, w, J, c3, m, n);
618 traduitCode(I, w, J, c4, o, p);
620 intersectionAreteGrille(i, j, k, l, &px1, &py1, rec, pressure);
621 intersectionAreteGrille(m, n, o, p, &px2, &py2, rec, pressure);
624void Segment::intersectionAreteGrille(
int i,
int j,
int k,
int l,
double *x,
627 double xa, xb, ya, yb, pa, pb, dec;
631 rec->
getXY(i, j, &xa, &ya);
632 rec->
getXY(k, l, &xb, &yb);
636 dec = (pressure - pa) / (pb - pa);
639 if (fabs(dec) > 1) dec = 0.5;
649 dec = (pressure - pa) / (pb - pa);
652 if (fabs(dec) > 1) dec = 0.5;
653 *y = ya + (yb - ya) * dec;
656void Segment::traduitCode(
int I,
int w,
int J,
char c1,
int &i,
int &j) {
657 int Im1 = I ? I - 1 : w - 1;
685void IsoLine::extractIsoLine(
const GribRecord *rec) {
692 if (rec->GetLonMax() + rec->
GetDi() - rec->GetLonMin() == 360) We++;
694 for (j = 1; j < H; j++)
698 for (i = 1; i < We; i++, a = b, c = d) {
707 if (a == GRIB_NOTDEF || b == GRIB_NOTDEF || c == GRIB_NOTDEF ||
711 if ((a < value && b < value && c < value && d < value) ||
712 (a > value && b > value && c > value && d > value))
721 if ((a <= value && b <= value && c <= value && d > value) ||
722 (a > value && b > value && c > value && d <= value))
723 trace.push_back(
new Segment(ni, W, j,
'c',
'd',
'b',
'd', rec, value));
724 else if ((a <= value && c <= value && d <= value && b > value) ||
725 (a > value && c > value && d > value && b <= value))
726 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'b',
'd', rec, value));
727 else if ((c <= value && d <= value && b <= value && a > value) ||
728 (c > value && d > value && b > value && a <= value))
729 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'a',
'c', rec, value));
730 else if ((a <= value && b <= value && d <= value && c > value) ||
731 (a > value && b > value && d > value && c <= value))
732 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'c',
'd', rec, value));
736 else if ((a <= value && b <= value && c > value && d > value) ||
737 (a > value && b > value && c <= value && d <= value))
738 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'b',
'd', rec, value));
739 else if ((a <= value && c <= value && b > value && d > value) ||
740 (a > value && c > value && b <= value && d <= value))
741 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'c',
'd', rec, value));
745 else if (a <= value && d <= value && c > value && b > value) {
746 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'b',
'd', rec, value));
747 trace.push_back(
new Segment(ni, W, j,
'a',
'c',
'c',
'd', rec, value));
748 }
else if (a > value && d > value && c <= value && b <= value) {
749 trace.push_back(
new Segment(ni, W, j,
'a',
'b',
'a',
'c', rec, value));
750 trace.push_back(
new Segment(ni, W, j,
'b',
'd',
'c',
'd', rec, value));
763void ocpn_wx_quadratic_spline(
double a1,
double b1,
double a2,
double b2,
764 double a3,
double b3,
double a4,
double b4);
765void ocpn_wx_clear_stack();
766int ocpn_wx_spline_pop(
double *x1,
double *y1,
double *x2,
double *y2,
767 double *x3,
double *y3,
double *x4,
double *y4);
768void ocpn_wx_spline_push(
double x1,
double y1,
double x2,
double y2,
double x3,
769 double y3,
double x4,
double y4);
770static bool ocpn_wx_spline_add_point(
double x,
double y);
772#define half(z1, z2) ((z1 + z2) / 2.0)
777void ocpn_wx_quadratic_spline(
double a1,
double b1,
double a2,
double b2,
778 double a3,
double b3,
double a4,
double b4) {
780 double x1, y1, x2, y2, x3, y3, x4, y4;
782 ocpn_wx_clear_stack();
783 ocpn_wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
785 while (ocpn_wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
786 xmid = (double)half(x2, x3);
787 ymid = (double)half(y2, y3);
788 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
789 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
790 ocpn_wx_spline_add_point(x1, y1);
791 ocpn_wx_spline_add_point(xmid, ymid);
793 ocpn_wx_spline_push(xmid, ymid, (
double)half(xmid, x3),
794 (
double)half(ymid, y3), (
double)half(x3, x4),
795 (
double)half(y3, y4), x4, y4);
796 ocpn_wx_spline_push(x1, y1, (
double)half(x1, x2), (
double)half(y1, y2),
797 (
double)half(x2, xmid), (
double)half(y2, ymid), xmid,
806 double x1, y1, x2, y2, x3, y3, x4, y4;
809#define SPLINE_STACK_DEPTH 20
810static Stack ocpn_wx_spline_stack[SPLINE_STACK_DEPTH];
811static Stack *ocpn_wx_stack_top;
812static int ocpn_wx_stack_count;
814void ocpn_wx_clear_stack() {
815 ocpn_wx_stack_top = ocpn_wx_spline_stack;
816 ocpn_wx_stack_count = 0;
819void ocpn_wx_spline_push(
double x1,
double y1,
double x2,
double y2,
double x3,
820 double y3,
double x4,
double y4) {
821 ocpn_wx_stack_top->x1 = x1;
822 ocpn_wx_stack_top->y1 = y1;
823 ocpn_wx_stack_top->x2 = x2;
824 ocpn_wx_stack_top->y2 = y2;
825 ocpn_wx_stack_top->x3 = x3;
826 ocpn_wx_stack_top->y3 = y3;
827 ocpn_wx_stack_top->x4 = x4;
828 ocpn_wx_stack_top->y4 = y4;
830 ocpn_wx_stack_count++;
833int ocpn_wx_spline_pop(
double *x1,
double *y1,
double *x2,
double *y2,
834 double *x3,
double *y3,
double *x4,
double *y4) {
835 if (ocpn_wx_stack_count == 0)
return (0);
837 ocpn_wx_stack_count--;
838 *x1 = ocpn_wx_stack_top->x1;
839 *y1 = ocpn_wx_stack_top->y1;
840 *x2 = ocpn_wx_stack_top->x2;
841 *y2 = ocpn_wx_stack_top->y2;
842 *x3 = ocpn_wx_stack_top->x3;
843 *y3 = ocpn_wx_stack_top->y3;
844 *x4 = ocpn_wx_stack_top->x4;
845 *y4 = ocpn_wx_stack_top->y4;
849static bool ocpn_wx_spline_add_point(
double x,
double y) {
850 wxPoint *point =
new wxPoint;
853 ocpn_wx_spline_point_list.Append((wxObject *)point);
857void GenSpline(wxList *points) {
859 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
860 double x1, y1, x2, y2;
862 wxList::compatibility_iterator node = points->GetFirst();
867 p = (wxPoint *)node->GetData();
872 node = node->GetNext();
873 p = (wxPoint *)node->GetData();
877 cx1 = (double)((x1 + x2) / 2);
878 cy1 = (double)((y1 + y2) / 2);
879 cx2 = (double)((cx1 + x2) / 2);
880 cy2 = (double)((cy1 + y2) / 2);
882 ocpn_wx_spline_add_point(x1, y1);
884 while ((node = node->GetNext())
889 p = (wxPoint *)node->GetData();
894 cx4 = (double)(x1 + x2) / 2;
895 cy4 = (double)(y1 + y2) / 2;
896 cx3 = (double)(x1 + cx4) / 2;
897 cy3 = (double)(y1 + cy4) / 2;
899 ocpn_wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
903 cx2 = (double)(cx1 + x2) / 2;
904 cy2 = (double)(cy1 + y2) / 2;
907 ocpn_wx_spline_add_point(cx1, cy1);
908 ocpn_wx_spline_add_point(x2, y2);
912static void GenerateSpline(
int n, wxPoint points[])
915 for (
int i =0; i < n; i++)
917 list.Append((wxObject*)&points[i]);
923static void ClearSplineList()
925 wxList::compatibility_iterator node = ocpn_wx_spline_point_list.GetFirst();
928 wxPoint *point = (wxPoint *)node->GetData();
930 ocpn_wx_spline_point_list.Erase(node);
931 node = ocpn_wx_spline_point_list.GetFirst();
Factory class for creating and managing GRIB data visualizations.
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.
void getXY(int i, int j, double *x, double *y) const
Converts grid indices to longitude/latitude coordinates.
double GetValue(int i, int j) const
Returns the data value at a specific grid point.
int GetNi() const
Returns the number of points in the longitude (i) direction of the grid.
double GetDi() const
Returns the grid spacing in longitude (i) direction in degrees.
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.)
GRIB Data Visualization and Rendering Factory.
GRIB Display Settings Configuration Interface.
GRIB Isobar and Isoline Generation System.
@ 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.