34 #include <wx/wxprec.h>
56 #include "glChartCanvas.h"
60 #include "chartbase.h"
66 #define __CALL_CONVENTION
68 #define __CALL_CONVENTION
73 extern wxString gWorldMapLocation;
75 #if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
76 static const GLchar *vertex_shader_source =
77 "attribute vec2 position;\n"
78 "uniform mat4 MVMatrix;\n"
79 "uniform mat4 TransformMatrix;\n"
80 "uniform vec4 color;\n"
81 "varying vec4 fragColor;\n"
83 " fragColor = color;\n"
84 " gl_Position = MVMatrix * TransformMatrix * vec4(position, 0.0, 1.0);\n"
87 static const GLchar *fragment_shader_source =
88 "precision lowp float;\n"
89 "varying vec4 fragColor;\n"
91 " gl_FragColor = fragColor;\n"
94 static const GLfloat vertices2[] = {
95 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f,
98 static const GLfloat vertices3[] = {
99 0.0f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, -0.5f, -0.5f, 0.0f,
102 enum Consts { INFOLOG_LEN = 512 };
103 GLchar infoLog[INFOLOG_LEN];
104 GLint fragment_shader;
109 extern GLint color_tri_shader_program;
114 GSHHSChart::GSHHSChart() {
116 land = wxColor(250, 250, 250);
117 water = wxColor(0, 0, 0);
120 GSHHSChart::~GSHHSChart() {
121 if (reader)
delete reader;
124 void GSHHSChart::SetColorScheme(ColorScheme scheme) {
125 land = wxColor(170, 175, 80);
126 water = wxColor(170, 195, 240);
131 case GLOBAL_COLOR_SCHEME_DUSK:
134 case GLOBAL_COLOR_SCHEME_NIGHT:
141 land.Set(land.Red() * dim, land.Green() * dim, land.Blue() * dim);
142 water.Set(water.Red() * dim, water.Green() * dim, water.Blue() * dim);
145 void GSHHSChart::SetColorsDirect(wxColour newLand, wxColour newWater) {
150 void GSHHSChart::Reset() {
151 if (reader)
delete reader;
153 gshhsCrossesLandReset();
156 int GSHHSChart::GetMinAvailableQuality() {
158 return reader->GetMinAvailableQuality();
161 int GSHHSChart::GetMaxAvailableQuality() {
163 return reader->GetMaxAvailableQuality();
169 if (reader->GetPolyVersion() < 210 || reader->GetPolyVersion() > 240) {
171 _T(
"GSHHS World chart files have wrong version. Found %d, expected ")
173 reader->GetPolyVersion());
176 _T(
"Background world map loaded from GSHHS datafiles found in: ") +
181 reader->drawContinents(dc, vp, water, land);
187 GshhsPolyCell::GshhsPolyCell(FILE *fpoly_,
int x0_,
int y0_,
194 for (
int i = 0; i < 6; i++) polyv[i] = NULL;
198 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++) high_res_map[i] = NULL;
201 GshhsPolyCell::~GshhsPolyCell() {
204 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++)
delete high_res_map[i];
205 for (
int i = 0; i < 6; i++)
delete[] polyv[i];
208 void GshhsPolyCell::ClearPolyV() {
209 for (
int i = 0; i < 6; i++) {
215 void GshhsPolyCell::ReadPoly(contour_list &poly) {
218 int32_t num_vertices, num_contours;
220 if (fread(&num_contours,
sizeof num_contours, 1, fpoly) != 1)
goto fail;
222 for (
int c = 0; c < num_contours; c++) {
224 if (fread(&value,
sizeof value, 1, fpoly) !=
226 fread(&value,
sizeof value, 1, fpoly) != 1)
229 num_vertices = value;
232 for (
int v = 0; v < num_vertices; v++) {
233 if (fread(&X,
sizeof X, 1, fpoly) != 1 ||
234 fread(&Y,
sizeof Y, 1, fpoly) != 1)
237 tmp_contour.push_back(wxRealPoint(X * GSHHS_SCL, Y * GSHHS_SCL));
239 poly.push_back(tmp_contour);
244 wxLogMessage(_T(
"gshhs ReadPoly failed"));
247 void GshhsPolyCell::ReadPolygonFile() {
253 tab_data = (x0cell / header->pasx) * (180 / header->pasy) +
254 (y0cell + 90) / header->pasy;
256 if (fread(&pos_data,
sizeof(
int), 1, fpoly) != 1)
goto fail;
258 fseek(fpoly, pos_data, SEEK_SET);
268 wxLogMessage(_T(
"gshhs ReadPolygon failed"));
271 wxPoint2DDouble GetDoublePixFromLL(
ViewPort &vp,
double lat,
double lon) {
272 wxPoint2DDouble p = vp.GetDoublePixFromLL(lat, lon);
273 p.m_x -= vp.rv_rect.x, p.m_y -= vp.rv_rect.y;
277 void GshhsPolyCell::DrawPolygonFilled(
ocpnDC &pnt, contour_list *p,
double dx,
278 ViewPort &vp, wxColor
const &color) {
292 for (c = 0; c < p->size(); c++) {
293 if (!p->at(c).size())
continue;
295 wxPoint *poly_pt =
new wxPoint[p->at(c).size()];
297 contour &cp = p->at(c);
300 for (v = 0; v < p->at(c).size(); v++) {
301 wxRealPoint &ccp = cp.at(v);
302 wxPoint2DDouble q = GetDoublePixFromLL(vp, ccp.y, ccp.x + dx);
303 if (std::isnan(q.m_x)) {
308 x = q.m_x, y = q.m_y;
310 if (v == 0 || x != x_old || y != y_old) {
311 poly_pt[pointCount].x = x;
312 poly_pt[pointCount].y = y;
319 if (pointCount > 1) pnt.DrawPolygonTessellated(pointCount, poly_pt, 0, 0);
341 static std::list<float_2Dpt> g_pv;
342 static std::list<GLvertex *> g_vertexes;
343 static int g_type, g_pos;
344 static float_2Dpt g_p1, g_p2;
346 void __CALL_CONVENTION gshhscombineCallback(GLdouble coords[3],
347 GLdouble *vertex_data[4],
349 GLdouble **dataOut) {
352 vertex =
new GLvertex();
353 g_vertexes.push_back(vertex);
355 vertex->info.x = coords[0];
356 vertex->info.y = coords[1];
358 *dataOut = vertex->data;
361 void __CALL_CONVENTION gshhsvertexCallback(GLvoid *arg) {
363 vertex = (GLvertex *)arg;
365 p.y = vertex->info.x;
366 p.x = vertex->info.y;
369 if (g_type != GL_TRIANGLES) {
371 g_pv.push_back(g_p1);
372 g_pv.push_back(g_p2);
375 if (g_type == GL_TRIANGLE_STRIP)
386 void __CALL_CONVENTION gshhserrorCallback(GLenum errorCode) {
387 const GLubyte *estring;
388 estring = gluErrorString(errorCode);
392 void __CALL_CONVENTION gshhsbeginCallback(GLenum type) {
395 case GL_TRIANGLE_STRIP:
396 case GL_TRIANGLE_FAN:
400 printf(
"tess unhandled begin type: %d\n", type);
406 void __CALL_CONVENTION gshhsendCallback() {}
408 void GshhsPolyCell::DrawPolygonFilledGL(
ocpnDC &pnt, contour_list *p, float_2Dpt **pv,
410 wxColor
const &color,
bool idl) {
417 for (
unsigned int c = 0; c < p->size(); c++) {
418 if (!p->at(c).size())
continue;
420 contour &cp = p->at(c);
422 GLUtesselator *tobj = gluNewTess();
424 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&gshhsvertexCallback);
425 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&gshhsbeginCallback);
426 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&gshhsendCallback);
427 gluTessCallback(tobj, GLU_TESS_COMBINE,
428 (_GLUfuncptr)&gshhscombineCallback);
429 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&gshhserrorCallback);
431 gluTessNormal(tobj, 0, 0, 1);
432 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
434 gluTessBeginPolygon(tobj, NULL);
435 gluTessBeginContour(tobj);
437 for (
unsigned int v = 0; v < p->at(c).size(); v++) {
438 wxRealPoint &ccp = cp.at(v);
440 if (v == 0 || ccp != cp.at(v - 1)) {
441 GLvertex *vertex =
new GLvertex();
442 g_vertexes.push_back(vertex);
445 if (glChartCanvas::HasNormalizedViewPort(vp))
446 q = GetDoublePixFromLL(vp, ccp.y, ccp.x);
448 q.m_x = ccp.y, q.m_y = ccp.x;
450 if (vp.m_projection_type != PROJECTION_POLAR) {
454 if (idl && ccp.x == 180) {
455 if (vp.m_projection_type != PROJECTION_MERCATOR &&
456 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
461 vertex->info.x = q.m_x;
462 vertex->info.y = q.m_y;
464 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
468 gluTessEndContour(tobj);
469 gluTessEndPolygon(tobj);
472 for (std::list<GLvertex *>::iterator it = g_vertexes.begin();
473 it != g_vertexes.end(); it++)
478 *pv =
new float_2Dpt[g_pv.size()];
480 for (std::list<float_2Dpt>::iterator it = g_pv.begin(); it != g_pv.end();
488 #if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
492 if (!vertex_shader) {
494 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
495 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
496 glCompileShader(vertex_shader);
497 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
499 glGetShaderInfoLog(vertex_shader, INFOLOG_LEN, NULL, infoLog);
500 printf(
"ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
504 if (!fragment_shader) {
506 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
507 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
508 glCompileShader(fragment_shader);
509 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
511 glGetShaderInfoLog(fragment_shader, INFOLOG_LEN, NULL, infoLog);
512 printf(
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
516 if (!shader_program) {
518 shader_program = glCreateProgram();
519 glAttachShader(shader_program, vertex_shader);
520 glAttachShader(shader_program, fragment_shader);
521 glLinkProgram(shader_program);
522 glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
524 glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
525 printf(
"ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
534 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)vp.pix_width,
535 2.0 / (
float)vp.pix_height, 1.0);
536 mat4x4_translate_in_place(mvp, -vp.pix_width / 2, vp.pix_height / 2, 0);
538 if (glChartCanvas::HasNormalizedViewPort(vp)) {
540 GLint pos = glGetAttribLocation(color_tri_shader_program,
"position");
541 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), *pv);
542 glEnableVertexAttribArray(pos);
548 GLint tmatloc = glGetUniformLocation(color_tri_shader_program,
"TransformMatrix");
549 glUniformMatrix4fv(tmatloc, 1, GL_FALSE, (
const GLfloat*)m);
551 glUseProgram(color_tri_shader_program);
552 glDrawArrays(GL_TRIANGLES, 0, *pvc);
555 float *pvt =
new float[2 * (*pvc)];
556 for (
int i = 0; i < *pvc; i++) {
557 float_2Dpt *pc = *pv + i;
558 wxPoint2DDouble q = vp.GetDoublePixFromLL(pc->y, pc->x);
560 pvt[(i * 2) + 1] = q.m_y;
563 GLShaderProgram *shader = pcolor_tri_shader_program[pnt.m_canvasIndex];
567 colorv[0] = color.Red() / float(256);
568 colorv[1] = color.Green() / float(256);
569 colorv[2] = color.Blue() / float(256);
571 shader->SetUniform4fv(
"color", colorv);
573 shader->SetAttributePointerf(
"position", pvt);
575 glDrawArrays(GL_TRIANGLES, 0, *pvc);
578 glDeleteBuffers(1, &vbo);
588 #define DRAW_POLY_FILLED(POLY, COL) \
589 if (POLY) DrawPolygonFilled(pnt, POLY, dx, vp, COL);
590 #define DRAW_POLY_FILLED_GL(NUM, COL) \
591 DrawPolygonFilledGL(pnt,&poly##NUM, &polyv[NUM], &polyc[NUM], vp, COL, idl);
593 void GshhsPolyCell::drawMapPlain(
ocpnDC &pnt,
double dx,
ViewPort &vp,
594 wxColor seaColor, wxColor landColor,
598 #if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
599 #define NORM_FACTOR 4096.0
600 if (dx && (vp.m_projection_type == PROJECTION_MERCATOR ||
601 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
603 40058986 * NORM_FACTOR;
605 glTranslated(dx > 0 ? ts : -ts, 0, 0);
608 DRAW_POLY_FILLED_GL(1, landColor);
609 DRAW_POLY_FILLED_GL(2, seaColor);
610 DRAW_POLY_FILLED_GL(3, landColor);
611 DRAW_POLY_FILLED_GL(4, seaColor);
612 DRAW_POLY_FILLED_GL(5, landColor);
614 #if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
615 if (dx) glPopMatrix();
621 DRAW_POLY_FILLED(&poly1, landColor);
622 DRAW_POLY_FILLED(&poly2, seaColor);
623 DRAW_POLY_FILLED(&poly3, landColor);
624 DRAW_POLY_FILLED(&poly4, seaColor);
625 DRAW_POLY_FILLED(&poly5, landColor);
629 void GshhsPolyCell::DrawPolygonContour(
ocpnDC &pnt, contour_list *p,
double dx,
631 double x1, y1, x2, y2;
632 double long_max, lat_max, long_min, lat_min;
634 long_min = (double)x0cell;
635 lat_min = (double)y0cell;
636 long_max = ((double)x0cell + (
double)header->pasx);
637 lat_max = ((double)y0cell + (
double)header->pasy);
641 for (
unsigned int i = 0; i < p->size(); i++) {
642 if (!p->at(i).size())
continue;
645 for (v = 0; v < (p->at(i).size() - 1); v++) {
646 x1 = p->at(i).at(v).x;
647 y1 = p->at(i).at(v).y;
648 x2 = p->at(i).at(v + 1).x;
649 y2 = p->at(i).at(v + 1).y;
652 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
653 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
654 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
655 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
656 pnt.DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
660 x1 = p->at(i).at(v).x;
661 y1 = p->at(i).at(v).y;
662 x2 = p->at(i).at(0).x;
663 y2 = p->at(i).at(0).y;
665 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
666 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
667 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
668 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
669 pnt.DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
674 #define DRAW_POLY_CONTOUR(POLY) \
675 if (POLY) DrawPolygonContour(pnt, POLY, dx, vp);
677 void GshhsPolyCell::drawSeaBorderLines(
ocpnDC &pnt,
double dx,
ViewPort &vp) {
679 DRAW_POLY_CONTOUR(&poly1)
680 DRAW_POLY_CONTOUR(&poly2)
681 DRAW_POLY_CONTOUR(&poly3)
682 DRAW_POLY_CONTOUR(&poly4)
683 DRAW_POLY_CONTOUR(&poly5)
688 GshhsPolyReader::GshhsPolyReader(
int quality) {
691 for (
int i = 0; i < 360; i++) {
692 for (
int j = 0; j < 180; j++) {
693 allCells[i][j] = NULL;
697 polyHeader.version = -1;
698 InitializeLoadQuality(quality);
702 GshhsPolyReader::~GshhsPolyReader() {
703 for (
int i = 0; i < 360; i++) {
704 for (
int j = 0; j < 180; j++) {
705 if (allCells[i][j] != NULL) {
706 delete allCells[i][j];
707 allCells[i][j] = NULL;
718 int GshhsPolyReader::ReadPolyVersion() {
719 wxString fname = GshhsReader::getFileName_Land(0);
720 if (fpoly) fclose(fpoly);
721 fpoly = fopen(fname.mb_str(),
"rb");
724 if (!fpoly)
return 0;
726 readPolygonFileHeader(fpoly, &polyHeader);
728 return polyHeader.version;
731 void GshhsPolyReader::InitializeLoadQuality(
734 if (currentQuality != quality) {
735 currentQuality = quality;
737 wxString fname = GshhsReader::getFileName_Land(quality);
739 if (fpoly) fclose(fpoly);
741 fpoly = fopen(fname.mb_str(),
"rb");
742 if (fpoly) readPolygonFileHeader(fpoly, &polyHeader);
744 for (
int i = 0; i < 360; i++) {
745 for (
int j = 0; j < 180; j++) {
746 if (allCells[i][j] != NULL) {
747 delete allCells[i][j];
748 allCells[i][j] = NULL;
755 static inline bool my_intersects(
const wxLineF &line1,
const wxLineF &line2) {
756 double x1 = line1.m_p1.x, y1 = line1.m_p1.y, x2 = line1.m_p2.x,
758 double x3 = line2.m_p1.x, y3 = line2.m_p1.y, x4 = line2.m_p2.x,
763 double ax = x2 - x1, ay = y2 - y1;
764 double bx = x3 - x4, by = y3 - y4;
765 double cx = x1 - x3, cy = y1 - y3;
767 #define INTER_LIMIT 1e-7
768 double denominator = ay * bx - ax * by;
769 if (denominator < 1e-10) {
770 if (fabs((y1 * ax - ay * x1) * bx - (y3 * bx - by * x3) * ax) > INTER_LIMIT)
772 if (fabs((x1 * ay - ax * y1) * by - (x3 * by - bx * y3) * ay) > INTER_LIMIT)
778 const double reciprocal = 1 / denominator;
779 const double na = (by * cx - bx * cy) * reciprocal;
781 if (na < -INTER_LIMIT || na > 1 + INTER_LIMIT)
return false;
783 const double nb = (ax * cy - ay * cx) * reciprocal;
784 if (nb < -INTER_LIMIT || nb > 1 + INTER_LIMIT)
return false;
789 bool GshhsPolyReader::crossing1(
wxLineF trajectWorld) {
790 double x1 = trajectWorld.p1().x, y1 = trajectWorld.p1().y;
791 double x2 = trajectWorld.p2().x, y2 = trajectWorld.p2().y;
793 int clonmin, clonmax, clatmax, clatmin;
794 clonmin = (int)floor(GSSH_SUBM * wxMin(x1, x2));
795 clonmax = (int)ceil(GSSH_SUBM * wxMax(x1, x2));
798 clonmin += GSSH_SUBM * 360;
799 clonmax += GSSH_SUBM * 360;
802 if (clonmax - clonmin > GSSH_SUBM * 180) {
803 clonmin = (int)floor(GSSH_SUBM * wxMax(x1, x2)) - GSSH_SUBM * 360;
804 clonmax = (int)ceil(GSSH_SUBM * wxMin(x1, x2));
807 clatmin = (int)floor(GSSH_SUBM * wxMin(y1, y2));
808 clatmax = (int)ceil(GSSH_SUBM * wxMax(y1, y2));
809 wxASSERT(clatmin >= -GSSH_SUBM * 90 && clatmax <= GSSH_SUBM * 89);
815 int clon, clonx, clat;
816 for (clon = clonmin; clon < clonmax; clon++) {
818 while (clonx < 0) clonx += GSSH_SUBM * 360;
819 while (clonx >= GSSH_SUBM * 360) clonx -= GSSH_SUBM * 360;
821 wxASSERT(clonx >= 0 && clonx < GSSH_SUBM * 360);
823 if (clonx < GSSH_SUBM * 180) {
824 if (x1 > 180) x1 -= 360;
825 if (x2 > 180) x2 -= 360;
827 if (x1 < 180) x1 += 360;
828 if (x2 < 180) x2 += 360;
831 wxLineF rtrajectWorld(x1, y1, x2, y2);
833 for (clat = clatmin; clat < clatmax; clat++) {
834 int cloni = clonx / GSSH_SUBM,
835 clati = (GSSH_SUBM * 90 + clat) / GSSH_SUBM;
841 cel =
new GshhsPolyCell(fpoly, cloni, clati - 90, &polyHeader);
847 int hash = GSSH_SUBM * (GSSH_SUBM * (90 - clati) + clat - cloni) + clonx;
848 std::vector<wxLineF> *&high_res_map = cel->high_res_map[hash];
849 wxASSERT(hash >= 0 && hash < GSSH_SUBM * GSSH_SUBM);
854 contour_list &poly1 = cel->getPoly1();
856 double minlat = (double)clat / GSSH_SUBM,
857 maxlat = (
double)(clat + 1) / GSSH_SUBM;
858 double minlon = (double)clonx / GSSH_SUBM,
859 maxlon = (
double)(clonx + 1) / GSSH_SUBM;
860 high_res_map =
new std::vector<wxLineF>;
861 for (
unsigned int pi = 0; pi < poly1.size(); pi++) {
862 contour &c = poly1[pi];
863 double lx = c[c.size() - 1].x, ly = c[c.size() - 1].y;
867 int lstatex = lx < minlon ? -1 : lx > maxlon ? 1 : 0;
868 int lstatey = ly < minlat ? -1 : ly > maxlat ? 1 : 0;
870 for (
unsigned int pj = 0; pj < c.size(); pj++) {
871 double clon = c[pj].x, clat = c[pj].y;
876 if (lx == clon && ly == clat)
continue;
878 int statex = clon < minlon ? -1 : clon > maxlon ? 1 : 0;
879 int statey = clat < minlat ? -1 : clat > maxlat ? 1 : 0;
881 if ((!statex || lstatex != statex) &&
882 (!statey || lstatey != statey))
883 high_res_map->push_back(
wxLineF(lx, ly, clon, clat));
885 lx = clon, ly = clat;
886 lstatex = statex, lstatey = statey;
893 for (std::vector<wxLineF>::iterator it2 = high_res_map->begin();
894 it2 != high_res_map->end(); it2++)
895 if (my_intersects(rtrajectWorld, *it2))
return true;
902 void GshhsPolyReader::readPolygonFileHeader(FILE *polyfile,
904 fseek(polyfile, 0, SEEK_SET);
906 wxLogMessage(_T(
"gshhs ReadPolygonFileHeader failed"));
910 void GshhsPolyReader::drawGshhsPolyMapPlain(
ocpnDC &pnt,
ViewPort &vp,
911 wxColor
const &seaColor,
912 wxColor
const &landColor) {
915 pnt.SetPen(wxNullPen);
917 int clonmin, clonmax, clatmax, clatmin;
918 LLBBox bbox = vp.GetBBox();
919 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
920 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
921 if (clatmin <= 0) clatmin--;
922 if (clatmax >= 0) clatmax++;
923 if (clonmin <= 0) clonmin--;
924 if (clonmax >= 0) clonmax++;
925 int dx, clon, clonx, clat;
932 if (vp.m_projection_type != last_rendered_vp.m_projection_type ||
933 (last_rendered_vp.m_projection_type == PROJECTION_POLAR &&
934 last_rendered_vp.clat * vp.clat <= 0)) {
935 last_rendered_vp = vp;
936 for (
int clon = 0; clon < 360; clon++)
937 for (
int clat = 0; clat < 180; clat++)
938 if (allCells[clon][clat]) allCells[clon][clat]->ClearPolyV();
940 #if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
941 glEnableClientState(GL_VERTEX_ARRAY);
945 if (glChartCanvas::HasNormalizedViewPort(vp)) {
947 glChartCanvas::MultMatrixViewPort(vp);
948 nvp = glChartCanvas::NormalizedViewPort(vp);
953 for (clon = clonmin; clon < clonmax; clon++) {
955 while (clonx < 0) clonx += 360;
956 while (clonx >= 360) clonx -= 360;
958 for (clat = clatmin; clat < clatmax; clat++) {
959 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
960 if (allCells[clonx][clat + 90] == NULL) {
963 allCells[clonx][clat + 90] = cel;
965 cel = allCells[clonx][clat + 90];
970 if (vp.m_projection_type != PROJECTION_MERCATOR &&
971 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
973 else if (pnt.GetDC())
981 if (vp.clon - clonn > 180)
983 else if (vp.clon - clonn < -180)
989 cel->drawMapPlain(pnt, dx, nvp, seaColor, landColor, idl);
995 #if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
997 if (glChartCanvas::HasNormalizedViewPort(vp)) glPopMatrix();
998 glDisableClientState(GL_VERTEX_ARRAY);
1005 void GshhsPolyReader::drawGshhsPolyMapSeaBorders(
ocpnDC &pnt,
ViewPort &vp) {
1007 int clonmin, clonmax, clatmax, clatmin;
1008 LLBBox bbox = vp.GetBBox();
1009 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
1010 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
1012 int dx, clon, clonx, clat;
1015 for (clon = clonmin; clon < clonmax; clon++) {
1017 while (clonx < 0) clonx += 360;
1018 while (clonx >= 360) clonx -= 360;
1020 for (clat = clatmin; clat < clatmax; clat++) {
1021 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
1022 if (allCells[clonx][clat + 90] == NULL) {
1025 allCells[clonx][clat + 90] = cel;
1027 cel = allCells[clonx][clat + 90];
1030 cel->drawSeaBorderLines(pnt, dx, vp);
1036 int GshhsPolygon::readInt4() {
1039 unsigned char buf[4];
1042 unsigned char in[4];
1045 nb += fread(&in, 1, 4, file);
1059 int GshhsPolygon::readInt2() {
1062 unsigned char buf[4];
1066 nb += fread(&v.buf[0], 2, 1, file);
1071 return v.buf[1] << 8 | v.buf[0];
1074 GshhsPolygon::GshhsPolygon(FILE *file_) {
1080 west = readInt4() * 1e-6;
1081 east = readInt4() * 1e-6;
1082 south = readInt4() * 1e-6;
1083 north = readInt4() * 1e-6;
1086 if (((flag >> 8) & 255) >= 7) {
1087 areaFull = readInt4();
1088 container = readInt4();
1089 ancestor = readInt4();
1091 greenwich = (flag >> 16) & 1;
1092 antarctic = (west == 0 && east == 360);
1094 double x = 0, y = 0;
1095 for (
int i = 0; i < n; i++) {
1096 x = readInt4() * 1e-6;
1097 if (greenwich && x > 270) x -= 360;
1098 y = readInt4() * 1e-6;
1102 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, y));
1103 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, -90));
1108 greenwich = (flag >> 16) & 1;
1109 antarctic = (west == 0 && east == 360);
1111 for (
int i = 0; i < n; i++) {
1112 double x = 0, y = 0;
1113 x = readInt4() * 1e-6;
1114 if (greenwich && x > 270) x -= 360;
1115 y = readInt4() * 1e-6;
1124 GshhsPolygon::~GshhsPolygon() {
1125 std::vector<GshhsPoint *>::iterator itp;
1126 for (itp = lsPoints.begin(); itp != lsPoints.end(); itp++) {
1135 GshhsReader::GshhsReader() {
1136 maxQualityAvailable = -1;
1137 minQualityAvailable = -1;
1139 for (
int i = 0; i < 5; i++) {
1140 qualityAvailable[i] =
false;
1141 if (GshhsReader::gshhsFilesExists(i)) {
1142 qualityAvailable[i] =
true;
1143 if (minQualityAvailable < 0) minQualityAvailable = i;
1144 maxQualityAvailable = i;
1148 if (maxQualityAvailable < 0) {
1150 _T(
"Unable to initialize background world map. No GSHHS datafiles ")
1152 msg += gWorldMapLocation;
1165 for (
int qual = 0; qual < 5; qual++) {
1166 lsPoly_boundaries[qual] =
new std::vector<GshhsPolygon *>;
1167 lsPoly_rivers[qual] =
new std::vector<GshhsPolygon *>;
1174 int GshhsReader::ReadPolyVersion() {
1175 return gshhsPoly_reader->ReadPolyVersion();
1180 GshhsReader::~GshhsReader() {
1182 delete gshhsPoly_reader;
1186 void GshhsReader::clearLists() {
1187 std::vector<GshhsPolygon *>::iterator itp;
1188 for (
int qual = 0; qual < 5; qual++) {
1189 for (itp = lsPoly_boundaries[qual]->begin();
1190 itp != lsPoly_boundaries[qual]->end(); itp++) {
1194 for (itp = lsPoly_rivers[qual]->begin(); itp != lsPoly_rivers[qual]->end();
1200 lsPoly_boundaries[qual]->clear();
1201 lsPoly_rivers[qual]->clear();
1202 delete lsPoly_boundaries[qual];
1203 delete lsPoly_rivers[qual];
1208 wxString GshhsReader::getNameExtension(
int quality) {
1233 wxString GshhsReader::getFileName_Land(
int quality) {
1234 wxString ext = GshhsReader::getNameExtension(quality);
1236 gWorldMapLocation + wxString::Format(_T(
"poly-%c-1.dat"), ext.GetChar(0));
1240 wxString GshhsReader::getFileName_boundaries(
int quality) {
1241 wxString ext = GshhsReader::getNameExtension(quality);
1242 wxString fname = gWorldMapLocation +
1243 wxString::Format(_T(
"wdb_borders_%c.b"), ext.GetChar(0));
1247 wxString GshhsReader::getFileName_rivers(
int quality) {
1248 wxString ext = GshhsReader::getNameExtension(quality);
1249 wxString fname = gWorldMapLocation +
1250 wxString::Format(_T(
"wdb_rivers_%c.b"), ext.GetChar(0));
1255 bool GshhsReader::gshhsFilesExists(
int quality) {
1256 if (!wxFile::Access(GshhsReader::getFileName_Land(quality), wxFile::read))
1268 void GshhsReader::LoadQuality(
int newQuality)
1270 if (quality == newQuality)
return;
1272 wxStopWatch perftimer;
1276 quality = newQuality;
1279 else if (quality > 4)
1282 gshhsPoly_reader->InitializeLoadQuality(quality);
1284 if( lsPoly_boundaries[quality]->size() == 0 ) {
1285 fname = getFileName_boundaries( quality );
1286 file = fopen( fname.mb_str(),
"rb" );
1288 if( file != NULL ) {
1295 if( poly->getLevel() < 2 )
1296 lsPoly_boundaries[quality]->push_back( poly );
1304 if( lsPoly_rivers[quality]->size() == 0 ) {
1305 fname = getFileName_rivers( quality );
1306 file = fopen( fname.mb_str(),
"rb" );
1307 if( file != NULL ) {
1313 lsPoly_rivers[quality]->push_back( poly );
1321 wxLogMessage(_T(
"Loading World Chart Q=%d in %ld ms."), quality,
1326 std::vector<GshhsPolygon *> &GshhsReader::getList_boundaries() {
1327 return *lsPoly_boundaries[quality];
1330 std::vector<GshhsPolygon *> &GshhsReader::getList_rivers() {
1331 return *lsPoly_rivers[quality];
1336 int GshhsReader::GSHHS_scaledPoints(
GshhsPolygon *pol, wxPoint *pts,
1339 box.Set(pol->south, pol->west + declon, pol->north, pol->east + declon);
1340 if (vp.GetBBox().IntersectOut(box))
return 0;
1344 wxPoint2DDouble p1 = GetDoublePixFromLL(vp, pol->west + declon, pol->north);
1345 wxPoint2DDouble p2 = GetDoublePixFromLL(vp, pol->east + declon, pol->south);
1347 if (p1.m_x == p2.m_x && p1.m_y == p2.m_y)
return 0;
1350 std::vector<GshhsPoint *>::iterator itp;
1351 int xx, yy, oxx = 0, oyy = 0;
1354 for (itp = (pol->lsPoints).begin(); itp != (pol->lsPoints).end(); itp++) {
1355 x = (*itp)->lon + declon;
1357 wxPoint2DDouble p = GetDoublePixFromLL(vp, y, x);
1358 xx = p.m_x, yy = p.m_y;
1359 if (j == 0 || (oxx != xx || oyy != yy)) {
1372 void GshhsReader::GsshDrawLines(
ocpnDC &pnt, std::vector<GshhsPolygon *> &lst,
1374 std::vector<GshhsPolygon *>::iterator iter;
1376 wxPoint *pts = NULL;
1381 pts =
new wxPoint[nbmax];
1384 for (i = 0, iter = lst.begin(); iter != lst.end(); iter++, i++) {
1387 if (nbmax < pol->n + 2) {
1390 pts =
new wxPoint[nbmax];
1394 nbp = GSHHS_scaledPoints(pol, pts, 0, vp);
1396 if (pol->isAntarctic()) {
1399 pnt.DrawLines(nbp, pts);
1402 pnt.DrawLines(nbp, pts);
1404 pnt.DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1408 nbp = GSHHS_scaledPoints(pol, pts, -360, vp);
1410 if (pol->isAntarctic()) {
1413 pnt.DrawLines(nbp, pts);
1416 pnt.DrawLines(nbp, pts);
1418 pnt.DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1427 wxColor
const &seaColor,
1428 wxColor
const &landColor) {
1429 LoadQuality(selectBestQuality(vp));
1430 gshhsPoly_reader->drawGshhsPolyMapPlain(pnt, vp, seaColor, landColor);
1435 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1436 gshhsPoly_reader->drawGshhsPolyMapSeaBorders(pnt, vp);
1441 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1444 wxPen *pen = wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxPENSTYLE_DOT);
1447 wxPen *pen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 80), 2,
1448 wxPENSTYLE_LONG_DASH);
1451 GsshDrawLines(pnt, getList_boundaries(), vp,
false);
1456 GsshDrawLines(pnt, getList_rivers(), vp,
false);
1460 int GshhsReader::selectBestQuality(
ViewPort &vp) {
1461 int bestQuality = 0;
1463 if (vp.chart_scale < 500000 && qualityAvailable[4])
1465 else if (vp.chart_scale < 2000000 && qualityAvailable[3])
1467 else if (vp.chart_scale < 8000000 && qualityAvailable[2])
1469 else if (vp.chart_scale < 20000000 && qualityAvailable[1])
1471 else if (qualityAvailable[0])
1474 while (!qualityAvailable[bestQuality] &&
1480 while (!qualityAvailable[bestQuality]) {
1482 if (bestQuality < 0)
break;
1495 void gshhsCrossesLandInit() {
1500 int bestQuality = 4;
1501 while (!reader->qualityAvailable[bestQuality] && bestQuality > 0)
1503 reader->LoadQuality(bestQuality);
1504 wxLogMessage(
"GSHHG: Loaded quality %d for land crossing detection.",
1508 void gshhsCrossesLandReset() {
1509 if (reader)
delete reader;
1513 bool gshhsCrossesLand(
double lat1,
double lon1,
double lat2,
double lon2) {
1515 gshhsCrossesLandInit();
1517 if (lon1 < 0) lon1 += 360;
1518 if (lon2 < 0) lon2 += 360;
1520 wxLineF trajectWorld(lon1, lat1, lon2, lat2);
1521 return reader->crossing1(trajectWorld);