56#include "glChartCanvas.h"
64#define __CALL_CONVENTION
66#define __CALL_CONVENTION
71extern wxString gWorldMapLocation;
73#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
74static const GLchar *vertex_shader_source =
75 "attribute vec2 position;\n"
76 "uniform mat4 MVMatrix;\n"
77 "uniform mat4 TransformMatrix;\n"
78 "uniform vec4 color;\n"
79 "varying vec4 fragColor;\n"
81 " fragColor = color;\n"
82 " gl_Position = MVMatrix * TransformMatrix * vec4(position, 0.0, 1.0);\n"
85static const GLchar *fragment_shader_source =
86 "precision lowp float;\n"
87 "varying vec4 fragColor;\n"
89 " gl_FragColor = fragColor;\n"
92static const GLfloat vertices2[] = {
93 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f,
96static const GLfloat vertices3[] = {
97 0.0f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, -0.5f, -0.5f, 0.0f,
100enum Consts { INFOLOG_LEN = 512 };
101GLchar infoLog[INFOLOG_LEN];
102GLint fragment_shader;
107extern GLint color_tri_shader_program;
112GSHHSChart::GSHHSChart() {
114 land = wxColor(250, 250, 250);
115 water = wxColor(0, 0, 0);
118GSHHSChart::~GSHHSChart() {
119 if (reader)
delete reader;
122void GSHHSChart::SetColorScheme(ColorScheme scheme) {
123 land = wxColor(170, 175, 80);
124 water = wxColor(170, 195, 240);
129 case GLOBAL_COLOR_SCHEME_DUSK:
132 case GLOBAL_COLOR_SCHEME_NIGHT:
139 land.Set(land.Red() * dim, land.Green() * dim, land.Blue() * dim);
140 water.Set(water.Red() * dim, water.Green() * dim, water.Blue() * dim);
143void GSHHSChart::SetColorsDirect(wxColour newLand, wxColour newWater) {
148void GSHHSChart::Reset() {
149 if (reader)
delete reader;
151 gshhsCrossesLandReset();
154int GSHHSChart::GetMinAvailableQuality() {
156 return reader->GetMinAvailableQuality();
159int GSHHSChart::GetMaxAvailableQuality() {
161 return reader->GetMaxAvailableQuality();
167 if (reader->GetPolyVersion() < 210 || reader->GetPolyVersion() > 240) {
169 _T(
"GSHHS World chart files have wrong version. Found %d, expected ")
171 reader->GetPolyVersion());
174 _T(
"Background world map loaded from GSHHS datafiles found in: ") +
179 reader->drawContinents(dc, vp, water, land);
185GshhsPolyCell::GshhsPolyCell(FILE *fpoly_,
int x0_,
int y0_,
192 for (
int i = 0; i < 6; i++) polyv[i] = NULL;
196 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++) high_res_map[i] = NULL;
199GshhsPolyCell::~GshhsPolyCell() {
202 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++)
delete high_res_map[i];
203 for (
int i = 0; i < 6; i++)
delete[] polyv[i];
206void GshhsPolyCell::ClearPolyV() {
207 for (
int i = 0; i < 6; i++) {
213void GshhsPolyCell::ReadPoly(contour_list &poly) {
216 int32_t num_vertices, num_contours;
218 if (fread(&num_contours,
sizeof num_contours, 1, fpoly) != 1)
goto fail;
220 for (
int c = 0; c < num_contours; c++) {
222 if (fread(&value,
sizeof value, 1, fpoly) !=
224 fread(&value,
sizeof value, 1, fpoly) != 1)
227 num_vertices = value;
230 for (
int v = 0; v < num_vertices; v++) {
231 if (fread(&X,
sizeof X, 1, fpoly) != 1 ||
232 fread(&Y,
sizeof Y, 1, fpoly) != 1)
235 tmp_contour.push_back(wxRealPoint(X * GSHHS_SCL, Y * GSHHS_SCL));
237 poly.push_back(tmp_contour);
242 wxLogMessage(_T(
"gshhs ReadPoly failed"));
245void GshhsPolyCell::ReadPolygonFile() {
251 tab_data = (x0cell / header->pasx) * (180 / header->pasy) +
252 (y0cell + 90) / header->pasy;
254 if (fread(&pos_data,
sizeof(
int), 1, fpoly) != 1)
goto fail;
256 fseek(fpoly, pos_data, SEEK_SET);
266 wxLogMessage(_T(
"gshhs ReadPolygon failed"));
269wxPoint2DDouble GetDoublePixFromLL(
ViewPort &vp,
double lat,
double lon) {
270 wxPoint2DDouble p = vp.GetDoublePixFromLL(lat, lon);
271 p.m_x -= vp.rv_rect.x, p.m_y -= vp.rv_rect.y;
275void GshhsPolyCell::DrawPolygonFilled(
ocpnDC &pnt, contour_list *p,
double dx,
276 ViewPort &vp, wxColor
const &color) {
290 for (c = 0; c < p->size(); c++) {
291 if (!p->at(c).size())
continue;
293 wxPoint *poly_pt =
new wxPoint[p->at(c).size()];
295 contour &cp = p->at(c);
298 for (v = 0; v < p->at(c).size(); v++) {
299 wxRealPoint &ccp = cp.at(v);
300 wxPoint2DDouble q = GetDoublePixFromLL(vp, ccp.y, ccp.x + dx);
301 if (std::isnan(q.m_x)) {
306 x = q.m_x, y = q.m_y;
308 if (v == 0 || x != x_old || y != y_old) {
309 poly_pt[pointCount].x = x;
310 poly_pt[pointCount].y = y;
317 if (pointCount > 1) pnt.DrawPolygonTessellated(pointCount, poly_pt, 0, 0);
339static std::list<float_2Dpt> g_pv;
340static std::list<GLvertex *> g_vertexes;
341static int g_type, g_pos;
342static float_2Dpt g_p1, g_p2;
344void __CALL_CONVENTION gshhscombineCallback(GLdouble coords[3],
345 GLdouble *vertex_data[4],
347 GLdouble **dataOut) {
350 vertex =
new GLvertex();
351 g_vertexes.push_back(vertex);
353 vertex->info.x = coords[0];
354 vertex->info.y = coords[1];
356 *dataOut = vertex->data;
359void __CALL_CONVENTION gshhsvertexCallback(GLvoid *arg) {
361 vertex = (GLvertex *)arg;
363 p.y = vertex->info.x;
364 p.x = vertex->info.y;
367 if (g_type != GL_TRIANGLES) {
369 g_pv.push_back(g_p1);
370 g_pv.push_back(g_p2);
373 if (g_type == GL_TRIANGLE_STRIP)
384void __CALL_CONVENTION gshhserrorCallback(GLenum errorCode) {
385 const GLubyte *estring;
386 estring = gluErrorString(errorCode);
390void __CALL_CONVENTION gshhsbeginCallback(GLenum type) {
393 case GL_TRIANGLE_STRIP:
394 case GL_TRIANGLE_FAN:
398 printf(
"tess unhandled begin type: %d\n", type);
404void __CALL_CONVENTION gshhsendCallback() {}
406void GshhsPolyCell::DrawPolygonFilledGL(
ocpnDC &pnt, contour_list *p, float_2Dpt **pv,
408 wxColor
const &color,
bool idl) {
415 for (
unsigned int c = 0; c < p->size(); c++) {
416 if (!p->at(c).size())
continue;
418 contour &cp = p->at(c);
420 GLUtesselator *tobj = gluNewTess();
422 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&gshhsvertexCallback);
423 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&gshhsbeginCallback);
424 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&gshhsendCallback);
425 gluTessCallback(tobj, GLU_TESS_COMBINE,
426 (_GLUfuncptr)&gshhscombineCallback);
427 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&gshhserrorCallback);
429 gluTessNormal(tobj, 0, 0, 1);
430 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
432 gluTessBeginPolygon(tobj, NULL);
433 gluTessBeginContour(tobj);
435 for (
unsigned int v = 0; v < p->at(c).size(); v++) {
436 wxRealPoint &ccp = cp.at(v);
438 if (v == 0 || ccp != cp.at(v - 1)) {
439 GLvertex *vertex =
new GLvertex();
440 g_vertexes.push_back(vertex);
443 if (glChartCanvas::HasNormalizedViewPort(vp))
444 q = GetDoublePixFromLL(vp, ccp.y, ccp.x);
446 q.m_x = ccp.y, q.m_y = ccp.x;
448 if (vp.m_projection_type != PROJECTION_POLAR) {
452 if (idl && ccp.x == 180) {
453 if (vp.m_projection_type == PROJECTION_MERCATOR ||
454 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)
462 vertex->info.x = q.m_x;
463 vertex->info.y = q.m_y;
465 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
469 gluTessEndContour(tobj);
470 gluTessEndPolygon(tobj);
473 for (std::list<GLvertex *>::iterator it = g_vertexes.begin();
474 it != g_vertexes.end(); it++)
479 *pv =
new float_2Dpt[g_pv.size()];
481 for (std::list<float_2Dpt>::iterator it = g_pv.begin(); it != g_pv.end();
489#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
493 if (!vertex_shader) {
495 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
496 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
497 glCompileShader(vertex_shader);
498 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
500 glGetShaderInfoLog(vertex_shader, INFOLOG_LEN, NULL, infoLog);
501 printf(
"ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
505 if (!fragment_shader) {
507 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
508 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
509 glCompileShader(fragment_shader);
510 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
512 glGetShaderInfoLog(fragment_shader, INFOLOG_LEN, NULL, infoLog);
513 printf(
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
517 if (!shader_program) {
519 shader_program = glCreateProgram();
520 glAttachShader(shader_program, vertex_shader);
521 glAttachShader(shader_program, fragment_shader);
522 glLinkProgram(shader_program);
523 glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
525 glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
526 printf(
"ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
535 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)vp.pix_width,
536 2.0 / (
float)vp.pix_height, 1.0);
537 mat4x4_translate_in_place(mvp, -vp.pix_width / 2, vp.pix_height / 2, 0);
539 if (glChartCanvas::HasNormalizedViewPort(vp)) {
541 GLint pos = glGetAttribLocation(color_tri_shader_program,
"position");
542 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), *pv);
543 glEnableVertexAttribArray(pos);
549 GLint tmatloc = glGetUniformLocation(color_tri_shader_program,
"TransformMatrix");
550 glUniformMatrix4fv(tmatloc, 1, GL_FALSE, (
const GLfloat*)m);
552 glUseProgram(color_tri_shader_program);
553 glDrawArrays(GL_TRIANGLES, 0, *pvc);
556 float *pvt =
new float[2 * (*pvc)];
557 for (
int i = 0; i < *pvc; i++) {
558 float_2Dpt *pc = *pv + i;
559 wxPoint2DDouble q = vp.GetDoublePixFromLL(pc->y, pc->x);
561 pvt[(i * 2) + 1] = q.m_y;
564 GLShaderProgram *shader = pcolor_tri_shader_program[pnt.m_canvasIndex];
568 colorv[0] = color.Red() / float(256);
569 colorv[1] = color.Green() / float(256);
570 colorv[2] = color.Blue() / float(256);
572 shader->SetUniform4fv(
"color", colorv);
574 shader->SetAttributePointerf(
"position", pvt);
576 glDrawArrays(GL_TRIANGLES, 0, *pvc);
579 glDeleteBuffers(1, &vbo);
589#define DRAW_POLY_FILLED(POLY, COL) \
590 if (POLY) DrawPolygonFilled(pnt, POLY, dx, vp, COL);
591#define DRAW_POLY_FILLED_GL(NUM, COL) \
592 DrawPolygonFilledGL(pnt,&poly##NUM, &polyv[NUM], &polyc[NUM], vp, COL, idl);
594void GshhsPolyCell::drawMapPlain(
ocpnDC &pnt,
double dx,
ViewPort &vp,
595 wxColor seaColor, wxColor landColor,
599#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
600#define NORM_FACTOR 4096.0
601 if (dx && (vp.m_projection_type == PROJECTION_MERCATOR ||
602 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
604 40058986 * NORM_FACTOR;
606 glTranslated(dx > 0 ? ts : -ts, 0, 0);
609 DRAW_POLY_FILLED_GL(1, landColor);
610 DRAW_POLY_FILLED_GL(2, seaColor);
611 DRAW_POLY_FILLED_GL(3, landColor);
612 DRAW_POLY_FILLED_GL(4, seaColor);
613 DRAW_POLY_FILLED_GL(5, landColor);
615#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
616 if (dx) glPopMatrix();
622 DRAW_POLY_FILLED(&poly1, landColor);
623 DRAW_POLY_FILLED(&poly2, seaColor);
624 DRAW_POLY_FILLED(&poly3, landColor);
625 DRAW_POLY_FILLED(&poly4, seaColor);
626 DRAW_POLY_FILLED(&poly5, landColor);
630void GshhsPolyCell::DrawPolygonContour(
ocpnDC &pnt, contour_list *p,
double dx,
632 double x1, y1, x2, y2;
633 double long_max, lat_max, long_min, lat_min;
635 long_min = (double)x0cell;
636 lat_min = (double)y0cell;
637 long_max = ((double)x0cell + (
double)header->pasx);
638 lat_max = ((double)y0cell + (
double)header->pasy);
642 for (
unsigned int i = 0; i < p->size(); i++) {
643 if (!p->at(i).size())
continue;
646 for (v = 0; v < (p->at(i).size() - 1); v++) {
647 x1 = p->at(i).at(v).x;
648 y1 = p->at(i).at(v).y;
649 x2 = p->at(i).at(v + 1).x;
650 y2 = p->at(i).at(v + 1).y;
653 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
654 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
655 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
656 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
657 pnt.DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
661 x1 = p->at(i).at(v).x;
662 y1 = p->at(i).at(v).y;
663 x2 = p->at(i).at(0).x;
664 y2 = p->at(i).at(0).y;
666 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
667 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
668 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
669 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
670 pnt.DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
675#define DRAW_POLY_CONTOUR(POLY) \
676 if (POLY) DrawPolygonContour(pnt, POLY, dx, vp);
678void GshhsPolyCell::drawSeaBorderLines(
ocpnDC &pnt,
double dx,
ViewPort &vp) {
680 DRAW_POLY_CONTOUR(&poly1)
681 DRAW_POLY_CONTOUR(&poly2)
682 DRAW_POLY_CONTOUR(&poly3)
683 DRAW_POLY_CONTOUR(&poly4)
684 DRAW_POLY_CONTOUR(&poly5)
689GshhsPolyReader::GshhsPolyReader(
int quality) {
692 for (
int i = 0; i < 360; i++) {
693 for (
int j = 0; j < 180; j++) {
694 allCells[i][j] = NULL;
698 polyHeader.version = -1;
699 InitializeLoadQuality(quality);
703GshhsPolyReader::~GshhsPolyReader() {
704 for (
int i = 0; i < 360; i++) {
705 for (
int j = 0; j < 180; j++) {
706 if (allCells[i][j] != NULL) {
707 delete allCells[i][j];
708 allCells[i][j] = NULL;
719int GshhsPolyReader::ReadPolyVersion() {
720 wxString fname = GshhsReader::getFileName_Land(0);
721 if (fpoly) fclose(fpoly);
722 fpoly = fopen(fname.mb_str(),
"rb");
725 if (!fpoly)
return 0;
727 readPolygonFileHeader(fpoly, &polyHeader);
729 return polyHeader.version;
732void GshhsPolyReader::InitializeLoadQuality(
735 if (currentQuality != quality) {
736 currentQuality = quality;
738 wxString fname = GshhsReader::getFileName_Land(quality);
740 if (fpoly) fclose(fpoly);
742 fpoly = fopen(fname.mb_str(),
"rb");
743 if (fpoly) readPolygonFileHeader(fpoly, &polyHeader);
745 for (
int i = 0; i < 360; i++) {
746 for (
int j = 0; j < 180; j++) {
747 if (allCells[i][j] != NULL) {
748 delete allCells[i][j];
749 allCells[i][j] = NULL;
756static inline bool my_intersects(
const wxLineF &line1,
const wxLineF &line2) {
757 double x1 = line1.m_p1.x, y1 = line1.m_p1.y, x2 = line1.m_p2.x,
759 double x3 = line2.m_p1.x, y3 = line2.m_p1.y, x4 = line2.m_p2.x,
764 double ax = x2 - x1, ay = y2 - y1;
765 double bx = x3 - x4, by = y3 - y4;
766 double cx = x1 - x3, cy = y1 - y3;
768#define INTER_LIMIT 1e-7
769 double denominator = ay * bx - ax * by;
770 if (denominator < 1e-10) {
771 if (fabs((y1 * ax - ay * x1) * bx - (y3 * bx - by * x3) * ax) > INTER_LIMIT)
773 if (fabs((x1 * ay - ax * y1) * by - (x3 * by - bx * y3) * ay) > INTER_LIMIT)
779 const double reciprocal = 1 / denominator;
780 const double na = (by * cx - bx * cy) * reciprocal;
782 if (na < -INTER_LIMIT || na > 1 + INTER_LIMIT)
return false;
784 const double nb = (ax * cy - ay * cx) * reciprocal;
785 if (nb < -INTER_LIMIT || nb > 1 + INTER_LIMIT)
return false;
790bool GshhsPolyReader::crossing1(
wxLineF trajectWorld) {
791 double x1 = trajectWorld.p1().x, y1 = trajectWorld.p1().y;
792 double x2 = trajectWorld.p2().x, y2 = trajectWorld.p2().y;
794 int clonmin, clonmax, clatmax, clatmin;
795 clonmin = (int)floor(GSSH_SUBM * wxMin(x1, x2));
796 clonmax = (int)ceil(GSSH_SUBM * wxMax(x1, x2));
799 clonmin += GSSH_SUBM * 360;
800 clonmax += GSSH_SUBM * 360;
803 if (clonmax - clonmin > GSSH_SUBM * 180) {
804 clonmin = (int)floor(GSSH_SUBM * wxMax(x1, x2)) - GSSH_SUBM * 360;
805 clonmax = (int)ceil(GSSH_SUBM * wxMin(x1, x2));
808 clatmin = (int)floor(GSSH_SUBM * wxMin(y1, y2));
809 clatmax = (int)ceil(GSSH_SUBM * wxMax(y1, y2));
810 wxASSERT(clatmin >= -GSSH_SUBM * 90 && clatmax <= GSSH_SUBM * 89);
816 int clon, clonx, clat;
817 for (clon = clonmin; clon < clonmax; clon++) {
819 while (clonx < 0) clonx += GSSH_SUBM * 360;
820 while (clonx >= GSSH_SUBM * 360) clonx -= GSSH_SUBM * 360;
822 wxASSERT(clonx >= 0 && clonx < GSSH_SUBM * 360);
824 if (clonx < GSSH_SUBM * 180) {
825 if (x1 > 180) x1 -= 360;
826 if (x2 > 180) x2 -= 360;
828 if (x1 < 180) x1 += 360;
829 if (x2 < 180) x2 += 360;
832 wxLineF rtrajectWorld(x1, y1, x2, y2);
834 for (clat = clatmin; clat < clatmax; clat++) {
835 int cloni = clonx / GSSH_SUBM,
836 clati = (GSSH_SUBM * 90 + clat) / GSSH_SUBM;
842 cel =
new GshhsPolyCell(fpoly, cloni, clati - 90, &polyHeader);
848 int hash = GSSH_SUBM * (GSSH_SUBM * (90 - clati) + clat - cloni) + clonx;
849 std::vector<wxLineF> *&high_res_map = cel->high_res_map[hash];
850 wxASSERT(hash >= 0 && hash < GSSH_SUBM * GSSH_SUBM);
855 contour_list &poly1 = cel->getPoly1();
857 double minlat = (double)clat / GSSH_SUBM,
858 maxlat = (
double)(clat + 1) / GSSH_SUBM;
859 double minlon = (double)clonx / GSSH_SUBM,
860 maxlon = (
double)(clonx + 1) / GSSH_SUBM;
861 high_res_map =
new std::vector<wxLineF>;
862 for (
unsigned int pi = 0; pi < poly1.size(); pi++) {
863 contour &c = poly1[pi];
864 double lx = c[c.size() - 1].x, ly = c[c.size() - 1].y;
868 int lstatex = lx < minlon ? -1 : lx > maxlon ? 1 : 0;
869 int lstatey = ly < minlat ? -1 : ly > maxlat ? 1 : 0;
871 for (
unsigned int pj = 0; pj < c.size(); pj++) {
872 double clon = c[pj].x, clat = c[pj].y;
877 if (lx == clon && ly == clat)
continue;
879 int statex = clon < minlon ? -1 : clon > maxlon ? 1 : 0;
880 int statey = clat < minlat ? -1 : clat > maxlat ? 1 : 0;
882 if ((!statex || lstatex != statex) &&
883 (!statey || lstatey != statey))
884 high_res_map->push_back(
wxLineF(lx, ly, clon, clat));
886 lx = clon, ly = clat;
887 lstatex = statex, lstatey = statey;
894 for (std::vector<wxLineF>::iterator it2 = high_res_map->begin();
895 it2 != high_res_map->end(); it2++)
896 if (my_intersects(rtrajectWorld, *it2))
return true;
903void GshhsPolyReader::readPolygonFileHeader(FILE *polyfile,
905 fseek(polyfile, 0, SEEK_SET);
907 wxLogMessage(_T(
"gshhs ReadPolygonFileHeader failed"));
911void GshhsPolyReader::drawGshhsPolyMapPlain(
ocpnDC &pnt,
ViewPort &vp,
912 wxColor
const &seaColor,
913 wxColor
const &landColor) {
916 pnt.SetPen(wxNullPen);
918 int clonmin, clonmax, clatmax, clatmin;
919 LLBBox bbox = vp.GetBBox();
920 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
921 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
922 if (clatmin <= 0) clatmin--;
923 if (clatmax >= 0) clatmax++;
924 if (clonmin <= 0) clonmin--;
925 if (clonmax >= 0) clonmax++;
926 int dx, clon, clonx, clat;
933 if (vp.m_projection_type != last_rendered_vp.m_projection_type ||
934 (last_rendered_vp.m_projection_type == PROJECTION_POLAR &&
935 last_rendered_vp.clat * vp.clat <= 0)) {
936 last_rendered_vp = vp;
937 for (
int clon = 0; clon < 360; clon++)
938 for (
int clat = 0; clat < 180; clat++)
939 if (allCells[clon][clat]) allCells[clon][clat]->ClearPolyV();
941#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
942 glEnableClientState(GL_VERTEX_ARRAY);
946 if (glChartCanvas::HasNormalizedViewPort(vp)) {
948 glChartCanvas::MultMatrixViewPort(vp);
949 nvp = glChartCanvas::NormalizedViewPort(vp);
954 for (clon = clonmin; clon < clonmax; clon++) {
956 while (clonx < 0) clonx += 360;
957 while (clonx >= 360) clonx -= 360;
959 for (clat = clatmin; clat < clatmax; clat++) {
960 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
961 if (allCells[clonx][clat + 90] == NULL) {
964 allCells[clonx][clat + 90] = cel;
966 cel = allCells[clonx][clat + 90];
971 if (vp.m_projection_type != PROJECTION_MERCATOR &&
972 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
974 else if (pnt.GetDC())
982 if (vp.clon - clonn > 180)
984 else if (vp.clon - clonn < -180)
990 cel->drawMapPlain(pnt, dx, nvp, seaColor, landColor, idl);
996#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
998 if (glChartCanvas::HasNormalizedViewPort(vp)) glPopMatrix();
999 glDisableClientState(GL_VERTEX_ARRAY);
1006void GshhsPolyReader::drawGshhsPolyMapSeaBorders(
ocpnDC &pnt,
ViewPort &vp) {
1008 int clonmin, clonmax, clatmax, clatmin;
1009 LLBBox bbox = vp.GetBBox();
1010 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
1011 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
1013 int dx, clon, clonx, clat;
1016 for (clon = clonmin; clon < clonmax; clon++) {
1018 while (clonx < 0) clonx += 360;
1019 while (clonx >= 360) clonx -= 360;
1021 for (clat = clatmin; clat < clatmax; clat++) {
1022 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
1023 if (allCells[clonx][clat + 90] == NULL) {
1026 allCells[clonx][clat + 90] = cel;
1028 cel = allCells[clonx][clat + 90];
1031 cel->drawSeaBorderLines(pnt, dx, vp);
1037int GshhsPolygon::readInt4() {
1040 unsigned char buf[4];
1043 unsigned char in[4];
1046 nb += fread(&in, 1, 4, file);
1060int GshhsPolygon::readInt2() {
1063 unsigned char buf[4];
1067 nb += fread(&v.buf[0], 2, 1, file);
1072 return v.buf[1] << 8 | v.buf[0];
1075GshhsPolygon::GshhsPolygon(FILE *file_) {
1081 west = readInt4() * 1e-6;
1082 east = readInt4() * 1e-6;
1083 south = readInt4() * 1e-6;
1084 north = readInt4() * 1e-6;
1087 if (((flag >> 8) & 255) >= 7) {
1088 areaFull = readInt4();
1089 container = readInt4();
1090 ancestor = readInt4();
1092 greenwich = (flag >> 16) & 1;
1093 antarctic = (west == 0 && east == 360);
1095 double x = 0, y = 0;
1096 for (
int i = 0; i < n; i++) {
1097 x = readInt4() * 1e-6;
1098 if (greenwich && x > 270) x -= 360;
1099 y = readInt4() * 1e-6;
1103 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, y));
1104 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, -90));
1109 greenwich = (flag >> 16) & 1;
1110 antarctic = (west == 0 && east == 360);
1112 for (
int i = 0; i < n; i++) {
1113 double x = 0, y = 0;
1114 x = readInt4() * 1e-6;
1115 if (greenwich && x > 270) x -= 360;
1116 y = readInt4() * 1e-6;
1125GshhsPolygon::~GshhsPolygon() {
1126 std::vector<GshhsPoint *>::iterator itp;
1127 for (itp = lsPoints.begin(); itp != lsPoints.end(); itp++) {
1136GshhsReader::GshhsReader() {
1137 maxQualityAvailable = -1;
1138 minQualityAvailable = -1;
1140 for (
int i = 0; i < 5; i++) {
1141 qualityAvailable[i] =
false;
1142 if (GshhsReader::gshhsFilesExists(i)) {
1143 qualityAvailable[i] =
true;
1144 if (minQualityAvailable < 0) minQualityAvailable = i;
1145 maxQualityAvailable = i;
1149 if (maxQualityAvailable < 0) {
1151 _T(
"Unable to initialize background world map. No GSHHS datafiles ")
1153 msg += gWorldMapLocation;
1166 for (
int qual = 0; qual < 5; qual++) {
1167 lsPoly_boundaries[qual] =
new std::vector<GshhsPolygon *>;
1168 lsPoly_rivers[qual] =
new std::vector<GshhsPolygon *>;
1175int GshhsReader::ReadPolyVersion() {
1176 return gshhsPoly_reader->ReadPolyVersion();
1181GshhsReader::~GshhsReader() {
1183 delete gshhsPoly_reader;
1187void GshhsReader::clearLists() {
1188 std::vector<GshhsPolygon *>::iterator itp;
1189 for (
int qual = 0; qual < 5; qual++) {
1190 for (itp = lsPoly_boundaries[qual]->begin();
1191 itp != lsPoly_boundaries[qual]->end(); itp++) {
1195 for (itp = lsPoly_rivers[qual]->begin(); itp != lsPoly_rivers[qual]->end();
1201 lsPoly_boundaries[qual]->clear();
1202 lsPoly_rivers[qual]->clear();
1203 delete lsPoly_boundaries[qual];
1204 delete lsPoly_rivers[qual];
1209wxString GshhsReader::getNameExtension(
int quality) {
1234wxString GshhsReader::getFileName_Land(
int quality) {
1235 wxString ext = GshhsReader::getNameExtension(quality);
1237 gWorldMapLocation + wxString::Format(_T(
"poly-%c-1.dat"), ext.GetChar(0));
1241wxString GshhsReader::getFileName_boundaries(
int quality) {
1242 wxString ext = GshhsReader::getNameExtension(quality);
1243 wxString fname = gWorldMapLocation +
1244 wxString::Format(_T(
"wdb_borders_%c.b"), ext.GetChar(0));
1248wxString GshhsReader::getFileName_rivers(
int quality) {
1249 wxString ext = GshhsReader::getNameExtension(quality);
1250 wxString fname = gWorldMapLocation +
1251 wxString::Format(_T(
"wdb_rivers_%c.b"), ext.GetChar(0));
1256bool GshhsReader::gshhsFilesExists(
int quality) {
1257 if (!wxFile::Access(GshhsReader::getFileName_Land(quality), wxFile::read))
1269void GshhsReader::LoadQuality(
int newQuality)
1271 if (quality == newQuality)
return;
1273 wxStopWatch perftimer;
1277 quality = newQuality;
1280 else if (quality > 4)
1283 gshhsPoly_reader->InitializeLoadQuality(quality);
1285 if( lsPoly_boundaries[quality]->size() == 0 ) {
1286 fname = getFileName_boundaries( quality );
1287 file = fopen( fname.mb_str(),
"rb" );
1289 if( file != NULL ) {
1296 if( poly->getLevel() < 2 )
1297 lsPoly_boundaries[quality]->push_back( poly );
1305 if( lsPoly_rivers[quality]->size() == 0 ) {
1306 fname = getFileName_rivers( quality );
1307 file = fopen( fname.mb_str(),
"rb" );
1308 if( file != NULL ) {
1314 lsPoly_rivers[quality]->push_back( poly );
1322 wxLogMessage(_T(
"Loading World Chart Q=%d in %ld ms."), quality,
1327std::vector<GshhsPolygon *> &GshhsReader::getList_boundaries() {
1328 return *lsPoly_boundaries[quality];
1331std::vector<GshhsPolygon *> &GshhsReader::getList_rivers() {
1332 return *lsPoly_rivers[quality];
1337int GshhsReader::GSHHS_scaledPoints(
GshhsPolygon *pol, wxPoint *pts,
1340 box.Set(pol->south, pol->west + declon, pol->north, pol->east + declon);
1341 if (vp.GetBBox().IntersectOut(box))
return 0;
1345 wxPoint2DDouble p1 = GetDoublePixFromLL(vp, pol->west + declon, pol->north);
1346 wxPoint2DDouble p2 = GetDoublePixFromLL(vp, pol->east + declon, pol->south);
1348 if (p1.m_x == p2.m_x && p1.m_y == p2.m_y)
return 0;
1351 std::vector<GshhsPoint *>::iterator itp;
1352 int xx, yy, oxx = 0, oyy = 0;
1355 for (itp = (pol->lsPoints).begin(); itp != (pol->lsPoints).end(); itp++) {
1356 x = (*itp)->lon + declon;
1358 wxPoint2DDouble p = GetDoublePixFromLL(vp, y, x);
1359 xx = p.m_x, yy = p.m_y;
1360 if (j == 0 || (oxx != xx || oyy != yy)) {
1373void GshhsReader::GsshDrawLines(
ocpnDC &pnt, std::vector<GshhsPolygon *> &lst,
1375 std::vector<GshhsPolygon *>::iterator iter;
1377 wxPoint *pts = NULL;
1382 pts =
new wxPoint[nbmax];
1385 for (i = 0, iter = lst.begin(); iter != lst.end(); iter++, i++) {
1388 if (nbmax < pol->n + 2) {
1391 pts =
new wxPoint[nbmax];
1395 nbp = GSHHS_scaledPoints(pol, pts, 0, vp);
1397 if (pol->isAntarctic()) {
1400 pnt.DrawLines(nbp, pts);
1403 pnt.DrawLines(nbp, pts);
1405 pnt.DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1409 nbp = GSHHS_scaledPoints(pol, pts, -360, vp);
1411 if (pol->isAntarctic()) {
1414 pnt.DrawLines(nbp, pts);
1417 pnt.DrawLines(nbp, pts);
1419 pnt.DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1428 wxColor
const &seaColor,
1429 wxColor
const &landColor) {
1430 LoadQuality(selectBestQuality(vp));
1431 gshhsPoly_reader->drawGshhsPolyMapPlain(pnt, vp, seaColor, landColor);
1436 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1437 gshhsPoly_reader->drawGshhsPolyMapSeaBorders(pnt, vp);
1442 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1445 wxPen *pen = wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxPENSTYLE_DOT);
1448 wxPen *pen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 80), 2,
1449 wxPENSTYLE_LONG_DASH);
1452 GsshDrawLines(pnt, getList_boundaries(), vp,
false);
1457 GsshDrawLines(pnt, getList_rivers(), vp,
false);
1461int GshhsReader::selectBestQuality(
ViewPort &vp) {
1462 int bestQuality = 0;
1464 if (vp.chart_scale < 500000 && qualityAvailable[4])
1466 else if (vp.chart_scale < 2000000 && qualityAvailable[3])
1468 else if (vp.chart_scale < 8000000 && qualityAvailable[2])
1470 else if (vp.chart_scale < 20000000 && qualityAvailable[1])
1472 else if (qualityAvailable[0])
1475 while (!qualityAvailable[bestQuality] &&
1481 while (!qualityAvailable[bestQuality]) {
1483 if (bestQuality < 0)
break;
1496void gshhsCrossesLandInit() {
1501 int bestQuality = 4;
1502 while (!reader->qualityAvailable[bestQuality] && bestQuality > 0)
1504 reader->LoadQuality(bestQuality);
1505 wxLogMessage(
"GSHHG: Loaded quality %d for land crossing detection.",
1509void gshhsCrossesLandReset() {
1510 if (reader)
delete reader;
1514bool gshhsCrossesLand(
double lat1,
double lon1,
double lat2,
double lon2) {
1516 gshhsCrossesLandInit();
1518 if (lon1 < 0) lon1 += 360;
1519 if (lon2 < 0) lon2 += 360;
1521 wxLineF trajectWorld(lon1, lat1, lon2, lat2);
1522 return reader->crossing1(trajectWorld);