OpenCPN Partial API docs
Loading...
Searching...
No Matches
iso_line.cpp
Go to the documentation of this file.
1/**********************************************************************
2zyGrib: meteorological GRIB file viewer
3Copyright (C) 2008 - Jacques Zaninetti - http://www.zygrib.org
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17***********************************************************************/
18
24
25#include "pi_gl.h" // Must included before anything using GL stuff
26
27#include "wx/wxprec.h"
28
29#ifndef WX_PRECOMP
30#include "wx/wx.h"
31#endif // precompiled headers
32
33// #include "chcanv.h"
34// #include "model/georef.h"
35#include <wx/graphics.h>
36
37#include "iso_line.h"
38#include "grib_settings_dlg.h"
40
41#ifdef __ANDROID__
42#include "qdebug.h"
43#endif
44
45// static void GenerateSpline(int n, wxPoint points[]);
46// static void ClearSplineList();
47wxList ocpn_wx_spline_point_list;
48
49#include <wx/listimpl.cpp>
50WX_DEFINE_LIST(MySegList);
51WX_DEFINE_LIST(MySegListList);
52
53#ifndef PI
54#define PI 3.14159
55#endif
56#define CTRUE -1
57#define CFALSE 0
58
59/* Local variables for cohen_sutherland_line_clip: */
61 double xmin, xmax, ymin, ymax;
62};
63void CompOutCode(double x, double y, outcode *code,
64 struct LOC_cohen_sutherland_line_clip *LINK) {
65 /*Compute outcode for the point (x,y) */
66 *code = 0;
67 if (y > LINK->ymax)
68 *code = 1L << ((long)TOP);
69 else if (y < LINK->ymin)
70 *code = 1L << ((long)BOTTOM);
71 if (x > LINK->xmax)
72 *code |= 1L << ((long)RIGHT);
73 else if (x < LINK->xmin)
74 *code |= 1L << ((long)LEFT);
75}
76
77ClipResult cohen_sutherland_line_clip_d(double *x0, double *y0, double *x1,
78 double *y1, double xmin_, double xmax_,
79 double ymin_, double ymax_) {
80 /* Cohen-Sutherland clipping algorithm for line P0=(x1,y0) to P1=(x1,y1)
81 * and clip rectangle with diagonal from (xmin,ymin) to (xmax,ymax).*/
83 int done = CFALSE;
84 ClipResult clip = Visible;
85 outcode outcode0, outcode1, outcodeOut;
86 /*Outcodes for P0,P1, and whichever point lies outside the clip rectangle*/
87 double x = 0., y = 0.;
88
89 V.xmin = xmin_;
90 V.xmax = xmax_;
91 V.ymin = ymin_;
92 V.ymax = ymax_;
93 CompOutCode(*x0, *y0, &outcode0, &V);
94 CompOutCode(*x1, *y1, &outcode1, &V);
95 do {
96 if (outcode0 == 0 && outcode1 == 0) { /*Trivial accept and exit*/
97 done = CTRUE;
98 } else if ((outcode0 & outcode1) != 0) {
99 clip = Invisible;
100 done = CTRUE;
101 }
102 /*Logical intersection is true, so trivial reject and exit.*/
103 else {
104 clip = Visible;
105 /*Failed both tests, so calculate the line segment to clip;
106 * from an outside point to an intersection with clip edge.*/
107 /*At least one endpoint is outside the clip rectangle; pick it.*/
108 if (outcode0 != 0)
109 outcodeOut = outcode0;
110 else
111 outcodeOut = outcode1;
112 /*Now find intersection point;
113 * use formulas y=y0+slope*(x-x0),x=x0+(1/slope)*(y-y0).*/
114
115 if (((1L << ((long)TOP)) & outcodeOut) != 0) {
116 /*Divide line at top of clip rectangle*/
117 x = *x0 + (*x1 - *x0) * (V.ymax - *y0) / (*y1 - *y0);
118 y = V.ymax;
119 } else if (((1L << ((long)BOTTOM)) & outcodeOut) != 0) {
120 /*Divide line at bottom of clip rectangle*/
121 x = *x0 + (*x1 - *x0) * (V.ymin - *y0) / (*y1 - *y0);
122 y = V.ymin;
123 } else if (((1L << ((long)RIGHT)) & outcodeOut) != 0) {
124 /*Divide line at right edge of clip rectangle*/
125 y = *y0 + (*y1 - *y0) * (V.xmax - *x0) / (*x1 - *x0);
126 x = V.xmax;
127 } else if (((1L << ((long)LEFT)) & outcodeOut) != 0) {
128 /*Divide line at left edge of clip rectangle*/
129 y = *y0 + (*y1 - *y0) * (V.xmin - *x0) / (*x1 - *x0);
130 x = V.xmin;
131 }
132 /*Now we move outside point to intersection point to clip,
133 * and get ready for next pass.*/
134 if (outcodeOut == outcode0) {
135 *x0 = x;
136 *y0 = y;
137 CompOutCode(*x0, *y0, &outcode0, &V);
138 } else {
139 *x1 = x;
140 *y1 = y;
141 CompOutCode(*x1, *y1, &outcode1, &V);
142 }
143 }
144 } while (!done);
145 return clip;
146}
147
148ClipResult cohen_sutherland_line_clip_i(int *x0_, int *y0_, int *x1_, int *y1_,
149 int xmin_, int xmax_, int ymin_,
150 int ymax_) {
151 ClipResult ret;
152 double x0, y0, x1, y1;
153 x0 = *x0_;
154 y0 = *y0_;
155 x1 = *x1_;
156 y1 = *y1_;
157 ret =
158 cohen_sutherland_line_clip_d(&x0, &y0, &x1, &y1, (double)xmin_,
159 (double)xmax_, (double)ymin_, (double)ymax_);
160 *x0_ = (int)x0;
161 *y0_ = (int)y0;
162 *x1_ = (int)x1;
163 *y1_ = (int)y1;
164 return ret;
165}
166
167double round_msvc(double x) { return (floor(x + 0.5)); }
168
169//---------------------------------------------------------------
170IsoLine::IsoLine(double val, double coeff, double offset,
171 const GribRecord *rec_) {
172 if (wxGetDisplaySize().x > 0) {
173 m_pixelMM = PlugInGetDisplaySizeMM() / wxGetDisplaySize().x;
174 m_pixelMM = wxMax(.02, m_pixelMM); // protect against bad data
175 } else
176 m_pixelMM = 0.27; // semi-standard number...
177
178 value = val / coeff - offset;
179
180 rec = rec_;
181 W = rec_->GetNi();
182 H = rec_->GetNj();
183
184 //---------------------------------------------------------
185 // Génère la liste des segments.
186 extractIsoLine(rec_);
187
188 value = val;
189
190 if (trace.size() == 0) return;
191
192 // Join the isoline segments into a nice list
193 // Which is end-to-end continuous and unidirectional
194
195 // Create a master wxList of the trace list
196 std::list<Segment *>::iterator it;
197 for (it = trace.begin(); it != trace.end(); it++) {
198 Segment *seg = *it;
199 seg->bUsed = false;
200 m_seglist.Append(*it);
201 }
202
203 // Isoline may be discontinuous....
204 // So build a list of continuous segments
205 bool bdone = false;
206 while (!bdone) {
207 MySegList *ps = BuildContinuousSegment();
208
209 m_SegListList.Append(ps);
210
211 MySegList::compatibility_iterator node;
212 Segment *seg;
213
214 // recreate the master list, removing used segs
215
216 node = m_seglist.GetFirst();
217 while (node) {
218 seg = node->GetData();
219 if (seg->bUsed) {
220 m_seglist.Erase(node);
221 node = m_seglist.GetFirst();
222 } else
223 node = node->GetNext();
224 }
225
226 if (0 == m_seglist.GetCount()) bdone = true;
227 }
228
231}
232//---------------------------------------------------------------
233IsoLine::~IsoLine() {
234 // printf("delete Isobar : press=%4.0f long=%d\n", pressure/100,
235 // trace.size());
236
237 std::list<Segment *>::iterator it;
238 for (it = trace.begin(); it != trace.end(); it++) {
239 delete *it;
240 *it = nullptr;
241 }
242 trace.clear();
243
244 m_SegListList.DeleteContents(true);
245 m_SegListList.Clear();
246}
247
248MySegList *IsoLine::BuildContinuousSegment(void) {
249 MySegList::compatibility_iterator node;
250 Segment *seg;
251
252 MySegList *ret_list = new MySegList;
253
254 // Build a chain extending from the "2" end of the target segment
255 // The joined list, side 2...
256 MySegList segjoin2;
257
258 // Add any first segment to the list
259 node = m_seglist.GetFirst();
260 Segment *seg0 = node->GetData();
261 seg0->bUsed = true;
262 segjoin2.Append(seg0);
263
264 Segment *tseg = seg0;
265
266 while (tseg) {
267 bool badded = false;
268 Segment *seg;
269 node = m_seglist.GetFirst();
270 while (node) {
271 seg = node->GetData();
272
273 if ((!seg->bUsed) && (seg->py1 == tseg->py2) &&
274 (seg->px1 == tseg->px2)) // fits without reverse
275 {
276 seg->bUsed = true;
277 segjoin2.Append(seg);
278 badded = true;
279 break;
280 } else if ((!seg->bUsed) && (seg->py2 == tseg->py2) &&
281 (seg->px2 == tseg->px2)) // fits, needs reverse
282 {
283 seg->bUsed = true;
284 double a = seg->px2;
285 seg->px2 = seg->px1;
286 seg->px1 = a;
287 double b = seg->py2;
288 seg->py2 = seg->py1;
289 seg->py1 = b;
290 segjoin2.Append(seg);
291 badded = true;
292 break;
293 }
294
295 node = node->GetNext();
296 }
297 if (badded == true)
298 tseg = seg;
299 else
300 tseg = nullptr;
301 }
302
303 // Build a chain extending from the "1" end of the target segment
304 // The joined list, side 1...
305 MySegList segjoin1;
306
307 // Add the same first segment to the list
308 node = m_seglist.GetFirst();
309 seg0 = node->GetData();
310 seg0->bUsed = true;
311 segjoin1.Append(seg0);
312
313 tseg = seg0;
314
315 while (tseg) {
316 bool badded = false;
317 node = m_seglist.GetFirst();
318 while (node) {
319 seg = node->GetData();
320
321 if ((!seg->bUsed) && (seg->py2 == tseg->py1) &&
322 (seg->px2 == tseg->px1)) // fits without reverse
323 {
324 seg->bUsed = true;
325 segjoin1.Append(seg);
326 badded = true;
327 break;
328 } else if ((!seg->bUsed) && (seg->py1 == tseg->py1) &&
329 (seg->px1 == tseg->px1)) // fits, needs reverse
330 {
331 seg->bUsed = true;
332 double a = seg->px2;
333 seg->px2 = seg->px1;
334 seg->px1 = a;
335 double b = seg->py2;
336 seg->py2 = seg->py1;
337 seg->py1 = b;
338 segjoin1.Append(seg);
339 badded = true;
340 break;
341 }
342
343 node = node->GetNext();
344 }
345 if (badded == true)
346 tseg = seg;
347 else
348 tseg = nullptr;
349 }
350
351 // Now have two lists...
352
353 // Start with "1" side list,
354 // starting from the end, and skipping the first segment
355
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);
361 }
362
363 // Now add the "2"side list
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);
369 }
370
371 // And there it is
372
373 return ret_list;
374}
375
376//---------------------------------------------------------------
377void IsoLine::drawIsoLine(GRIBOverlayFactory *pof, wxDC *dc,
378 PlugIn_ViewPort *vp, bool bHiDef) {
379 int nsegs = trace.size();
380 if (nsegs < 1) return;
381
382 GetGlobalColor(_T ( "UITX1" ), &isoLineColor);
383
384#if wxUSE_GRAPHICS_CONTEXT
385 wxGraphicsContext *pgc = nullptr;
386#endif
387
388 if (dc) {
389 wxPen ppISO(isoLineColor, 2);
390
391#if wxUSE_GRAPHICS_CONTEXT
392 wxMemoryDC *pmdc;
393 pmdc = dynamic_cast<wxMemoryDC *>(dc);
394 pgc = wxGraphicsContext::Create(*pmdc);
395 pgc->SetPen(ppISO);
396#endif
397 dc->SetPen(ppISO);
398 } else { /* opengl */
399#ifdef ocpnUSE_GL
400 // #ifndef USE_ANDROID_GLES2
401 // if(m_pixelMM > 0.2){ // pixel size large enough to
402 // render well
403 // // Enable anti-aliased lines, at best quality
404 // glEnable( GL_LINE_SMOOTH );
405 // glEnable( GL_BLEND );
406 // glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
407 // glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
408 // glLineWidth( 2 );
409 // }
410 // else{
411 // glLineWidth( 0.4/m_pixelMM); // set a target line
412 // width by MM
413 // }
414 // #else
415 if (pof->m_oDC) {
416 wxPen ppISO(isoLineColor, 2);
417 pof->m_oDC->SetPen(ppISO);
418 }
419#endif
420 }
421
422 std::list<Segment *>::iterator it;
423
424 //---------------------------------------------------------
425 // Dessine les segments
426 //---------------------------------------------------------
427 for (it = trace.begin(); it != trace.end(); it++) {
428 Segment *seg = *it;
429
432 /* skip segments that go the wrong way around the world */
433 double sx1 = seg->px1, sx2 = seg->px2;
434 if (sx2 - sx1 > 180)
435 sx2 -= 360;
436 else if (sx1 - sx2 > 180)
437 sx1 -= 360;
438
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))
443 continue;
444 }
445
446 wxPoint ab;
447 GetCanvasPixLL(vp, &ab, seg->py1, seg->px1);
448 wxPoint cd;
449 GetCanvasPixLL(vp, &cd, seg->py2, seg->px2);
450
451 if (dc) {
452#if wxUSE_GRAPHICS_CONTEXT
453 if (bHiDef && pgc)
454 pgc->StrokeLine(ab.x, ab.y, cd.x, cd.y);
455 else
456#endif
457 dc->DrawLine(ab.x, ab.y, cd.x, cd.y);
458 } else { /* opengl */
459#ifdef ocpnUSE_GL
460
461 if (pof->m_oDC) {
462 pof->m_oDC->DrawLine(ab.x, ab.y, cd.x, cd.y);
463 }
464
465#endif
466 }
467 }
468
469#if wxUSE_GRAPHICS_CONTEXT
470 delete pgc;
471#endif
472
473 // if(!dc) /* opengl */
474 // glEnd();
475}
476
477//---------------------------------------------------------------
478
479void IsoLine::drawIsoLineLabels(GRIBOverlayFactory *pof, wxDC *dc,
480 PlugIn_ViewPort *vp, int density, int first,
481 wxImage &imageLabel)
482
483{
484 std::list<Segment *>::iterator it;
485 int nb = first;
486 wxString label;
487
488 //---------------------------------------------------------
489 // Ecrit les labels
490 //---------------------------------------------------------
491 wxRect prev;
492 for (it = trace.begin(); it != trace.end(); it++, nb++) {
493 if (nb % density == 0) {
494 Segment *seg = *it;
495
496 // if(vp->vpBBox.PointInBox((seg->px1 + seg->px2)/2., (seg->py1
497 // + seg->py2)/2., 0.))
498 {
499 wxPoint ab;
500 GetCanvasPixLL(vp, &ab, seg->py1, seg->px1);
501 wxPoint cd;
502 GetCanvasPixLL(vp, &cd, seg->py1, seg->px1);
503
504 int w = imageLabel.GetWidth();
505 int h = imageLabel.GetHeight();
506
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;
510
511 int x = xd - label_offset;
512 wxRect r(x, yd, w, h);
513 r.Inflate(w);
514 if (!prev.Intersects(r)) {
515 prev = r;
516
517 /* don't use alpha for isobars, for some reason draw bitmap ignores
518 the 4th argument (true or false has same result) */
519 wxImage img(w, h, imageLabel.GetData(), true);
520 dc->DrawBitmap(img, xd, yd, false);
521 }
522 }
523 }
524 }
525}
526
527void IsoLine::drawIsoLineLabelsGL(GRIBOverlayFactory *pof, PlugIn_ViewPort *vp,
528 int density, int first, wxString label,
529 wxColour &color, TexFont &texfont)
530
531{
532 std::list<Segment *>::iterator it;
533 int nb = first;
534
535#ifdef ocpnUSE_GL
536 glEnable(GL_BLEND);
537 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
538
539 //---------------------------------------------------------
540 // Ecrit les labels
541 //---------------------------------------------------------
542 wxRect prev;
543 for (it = trace.begin(); it != trace.end(); it++, nb++) {
544 if (nb % density == 0) {
545 Segment *seg = *it;
546
547 // if(vp->vpBBox.PointInBox((seg->px1 + seg->px2)/2., (seg->py1
548 // + seg->py2)/2., 0.))
549 {
550 wxPoint ab;
551 GetCanvasPixLL(vp, &ab, seg->py1, seg->px1);
552 wxPoint cd;
553 GetCanvasPixLL(vp, &cd, seg->py1, seg->px1);
554
555 int w, h;
556 texfont.GetTextExtent(label, &w, &h);
557
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;
563
564 wxRect r(x, y, w, h);
565 r.Inflate(w);
566 if (!prev.Intersects(r)) {
567#if 1
568 prev = r;
569 if (pof->m_oDC) {
570 // pof->m_oDC->SetFont( *mfont );
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);
575 }
576
577#else
578 prev = r;
579 glColor4ub(color.Red(), color.Green(), color.Blue(), color.Alpha());
580
581 /* draw bounding rectangle */
582 glBegin(GL_QUADS);
583 glVertex2i(x, y);
584 glVertex2i(x + w, y);
585 glVertex2i(x + w, y + h);
586 glVertex2i(x, y + h);
587 glEnd();
588
589 glColor3ub(0, 0, 0);
590
591 glBegin(GL_LINE_LOOP);
592 glVertex2i(x, y);
593 glVertex2i(x + w, y);
594 glVertex2i(x + w, y + h);
595 glVertex2i(x, y + h);
596 glEnd();
597
598 glEnable(GL_TEXTURE_2D);
599 texfont.RenderString(label, xd, yd);
600 glDisable(GL_TEXTURE_2D);
601#endif
602 }
603 }
604 }
605 }
606 glDisable(GL_BLEND);
607#endif
608}
609
610//==================================================================================
611// Segment
612//==================================================================================
613Segment::Segment(int I, int w, int J, char c1, char c2, char c3, char c4,
614 const GribRecord *rec, double pressure) {
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);
619
620 intersectionAreteGrille(i, j, k, l, &px1, &py1, rec, pressure);
621 intersectionAreteGrille(m, n, o, p, &px2, &py2, rec, pressure);
622}
623//-----------------------------------------------------------------------
624void Segment::intersectionAreteGrille(int i, int j, int k, int l, double *x,
625 double *y, const GribRecord *rec,
626 double pressure) {
627 double xa, xb, ya, yb, pa, pb, dec;
628 pa = rec->GetValue(i, j);
629 pb = rec->GetValue(k, l);
630
631 rec->getXY(i, j, &xa, &ya);
632 rec->getXY(k, l, &xb, &yb);
633
634 // Abscisse
635 if (pb != pa)
636 dec = (pressure - pa) / (pb - pa);
637 else
638 dec = 0.5;
639 if (fabs(dec) > 1) dec = 0.5;
640 double xd = xb - xa;
641 if (xd < -180)
642 xd += 360;
643 else if (xd > 180)
644 xd -= 360;
645 *x = xa + xd * dec;
646
647 // Ordonnée
648 if (pb != pa)
649 dec = (pressure - pa) / (pb - pa);
650 else
651 dec = 0.5;
652 if (fabs(dec) > 1) dec = 0.5;
653 *y = ya + (yb - ya) * dec;
654}
655//---------------------------------------------------------------
656void Segment::traduitCode(int I, int w, int J, char c1, int &i, int &j) {
657 int Im1 = I ? I - 1 : w - 1;
658 switch (c1) {
659 case 'a':
660 i = Im1;
661 j = J - 1;
662 break;
663 case 'b':
664 i = I;
665 j = J - 1;
666 break;
667 case 'c':
668 i = Im1;
669 j = J;
670 break;
671 case 'd':
672 i = I;
673 j = J;
674 break;
675 default:
676 i = I;
677 j = J;
678 }
679}
680
681//-----------------------------------------------------------------------
682// Génère la liste des segments.
683// Les coordonnées sont les indices dans la grille du GribRecord
684//---------------------------------------------------------
685void IsoLine::extractIsoLine(const GribRecord *rec) {
686 int i, j, W, H;
687 double a, b, c, d;
688 W = rec->GetNi();
689 H = rec->GetNj();
690
691 int We = W;
692 if (rec->GetLonMax() + rec->GetDi() - rec->GetLonMin() == 360) We++;
693
694 for (j = 1; j < H; j++) // !!!! 1 to end
695 {
696 a = rec->GetValue(0, j - 1);
697 c = rec->GetValue(0, j);
698 for (i = 1; i < We; i++, a = b, c = d) {
699 // x = rec->GetX(i);
700 // y = rec->GetY(j);
701
702 int ni = i;
703 if (i == W) ni = 0;
704 b = rec->GetValue(ni, j - 1);
705 d = rec->GetValue(ni, j);
706
707 if (a == GRIB_NOTDEF || b == GRIB_NOTDEF || c == GRIB_NOTDEF ||
708 d == GRIB_NOTDEF)
709 continue;
710
711 if ((a < value && b < value && c < value && d < value) ||
712 (a > value && b > value && c > value && d > value))
713 continue;
714
715 // Détermine si 1 ou 2 segments traversent la case ab-cd
716 // a b
717 // c d
718 //--------------------------------
719 // 1 segment en diagonale
720 //--------------------------------
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));
733 //--------------------------------
734 // 1 segment H ou V
735 //--------------------------------
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));
742 //--------------------------------
743 // 2 segments en diagonale
744 //--------------------------------
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));
751 }
752 }
753 }
754}
755
756// ----------------------------------------------------------------------------
757// splines code lifted from wxWidgets
758// ----------------------------------------------------------------------------
759
760// ----------------------------------- spline code
761// ----------------------------------------
762
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);
771
772#define half(z1, z2) ((z1 + z2) / 2.0)
773#define THRESHOLD 5
774
775/* iterative version */
776
777void ocpn_wx_quadratic_spline(double a1, double b1, double a2, double b2,
778 double a3, double b3, double a4, double b4) {
779 double xmid, ymid;
780 double x1, y1, x2, y2, x3, y3, x4, y4;
781
782 ocpn_wx_clear_stack();
783 ocpn_wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
784
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);
792 } else {
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,
798 ymid);
799 }
800 }
801}
802
803/* utilities used by spline drawing routines */
804
806 double x1, y1, x2, y2, x3, y3, x4, y4;
807} Stack;
808
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;
813
814void ocpn_wx_clear_stack() {
815 ocpn_wx_stack_top = ocpn_wx_spline_stack;
816 ocpn_wx_stack_count = 0;
817}
818
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;
829 ocpn_wx_stack_top++;
830 ocpn_wx_stack_count++;
831}
832
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);
836 ocpn_wx_stack_top--;
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;
846 return (1);
847}
848
849static bool ocpn_wx_spline_add_point(double x, double y) {
850 wxPoint *point = new wxPoint;
851 point->x = (int)x;
852 point->y = (int)y;
853 ocpn_wx_spline_point_list.Append((wxObject *)point);
854 return true;
855}
856
857void GenSpline(wxList *points) {
858 wxPoint *p;
859 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
860 double x1, y1, x2, y2;
861
862 wxList::compatibility_iterator node = points->GetFirst();
863 if (!node)
864 // empty list
865 return;
866
867 p = (wxPoint *)node->GetData();
868
869 x1 = p->x;
870 y1 = p->y;
871
872 node = node->GetNext();
873 p = (wxPoint *)node->GetData();
874
875 x2 = p->x;
876 y2 = p->y;
877 cx1 = (double)((x1 + x2) / 2);
878 cy1 = (double)((y1 + y2) / 2);
879 cx2 = (double)((cx1 + x2) / 2);
880 cy2 = (double)((cy1 + y2) / 2);
881
882 ocpn_wx_spline_add_point(x1, y1);
883
884 while ((node = node->GetNext())
885#if !wxUSE_STL
886 != nullptr
887#endif // !wxUSE_STL
888 ) {
889 p = (wxPoint *)node->GetData();
890 x1 = x2;
891 y1 = y2;
892 x2 = p->x;
893 y2 = p->y;
894 cx4 = (double)(x1 + x2) / 2;
895 cy4 = (double)(y1 + y2) / 2;
896 cx3 = (double)(x1 + cx4) / 2;
897 cy3 = (double)(y1 + cy4) / 2;
898
899 ocpn_wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
900
901 cx1 = cx4;
902 cy1 = cy4;
903 cx2 = (double)(cx1 + x2) / 2;
904 cy2 = (double)(cy1 + y2) / 2;
905 }
906
907 ocpn_wx_spline_add_point(cx1, cy1);
908 ocpn_wx_spline_add_point(x2, y2);
909}
910
911#if 0
912static void GenerateSpline(int n, wxPoint points[])
913{
914 wxList list;
915 for (int i =0; i < n; i++)
916 {
917 list.Append((wxObject*)&points[i]);
918 }
919
920 GenSpline(&list);
921}
922
923static void ClearSplineList()
924{
925 wxList::compatibility_iterator node = ocpn_wx_spline_point_list.GetFirst();
926 while (node)
927 {
928 wxPoint *point = (wxPoint *)node->GetData();
929 delete point;
930 ocpn_wx_spline_point_list.Erase(node);
931 node = ocpn_wx_spline_point_list.GetFirst();
932 }
933}
934#endif
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.
IsoLine(double val, double coeff, double offset, const GribRecord *rec)
Definition iso_line.cpp:170
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
@ PI_PROJECTION_EQUIRECTANGULAR
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.