33#include <wx/graphics.h>
34#include <wx/listbook.h>
35#include <wx/clipbrd.h>
36#include <wx/aui/aui.h>
38#if defined(__OCPN__ANDROID__)
40#elif defined(__WXQT__) || defined(__WXGTK__)
48#include <wx/listimpl.cpp>
62#include "TrackPropDlg.h"
64#include "routemanagerdialog.h"
65#include "pluginmanager.h"
66#include "ocpn_pixel.h"
69#include "multiplexer.h"
72#include "glTextureDescriptor.h"
75#include "select_item.h"
78#include "ais_decoder.h"
79#include "ais_target_data.h"
80#include "AISTargetAlertDialog.h"
81#include "SendToGpsDlg.h"
82#include "OCPNRegion.h"
86#include "glChartCanvas.h"
96#define _CRTDBG_MAP_ALLOC
99#define DEBUG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)
107extern struct sigaction sa_all_old;
109extern sigjmp_buf env;
118extern void catch_signals(
int signo);
123ViewPort::ViewPort() {
130 pix_height = pix_width = 0;
131 b_MercatorProjectionOverride =
false;
133 m_projection_type = PROJECTION_MERCATOR;
136void ViewPort::PixelScale(
float scale){
139 view_scale_ppm *=
scale;
143wxPoint ViewPort::GetPixFromLL(
double lat,
double lon) {
144 wxPoint2DDouble p = GetDoublePixFromLL(lat, lon);
145 if (wxFinite(p.m_x) && wxFinite(p.m_y)){
146 if( (abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6) )
147 return wxPoint(wxRound(p.m_x), wxRound(p.m_y));
149 return wxPoint(INVALID_COORD, INVALID_COORD);
152wxPoint2DDouble ViewPort::GetDoublePixFromLL(
double lat,
double lon) {
158 if (xlon * clon < 0.) {
165 if (fabs(xlon - clon) > 180.) {
173 if (clat != lat0_cache) {
175 switch (m_projection_type) {
176 case PROJECTION_MERCATOR:
177 case PROJECTION_WEB_MERCATOR:
178 cache0 = toSMcache_y30(clat);
180 case PROJECTION_POLAR:
181 cache0 = toPOLARcache_e(clat);
183 case PROJECTION_ORTHOGRAPHIC:
184 case PROJECTION_STEREOGRAPHIC:
185 case PROJECTION_GNOMONIC:
186 cache_phi0(clat, &cache0, &cache1);
191 switch (m_projection_type) {
192 case PROJECTION_MERCATOR:
193 case PROJECTION_WEB_MERCATOR:
194 toSMcache(lat, xlon, cache0, clon, &easting, &northing);
197 case PROJECTION_TRANSVERSE_MERCATOR:
201 double tmeasting, tmnorthing;
202 double tmceasting, tmcnorthing;
203 toTM(clat, clon, 0., clon, &tmceasting, &tmcnorthing);
204 toTM(lat, xlon, 0., clon, &tmeasting, &tmnorthing);
206 northing = tmnorthing - tmcnorthing;
207 easting = tmeasting - tmceasting;
210 case PROJECTION_POLYCONIC:
214 double pceasting, pcnorthing;
215 toPOLY(clat, clon, 0., clon, &pceasting, &pcnorthing);
217 double peasting, pnorthing;
218 toPOLY(lat, xlon, 0., clon, &peasting, &pnorthing);
221 northing = pnorthing - pcnorthing;
224 case PROJECTION_ORTHOGRAPHIC:
225 toORTHO(lat, xlon, cache0, cache1, clon, &easting, &northing);
228 case PROJECTION_POLAR:
229 toPOLAR(lat, xlon, cache0, clat, clon, &easting, &northing);
232 case PROJECTION_STEREOGRAPHIC:
233 toSTEREO(lat, xlon, cache0, cache1, clon, &easting, &northing);
236 case PROJECTION_GNOMONIC:
237 toGNO(lat, xlon, cache0, cache1, clon, &easting, &northing);
240 case PROJECTION_EQUIRECTANGULAR:
241 toEQUIRECT(lat, xlon, clat, clon, &easting, &northing);
245 printf(
"unhandled projection\n");
248 if (!wxFinite(easting) || !wxFinite(northing))
249 return wxPoint2DDouble(easting, northing);
251 double epix = easting * view_scale_ppm;
252 double npix = northing * view_scale_ppm;
257 double angle = rotation;
260 dxr = epix * cos(angle) + npix * sin(angle);
261 dyr = npix * cos(angle) - epix * sin(angle);
264 return wxPoint2DDouble((pix_width / 2.0) + dxr, (pix_height / 2.0) - dyr);
267void ViewPort::GetLLFromPix(
const wxPoint2DDouble &p,
double *lat,
269 double dx = p.m_x - (pix_width / 2.0);
270 double dy = (pix_height / 2.0) - p.m_y;
276 double angle = rotation;
279 xpr = (dx * cos(angle)) - (dy * sin(angle));
280 ypr = (dy * cos(angle)) + (dx * sin(angle));
282 double d_east = xpr / view_scale_ppm;
283 double d_north = ypr / view_scale_ppm;
285 double slat = 0.0, slon = 0.0;
286 switch (m_projection_type) {
287 case PROJECTION_MERCATOR:
288 case PROJECTION_WEB_MERCATOR:
292 fromSM(d_east, d_north, clat, clon, &slat, &slon);
295 case PROJECTION_TRANSVERSE_MERCATOR: {
296 double tmceasting, tmcnorthing;
297 toTM(clat, clon, 0., clon, &tmceasting, &tmcnorthing);
299 fromTM(d_east, d_north + tmcnorthing, 0., clon, &slat, &slon);
302 case PROJECTION_POLYCONIC: {
303 double polyeasting, polynorthing;
304 toPOLY(clat, clon, 0., clon, &polyeasting, &polynorthing);
306 fromPOLY(d_east, d_north + polynorthing, 0., clon, &slat, &slon);
309 case PROJECTION_ORTHOGRAPHIC:
310 fromORTHO(d_east, d_north, clat, clon, &slat, &slon);
313 case PROJECTION_POLAR:
314 fromPOLAR(d_east, d_north, clat, clon, &slat, &slon);
317 case PROJECTION_STEREOGRAPHIC:
318 fromSTEREO(d_east, d_north, clat, clon, &slat, &slon);
321 case PROJECTION_GNOMONIC:
322 fromGNO(d_east, d_north, clat, clon, &slat, &slon);
325 case PROJECTION_EQUIRECTANGULAR:
326 fromEQUIRECT(d_east, d_north, clat, clon, &slat, &slon);
330 printf(
"unhandled projection\n");
337 else if (slon > 180.)
342LLRegion ViewPort::GetLLRegion(
const OCPNRegion ®ion) {
346 return LLRegion(GetBBox());
349 if (!glChartCanvas::CanClipViewport(*
this))
return LLRegion(GetBBox());
353 while (it.HaveRects()) {
354 wxRect rect = it.GetRect();
356 int x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height;
357 int p[8] = {x1, y1, x2, y1, x2, y2, x1, y2};
363 if (fabs(rotation) >= 0.0001) {
365 double lastlat, lastlon;
367 GetLLFromPix(wxPoint(p[li], p[li + 1]), &lastlat, &lastlon);
368 for (
int i = 0; i < 8; i += 2) {
370 GetLLFromPix(wxPoint(p[i], p[i + 1]), &lat, &lon);
374 int lat_splits = floor(fabs(lat - lastlat) / grid);
375 double lond = fabs(lon - lastlon);
376 int lon_splits = floor((lond > 180 ? 360 - lond : lond) / grid);
377 int splits = wxMax(lat_splits, lon_splits) + 1;
379 for (
int k = 1; k < splits; k++) {
380 float d = (float)k / splits;
381 GetLLFromPix(wxPoint((1 - d) * p[li] + d * p[i],
382 (1 - d) * p[li + 1] + d * p[i + 1]),
383 pll + j, pll + j + 1);
389 lastlat = lat, lastlon = lon;
393 for (
int i = 0; i < j; i += 2)
394 GetLLFromPix(wxPoint(p[i], p[i + 1]), pll + i, pll + i + 1);
398 for (
int i = 0; i < j; i += 2) {
399 if (pll[i + 1] <= clon - 180)
401 else if (pll[i + 1] >= clon + 180)
405 r.Union(LLRegion(j / 2, pll));
419 const LLRegion &llregion,
420 int chart_native_scale) {
421 double rotation_save = rotation;
424 std::list<ContourRegion> cregions;
425 for (std::list<poly_contour>::const_iterator i = llregion.contours.begin();
426 i != llregion.contours.end(); i++) {
427 float *contour_points =
new float[2 * i->size()];
429 std::list<contour_pt>::const_iterator j;
430 for (j = i->begin(); j != i->end(); j++) {
431 contour_points[idx++] = j->y;
432 contour_points[idx++] = j->x;
435 double total = 0, maxlat = -90;
437 double x0 = contour_points[0] - contour_points[pl + 0];
438 double y0 = contour_points[1] - contour_points[pl + 1];
440 for (
int p = 0; p < idx; p += 2) {
441 maxlat = wxMax(maxlat, contour_points[p]);
442 int pn = p < idx - 2 ? p + 2 : 0;
443 double x1 = contour_points[pn + 0] - contour_points[p + 0];
444 double y1 = contour_points[pn + 1] - contour_points[p + 1];
445 total += x1 * y0 - x0 * y1;
451 s.subtract = total < 0;
452 s.r = GetVPRegionIntersect(region, i->size(), contour_points,
453 chart_native_scale, NULL);
454 delete[] contour_points;
456 std::list<ContourRegion>::iterator k = cregions.begin();
457 while (k != cregions.end()) {
458 if (k->maxlat < s.maxlat)
break;
461 cregions.insert(k, s);
465 for (std::list<ContourRegion>::iterator k = cregions.begin();
466 k != cregions.end(); k++) {
475 rotation = rotation_save;
481 int chart_native_scale,
491 if (chart_scale < chart_native_scale / 10) {
493 float *pfp = llpoints;
494 float lon_max = -10000.;
495 float lon_min = 10000.;
496 float lat_max = -10000.;
497 float lat_min = 10000.;
499 for (
int ip = 0; ip < nPoints; ip++) {
500 lon_max = wxMax(lon_max, pfp[1]);
501 lon_min = wxMin(lon_min, pfp[1]);
502 lat_max = wxMax(lat_max, pfp[0]);
503 lat_min = wxMin(lat_min, pfp[0]);
509 chart_box.Set(lat_min, lon_min, lat_max, lon_max);
513 if (chart_box.IntersectOut(vpBBox))
return OCPNRegion();
523 if (chart_box.IntersectIn(vpBBox))
return Region;
525 wxPoint p1 = GetPixFromLL(lat_max, lon_min);
526 wxPoint p2 = GetPixFromLL(lat_min, lon_max);
539 pp =
new wxPoint[nPoints];
543 float *pfp = llpoints;
545 wxPoint p = GetPixFromLL(pfp[0], pfp[1]);
546 int poly_x_max = INVALID_COORD, poly_y_max = INVALID_COORD,
547 poly_x_min = INVALID_COORD, poly_y_min = INVALID_COORD;
551 for (
int ip = 0; ip < nPoints; ip++) {
552 wxPoint p = GetPixFromLL(pfp[0], pfp[1]);
553 if (p.x == INVALID_COORD)
continue;
558 poly_x_max = wxMax(poly_x_max, p.x);
559 poly_y_max = wxMax(poly_y_max, p.y);
560 poly_x_min = wxMin(poly_x_min, p.x);
561 poly_y_min = wxMin(poly_y_min, p.y);
573 if (ppoints == NULL)
delete[] pp;
580 float_2Dpt p0, p1, p2, p3;
585 bool b_intersect =
false;
587 while (screen_region_it1.HaveRects()) {
588 wxRect rect = screen_region_it1.GetRect();
593 GetLLFromPix(wxPoint(rect.x, rect.y), &lat, &lon);
597 GetLLFromPix(wxPoint(rect.x + rect.width, rect.y), &lat, &lon);
601 GetLLFromPix(wxPoint(rect.x + rect.width, rect.y + rect.height), &lat,
606 GetLLFromPix(wxPoint(rect.x, rect.y + rect.height), &lat, &lon);
610 for (
int i = 0; i < npPoints - 1; i++) {
613 int y1 = pp[i + 1].y;
615 if (((y0 < rect.y) && (y1 < rect.y)) ||
616 ((y0 > rect.y + rect.height) && (y1 > rect.y + rect.height)))
621 f0.y = llpoints[i * 2];
622 f0.x = llpoints[(i * 2) + 1];
624 f1.y = llpoints[(i + 1) * 2];
625 f1.x = llpoints[((i + 1) * 2) + 1];
626 b_intersect |= Intersect_FL(p0, p1, f0, f1) != 0;
627 if (b_intersect)
break;
628 b_intersect |= Intersect_FL(p1, p2, f0, f1) != 0;
629 if (b_intersect)
break;
630 b_intersect |= Intersect_FL(p2, p3, f0, f1) != 0;
631 if (b_intersect)
break;
632 b_intersect |= Intersect_FL(p3, p0, f0, f1) != 0;
633 if (b_intersect)
break;
639 b_intersect |= Intersect_FL(p0, p1, f0, f1) != 0;
640 if (b_intersect)
break;
641 b_intersect |= Intersect_FL(p1, p2, f0, f1) != 0;
642 if (b_intersect)
break;
643 b_intersect |= Intersect_FL(p2, p3, f0, f1) != 0;
644 if (b_intersect)
break;
645 b_intersect |= Intersect_FL(p3, p0, f0, f1) != 0;
646 if (b_intersect)
break;
652 f0.y = llpoints[(nPoints - 1) * 2];
653 f0.x = llpoints[((nPoints - 1) * 2) + 1];
657 b_intersect |= Intersect_FL(p0, p1, f0, f1) != 0;
658 b_intersect |= Intersect_FL(p1, p2, f0, f1) != 0;
659 b_intersect |= Intersect_FL(p2, p3, f0, f1) != 0;
660 b_intersect |= Intersect_FL(p3, p0, f0, f1) != 0;
664 b_intersect |= Intersect_FL(p0, p1, f0, f1) != 0;
665 b_intersect |= Intersect_FL(p1, p2, f0, f1) != 0;
666 b_intersect |= Intersect_FL(p2, p3, f0, f1) != 0;
667 b_intersect |= Intersect_FL(p3, p0, f0, f1) != 0;
670 screen_region_it1.NextRect();
676 bool b_contained =
false;
679 while (screen_region_it2.HaveRects()) {
680 wxRect rect = screen_region_it2.GetRect();
682 for (
int i = 0; i < npPoints - 1; i++) {
686 if ((x0 < rect.x) || (x0 > rect.x + rect.width) || (y0 < rect.y) ||
687 (y0 > rect.y + rect.height))
693 screen_region_it2.NextRect();
699 if (!b_contained && !b_intersect) {
701 wxRect rpoly(poly_x_min, poly_y_min, poly_x_max - poly_x_min,
702 poly_y_max - poly_y_min);
703 wxRect rRegion = Region.GetBox();
704 if (rpoly.Contains(rRegion)) {
714 float rlat = (p0.y + p2.y) / 2.;
715 float rlon = (p0.x + p1.x) / 2.;
717 if (G_PtInPolygon_FL((float_2Dpt *)llpoints, nPoints, rlon, rlat)) {
718 if (NULL == ppoints)
delete[] pp;
722 if (G_PtInPolygon_FL((float_2Dpt *)llpoints, nPoints, rlon, rlat)) {
723 if (NULL == ppoints)
delete[] pp;
729 if (NULL == ppoints)
delete[] pp;
740 if (NULL == ppoints)
delete[] pp;
744 }
else if (b_contained && !b_intersect) {
748 if (NULL == ppoints)
delete[] pp;
755 sigaction(SIGSEGV, NULL,
758 struct sigaction temp;
759 sigaction(SIGSEGV, NULL, &temp);
761 temp.sa_handler = catch_signals;
762 sigemptyset(&temp.sa_mask);
767 sigaction(SIGSEGV, &temp, NULL);
769 if (sigsetjmp(env, 1))
771 sigaction(SIGSEGV, &sa_all_old, NULL);
779 if (NULL == ppoints)
delete[] pp;
781 sigaction(SIGSEGV, &sa_all_old, NULL);
789 if (NULL == ppoints)
delete[] pp;
797wxRect ViewPort::GetVPRectIntersect(
size_t n,
float *llpoints) {
801 float *pfp = llpoints;
803 BoundingBox point_box;
804 for (
unsigned int ip = 0; ip < n; ip++) {
805 point_box.Expand(pfp[1], pfp[0]);
809 wxPoint pul = GetPixFromLL(point_box.GetMaxY(), point_box.GetMinX());
810 wxPoint plr = GetPixFromLL(point_box.GetMinY(), point_box.GetMaxX());
820void ViewPort::SetBoxes(
void) {
824 rv_rect = wxRect(0, 0, pix_width, pix_height);
828 if ((fabs(skew) > .0001) || (fabs(rotation) > .0001)) {
829 double rotator = rotation;
830 double lpixh = pix_height;
831 double lpixw = pix_width;
834 (fabs(pix_height * cos(skew)) + fabs(pix_width * sin(skew))));
836 (fabs(pix_width * cos(skew)) + fabs(pix_height * sin(skew))));
838 int dy = wxRound(fabs(lpixh * cos(rotator)) + fabs(lpixw * sin(rotator)));
839 int dx = wxRound(fabs(lpixw * cos(rotator)) + fabs(lpixh * sin(rotator)));
843 if (dy % 4) dy += 4 - (dy % 4);
844 if (dx % 4) dx += 4 - (dx % 4);
846 int inflate_x = wxMax((dx - pix_width) / 2, 0);
847 int inflate_y = wxMax((dy - pix_height) / 2, 0);
850 rv_rect.Inflate(inflate_x, inflate_y);
857 double rotation_save = rotation;
858 SetRotationAngle(0.0);
860 wxPoint ul(rv_rect.x, rv_rect.y),
861 lr(rv_rect.x + rv_rect.width, rv_rect.y + rv_rect.height);
862 double dlat_min, dlat_max, dlon_min, dlon_max;
864 bool hourglass =
false;
865 switch (m_projection_type) {
866 case PROJECTION_TRANSVERSE_MERCATOR:
867 case PROJECTION_STEREOGRAPHIC:
868 case PROJECTION_GNOMONIC:
871 case PROJECTION_POLYCONIC:
872 case PROJECTION_POLAR:
873 case PROJECTION_ORTHOGRAPHIC: {
877 wxPoint u(rv_rect.x + rv_rect.width / 2, rv_rect.y);
878 wxPoint ur(rv_rect.x + rv_rect.width, rv_rect.y);
879 GetLLFromPix(ul, &d, &dlon_min);
880 GetLLFromPix(ur, &d, &dlon_max);
881 GetLLFromPix(lr, &dlat_min, &d);
882 GetLLFromPix(u, &dlat_max, &d);
884 if (fabs(fabs(d - clon) - 180) < 1) {
888 }
else if (std::isnan(dlat_max))
893 wxPoint l(rv_rect.x + rv_rect.width / 2, rv_rect.y + rv_rect.height);
895 GetLLFromPix(l, &dlat_min2, &d);
896 dlat_min = wxMin(dlat_min, dlat_min2);
899 if (std::isnan(dlat_min))
900 dlat_min = clat - 90;
902 wxPoint l(rv_rect.x + rv_rect.width / 2, rv_rect.y + rv_rect.height);
903 wxPoint ll(rv_rect.x, rv_rect.y + rv_rect.height);
904 GetLLFromPix(ul, &dlat_max, &d);
905 GetLLFromPix(lr, &d, &dlon_max);
906 GetLLFromPix(ll, &d, &dlon_min);
907 GetLLFromPix(l, &dlat_min, &d);
909 if (fabs(fabs(d - clon) - 180) < 1) {
913 }
else if (std::isnan(dlat_min))
918 wxPoint u(rv_rect.x + rv_rect.width / 2, rv_rect.y);
920 GetLLFromPix(u, &dlat_max2, &d);
921 dlat_max = wxMax(dlat_max, dlat_max2);
924 if (std::isnan(dlat_max))
925 dlat_max = clat + 90;
928 if (std::isnan(dlon_min)) {
931 if (dlat_max < 90 && dlat_min > -90) {
935 dlon_max = clon + 90 + fabs(clat);
945 GetLLFromPix(ul, &dlat_max, &dlon_min);
946 GetLLFromPix(lr, &dlat_min, &dlon_max);
952 else if (clon > dlon_max)
956 vpBBox.Set(dlat_min, dlon_min, dlat_max, dlon_max);
959 SetRotationAngle(rotation_save);
962void ViewPort::SetBBoxDirect(
double latmin,
double lonmin,
double latmax,
964 vpBBox.Set(latmin, lonmin, latmax, lonmax);
967ViewPort ViewPort::BuildExpandedVP(
int width,
int height) {
970 new_vp.pix_width = width;
971 new_vp.pix_height = height;