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
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::Node *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::Node *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.
double GetDi() const
Returns the grid spacing in longitude (i) direction in degrees.
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
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.