60#define __CALL_CONVENTION
62#define __CALL_CONVENTION
65#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
66static const GLchar *vertex_shader_source =
67 "attribute vec2 position;\n"
68 "uniform mat4 MVMatrix;\n"
69 "uniform mat4 TransformMatrix;\n"
70 "uniform vec4 color;\n"
71 "varying vec4 fragColor;\n"
73 " fragColor = color;\n"
74 " gl_Position = MVMatrix * TransformMatrix * vec4(position, 0.0, 1.0);\n"
77static const GLchar *fragment_shader_source =
78 "precision lowp float;\n"
79 "varying vec4 fragColor;\n"
81 " gl_FragColor = fragColor;\n"
84static const GLfloat vertices2[] = {
85 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f,
88static const GLfloat vertices3[] = {
89 0.0f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, -0.5f, -0.5f, 0.0f,
92enum Consts { INFOLOG_LEN = 512 };
93static GLchar infoLog[INFOLOG_LEN];
94static GLint fragment_shader;
96static GLint vertex_shader;
98extern GLint color_tri_shader_program;
103GSHHSChart::GSHHSChart() {
105 land = wxColor(250, 250, 250);
106 water = wxColor(0, 0, 0);
109GSHHSChart::~GSHHSChart() {
110 if (reader)
delete reader;
113void GSHHSChart::SetColorScheme(ColorScheme scheme) {
114 land = wxColor(170, 175, 80);
115 water = wxColor(170, 195, 240);
120 case GLOBAL_COLOR_SCHEME_DUSK:
123 case GLOBAL_COLOR_SCHEME_NIGHT:
124 case GLOBAL_COLOR_SCHEME_NIGHT_HICON:
131 land.Set(land.Red() * dim, land.Green() * dim, land.Blue() * dim);
132 water.Set(water.Red() * dim, water.Green() * dim, water.Blue() * dim);
135void GSHHSChart::SetColorsDirect(wxColour newLand, wxColour newWater) {
140void GSHHSChart::Reset() {
141 if (reader)
delete reader;
145int GSHHSChart::GetMinAvailableQuality() {
147 return reader->GetMinAvailableQuality();
150int GSHHSChart::GetMaxAvailableQuality() {
152 return reader->GetMaxAvailableQuality();
158 if (reader->GetPolyVersion() < 210 || reader->GetPolyVersion() > 240) {
160 "GSHHS World chart files have wrong version. Found %d, expected "
162 reader->GetPolyVersion());
165 "Background world map loaded from GSHHS datafiles found in: " +
170 reader->drawContinents(dc, vp, water, land);
176GshhsPolyCell::GshhsPolyCell(FILE *fpoly_,
int x0_,
int y0_,
183 for (
int i = 0; i < 6; i++) polyv[i] = NULL;
187 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++) high_res_map[i] = NULL;
190GshhsPolyCell::~GshhsPolyCell() {
193 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++)
delete high_res_map[i];
194 for (
int i = 0; i < 6; i++)
delete[] polyv[i];
197void GshhsPolyCell::ClearPolyV() {
198 for (
int i = 0; i < 6; i++) {
204void GshhsPolyCell::ReadPoly(contour_list &poly) {
207 int32_t num_vertices, num_contours;
209 if (fread(&num_contours,
sizeof num_contours, 1, fpoly) != 1)
goto fail;
211 for (
int c = 0; c < num_contours; c++) {
213 if (fread(&value,
sizeof value, 1, fpoly) !=
215 fread(&value,
sizeof value, 1, fpoly) != 1)
218 num_vertices = value;
221 for (
int v = 0; v < num_vertices; v++) {
222 if (fread(&X,
sizeof X, 1, fpoly) != 1 ||
223 fread(&Y,
sizeof Y, 1, fpoly) != 1)
226 tmp_contour.push_back(wxRealPoint(X * GSHHS_SCL, Y * GSHHS_SCL));
228 poly.push_back(tmp_contour);
233 wxLogMessage(
"gshhs ReadPoly failed");
236void GshhsPolyCell::ReadPolygonFile() {
242 tab_data = (x0cell / header->pasx) * (180 / header->pasy) +
243 (y0cell + 90) / header->pasy;
245 if (fread(&pos_data,
sizeof(
int), 1, fpoly) != 1)
goto fail;
247 fseek(fpoly, pos_data, SEEK_SET);
257 wxLogMessage(
"gshhs ReadPolygon failed");
260wxPoint2DDouble GetDoublePixFromLL(
ViewPort &vp,
double lat,
double lon) {
262 p.m_x -= vp.rv_rect.x, p.m_y -= vp.rv_rect.y;
266void GshhsPolyCell::DrawPolygonFilled(
ocpnDC &pnt, contour_list *p,
double dx,
267 ViewPort &vp, wxColor
const &color) {
281 for (c = 0; c < p->size(); c++) {
282 if (!p->at(c).size())
continue;
284 wxPoint *poly_pt =
new wxPoint[p->at(c).size()];
286 contour &cp = p->at(c);
289 for (v = 0; v < p->at(c).size(); v++) {
290 wxRealPoint &ccp = cp.at(v);
291 wxPoint2DDouble q = GetDoublePixFromLL(vp, ccp.y, ccp.x + dx);
292 if (std::isnan(q.m_x)) {
297 x = q.m_x, y = q.m_y;
299 if (v == 0 || x != x_old || y != y_old) {
300 poly_pt[pointCount].x = x;
301 poly_pt[pointCount].y = y;
308 if (pointCount > 1) pnt.DrawPolygonTessellated(pointCount, poly_pt, 0, 0);
328static std::list<float_2Dpt> g_pv;
329static std::list<GLvertex *> g_vertexes;
330static int g_type, g_pos;
331static float_2Dpt g_p1, g_p2;
333void __CALL_CONVENTION gshhscombineCallback(GLdouble coords[3],
334 GLdouble *vertex_data[4],
336 GLdouble **dataOut) {
339 vertex =
new GLvertex();
340 g_vertexes.push_back(vertex);
342 vertex->info.x = coords[0];
343 vertex->info.y = coords[1];
345 *dataOut = vertex->data;
348void __CALL_CONVENTION gshhsvertexCallback(GLvoid *arg) {
350 vertex = (GLvertex *)arg;
352 p.y = vertex->info.x;
353 p.x = vertex->info.y;
356 if (g_type != GL_TRIANGLES) {
358 g_pv.push_back(g_p1);
359 g_pv.push_back(g_p2);
362 if (g_type == GL_TRIANGLE_STRIP)
373void __CALL_CONVENTION gshhserrorCallback(GLenum errorCode) {
374 const GLubyte *estring;
375 estring = gluErrorString(errorCode);
379void __CALL_CONVENTION gshhsbeginCallback(GLenum type) {
382 case GL_TRIANGLE_STRIP:
383 case GL_TRIANGLE_FAN:
387 printf(
"tess unhandled begin type: %d\n", type);
393void __CALL_CONVENTION gshhsendCallback() {}
395void GshhsPolyCell::DrawPolygonFilledGL(
ocpnDC &pnt, contour_list *p,
396 float_2Dpt **pv,
int *pvc,
ViewPort &vp,
397 wxColor
const &color,
bool idl) {
404 for (
unsigned int c = 0; c < p->size(); c++) {
405 if (!p->at(c).size())
continue;
407 contour &cp = p->at(c);
409 GLUtesselator *tobj = gluNewTess();
411 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&gshhsvertexCallback);
412 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&gshhsbeginCallback);
413 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&gshhsendCallback);
414 gluTessCallback(tobj, GLU_TESS_COMBINE,
415 (_GLUfuncptr)&gshhscombineCallback);
416 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&gshhserrorCallback);
418 gluTessNormal(tobj, 0, 0, 1);
419 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
421 gluTessBeginPolygon(tobj, NULL);
422 gluTessBeginContour(tobj);
424 for (
unsigned int v = 0; v < p->at(c).size(); v++) {
425 wxRealPoint &ccp = cp.at(v);
427 if (v == 0 || ccp != cp.at(v - 1)) {
428 GLvertex *vertex =
new GLvertex();
429 g_vertexes.push_back(vertex);
432 if (glChartCanvas::HasNormalizedViewPort(vp))
433 q = GetDoublePixFromLL(vp, ccp.y, ccp.x);
435 q.m_x = ccp.y, q.m_y = ccp.x;
437 if (vp.m_projection_type != PROJECTION_POLAR) {
441 if (idl && ccp.x == 180) {
442 if (vp.m_projection_type != PROJECTION_MERCATOR &&
443 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
448 vertex->info.x = q.m_x;
449 vertex->info.y = q.m_y;
451 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
455 gluTessEndContour(tobj);
456 gluTessEndPolygon(tobj);
459 for (std::list<GLvertex *>::iterator it = g_vertexes.begin();
460 it != g_vertexes.end(); it++)
465 *pv =
new float_2Dpt[g_pv.size()];
467 for (std::list<float_2Dpt>::iterator it = g_pv.begin(); it != g_pv.end();
475#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
479 if (!vertex_shader) {
481 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
482 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
483 glCompileShader(vertex_shader);
484 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
486 glGetShaderInfoLog(vertex_shader, INFOLOG_LEN, NULL, infoLog);
487 printf(
"ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
491 if (!fragment_shader) {
493 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
494 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
495 glCompileShader(fragment_shader);
496 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
498 glGetShaderInfoLog(fragment_shader, INFOLOG_LEN, NULL, infoLog);
499 printf(
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
503 if (!shader_program) {
505 shader_program = glCreateProgram();
506 glAttachShader(shader_program, vertex_shader);
507 glAttachShader(shader_program, fragment_shader);
508 glLinkProgram(shader_program);
509 glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
511 glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
512 printf(
"ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
521 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)vp.
pix_width,
525 if (glChartCanvas::HasNormalizedViewPort(vp)) {
527 GLint pos = glGetAttribLocation(color_tri_shader_program,
"position");
528 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), *pv);
529 glEnableVertexAttribArray(pos);
535 GLint tmatloc = glGetUniformLocation(color_tri_shader_program,
"TransformMatrix");
536 glUniformMatrix4fv(tmatloc, 1, GL_FALSE, (
const GLfloat*)m);
538 glUseProgram(color_tri_shader_program);
539 glDrawArrays(GL_TRIANGLES, 0, *pvc);
542 float *pvt =
new float[2 * (*pvc)];
543 for (
int i = 0; i < *pvc; i++) {
544 float_2Dpt *pc = *pv + i;
547 pvt[(i * 2) + 1] = q.m_y;
550 GLShaderProgram *shader = pcolor_tri_shader_program[pnt.m_canvasIndex];
554 colorv[0] = color.Red() / float(256);
555 colorv[1] = color.Green() / float(256);
556 colorv[2] = color.Blue() / float(256);
558 shader->SetUniform4fv(
"color", colorv);
560 shader->SetAttributePointerf(
"position", pvt);
562 glDrawArrays(GL_TRIANGLES, 0, *pvc);
565 glDeleteBuffers(1, &vbo);
574#define DRAW_POLY_FILLED(POLY, COL) \
575 if (POLY) DrawPolygonFilled(pnt, POLY, dx, vp, COL);
576#define DRAW_POLY_FILLED_GL(NUM, COL) \
577 DrawPolygonFilledGL(pnt, &poly##NUM, &polyv[NUM], &polyc[NUM], vp, COL, idl);
579void GshhsPolyCell::drawMapPlain(
ocpnDC &pnt,
double dx,
ViewPort &vp,
580 wxColor seaColor, wxColor landColor,
584#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
585#define NORM_FACTOR 4096.0
586 if (dx && (vp.m_projection_type == PROJECTION_MERCATOR ||
587 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
589 40058986 * NORM_FACTOR;
591 glTranslated(dx > 0 ? ts : -ts, 0, 0);
594 DRAW_POLY_FILLED_GL(1, landColor);
595 DRAW_POLY_FILLED_GL(2, seaColor);
596 DRAW_POLY_FILLED_GL(3, landColor);
597 DRAW_POLY_FILLED_GL(4, seaColor);
598 DRAW_POLY_FILLED_GL(5, landColor);
600#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
601 if (dx) glPopMatrix();
607 DRAW_POLY_FILLED(&poly1, landColor);
608 DRAW_POLY_FILLED(&poly2, seaColor);
609 DRAW_POLY_FILLED(&poly3, landColor);
610 DRAW_POLY_FILLED(&poly4, seaColor);
611 DRAW_POLY_FILLED(&poly5, landColor);
615void GshhsPolyCell::DrawPolygonContour(
ocpnDC &pnt, contour_list *p,
double dx,
617 double x1, y1, x2, y2;
618 double long_max, lat_max, long_min, lat_min;
620 long_min = (double)x0cell;
621 lat_min = (double)y0cell;
622 long_max = ((double)x0cell + (
double)header->pasx);
623 lat_max = ((double)y0cell + (
double)header->pasy);
627 for (
unsigned int i = 0; i < p->size(); i++) {
628 if (!p->at(i).size())
continue;
631 for (v = 0; v < (p->at(i).size() - 1); v++) {
632 x1 = p->at(i).at(v).x;
633 y1 = p->at(i).at(v).y;
634 x2 = p->at(i).at(v + 1).x;
635 y2 = p->at(i).at(v + 1).y;
638 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
639 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
640 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
641 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
642 pnt.
DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
646 x1 = p->at(i).at(v).x;
647 y1 = p->at(i).at(v).y;
648 x2 = p->at(i).at(0).x;
649 y2 = p->at(i).at(0).y;
651 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
652 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
653 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
654 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
655 pnt.
DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
660#define DRAW_POLY_CONTOUR(POLY) \
661 if (POLY) DrawPolygonContour(pnt, POLY, dx, vp);
663void GshhsPolyCell::drawSeaBorderLines(
ocpnDC &pnt,
double dx,
ViewPort &vp) {
665 DRAW_POLY_CONTOUR(&poly1)
666 DRAW_POLY_CONTOUR(&poly2)
667 DRAW_POLY_CONTOUR(&poly3)
668 DRAW_POLY_CONTOUR(&poly4)
669 DRAW_POLY_CONTOUR(&poly5)
674GshhsPolyReader::GshhsPolyReader(
int quality) {
677 for (
int i = 0; i < 360; i++) {
678 for (
int j = 0; j < 180; j++) {
679 allCells[i][j] = NULL;
683 polyHeader.version = -1;
684 InitializeLoadQuality(quality);
688GshhsPolyReader::~GshhsPolyReader() {
689 for (
int i = 0; i < 360; i++) {
690 for (
int j = 0; j < 180; j++) {
691 if (allCells[i][j] != NULL) {
692 delete allCells[i][j];
693 allCells[i][j] = NULL;
704int GshhsPolyReader::ReadPolyVersion() {
705 wxString fname = GshhsReader::getFileName_Land(0);
706 if (fpoly) fclose(fpoly);
707 fpoly = fopen(fname.mb_str(),
"rb");
710 if (!fpoly)
return 0;
712 readPolygonFileHeader(fpoly, &polyHeader);
714 return polyHeader.version;
717void GshhsPolyReader::InitializeLoadQuality(
720 if (currentQuality != quality) {
721 currentQuality = quality;
723 wxString fname = GshhsReader::getFileName_Land(quality);
725 if (fpoly) fclose(fpoly);
727 fpoly = fopen(fname.mb_str(),
"rb");
728 if (fpoly) readPolygonFileHeader(fpoly, &polyHeader);
730 for (
int i = 0; i < 360; i++) {
731 for (
int j = 0; j < 180; j++) {
732 if (allCells[i][j] != NULL) {
733 delete allCells[i][j];
734 allCells[i][j] = NULL;
741static inline bool my_intersects(
const wxLineF &line1,
const wxLineF &line2) {
742 double x1 = line1.m_p1.x, y1 = line1.m_p1.y, x2 = line1.m_p2.x,
744 double x3 = line2.m_p1.x, y3 = line2.m_p1.y, x4 = line2.m_p2.x,
749 double ax = x2 - x1, ay = y2 - y1;
750 double bx = x3 - x4, by = y3 - y4;
751 double cx = x1 - x3, cy = y1 - y3;
753#define INTER_LIMIT 1e-7
754 double denominator = ay * bx - ax * by;
755 if (denominator < 1e-10) {
756 if (fabs((y1 * ax - ay * x1) * bx - (y3 * bx - by * x3) * ax) > INTER_LIMIT)
758 if (fabs((x1 * ay - ax * y1) * by - (x3 * by - bx * y3) * ay) > INTER_LIMIT)
764 const double reciprocal = 1 / denominator;
765 const double na = (by * cx - bx * cy) * reciprocal;
767 if (na < -INTER_LIMIT || na > 1 + INTER_LIMIT)
return false;
769 const double nb = (ax * cy - ay * cx) * reciprocal;
770 if (nb < -INTER_LIMIT || nb > 1 + INTER_LIMIT)
return false;
775bool GshhsPolyReader::crossing1(
wxLineF trajectWorld) {
776 double x1 = trajectWorld.p1().x, y1 = trajectWorld.p1().y;
777 double x2 = trajectWorld.p2().x, y2 = trajectWorld.p2().y;
779 int clonmin, clonmax, clatmax, clatmin;
780 clonmin = (int)floor(GSSH_SUBM * wxMin(x1, x2));
781 clonmax = (int)ceil(GSSH_SUBM * wxMax(x1, x2));
784 clonmin += GSSH_SUBM * 360;
785 clonmax += GSSH_SUBM * 360;
788 if (clonmax - clonmin > GSSH_SUBM * 180) {
789 clonmin = (int)floor(GSSH_SUBM * wxMax(x1, x2)) - GSSH_SUBM * 360;
790 clonmax = (int)ceil(GSSH_SUBM * wxMin(x1, x2));
793 clatmin = (int)floor(GSSH_SUBM * wxMin(y1, y2));
794 clatmax = (int)ceil(GSSH_SUBM * wxMax(y1, y2));
795 wxASSERT(clatmin >= -GSSH_SUBM * 90 && clatmax <= GSSH_SUBM * 89);
801 int clon, clonx, clat;
802 for (clon = clonmin; clon < clonmax; clon++) {
804 while (clonx < 0) clonx += GSSH_SUBM * 360;
805 while (clonx >= GSSH_SUBM * 360) clonx -= GSSH_SUBM * 360;
807 wxASSERT(clonx >= 0 && clonx < GSSH_SUBM * 360);
809 if (clonx < GSSH_SUBM * 180) {
810 if (x1 > 180) x1 -= 360;
811 if (x2 > 180) x2 -= 360;
813 if (x1 < 180) x1 += 360;
814 if (x2 < 180) x2 += 360;
817 wxLineF rtrajectWorld(x1, y1, x2, y2);
819 for (clat = clatmin; clat < clatmax; clat++) {
820 int cloni = clonx / GSSH_SUBM,
821 clati = (GSSH_SUBM * 90 + clat) / GSSH_SUBM;
827 cel =
new GshhsPolyCell(fpoly, cloni, clati - 90, &polyHeader);
833 int hash = GSSH_SUBM * (GSSH_SUBM * (90 - clati) + clat - cloni) + clonx;
834 std::vector<wxLineF> *&high_res_map = cel->high_res_map[hash];
835 wxASSERT(hash >= 0 && hash < GSSH_SUBM * GSSH_SUBM);
840 contour_list &poly1 = cel->getPoly1();
842 double minlat = (double)clat / GSSH_SUBM,
843 maxlat = (
double)(clat + 1) / GSSH_SUBM;
844 double minlon = (double)clonx / GSSH_SUBM,
845 maxlon = (
double)(clonx + 1) / GSSH_SUBM;
846 high_res_map =
new std::vector<wxLineF>;
847 for (
unsigned int pi = 0; pi < poly1.size(); pi++) {
848 contour &c = poly1[pi];
849 double lx = c[c.size() - 1].x, ly = c[c.size() - 1].y;
853 int lstatex = lx < minlon ? -1 : lx > maxlon ? 1 : 0;
854 int lstatey = ly < minlat ? -1 : ly > maxlat ? 1 : 0;
856 for (
unsigned int pj = 0; pj < c.size(); pj++) {
857 double clon = c[pj].x, clat = c[pj].y;
862 if (lx == clon && ly == clat)
continue;
864 int statex = clon < minlon ? -1 : clon > maxlon ? 1 : 0;
865 int statey = clat < minlat ? -1 : clat > maxlat ? 1 : 0;
867 if ((!statex || lstatex != statex) &&
868 (!statey || lstatey != statey))
869 high_res_map->push_back(
wxLineF(lx, ly, clon, clat));
871 lx = clon, ly = clat;
872 lstatex = statex, lstatey = statey;
879 for (std::vector<wxLineF>::iterator it2 = high_res_map->begin();
880 it2 != high_res_map->end(); it2++)
881 if (my_intersects(rtrajectWorld, *it2))
return true;
888void GshhsPolyReader::readPolygonFileHeader(FILE *polyfile,
890 fseek(polyfile, 0, SEEK_SET);
892 wxLogMessage(
"gshhs ReadPolygonFileHeader failed");
896void GshhsPolyReader::drawGshhsPolyMapPlain(
ocpnDC &pnt,
ViewPort &vp,
897 wxColor
const &seaColor,
898 wxColor
const &landColor) {
901 pnt.SetPen(wxNullPen);
903 int clonmin, clonmax, clatmax, clatmin;
904 LLBBox bbox = vp.GetBBox();
905 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
906 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
907 if (clatmin <= 0) clatmin--;
908 if (clatmax >= 0) clatmax++;
909 if (clonmin <= 0) clonmin--;
910 if (clonmax >= 0) clonmax++;
911 int dx, clon, clonx, clat;
918 if (vp.m_projection_type != last_rendered_vp.m_projection_type ||
919 (last_rendered_vp.m_projection_type == PROJECTION_POLAR &&
920 last_rendered_vp.
clat * vp.
clat <= 0)) {
921 last_rendered_vp = vp;
922 for (
int clon = 0; clon < 360; clon++)
923 for (
int clat = 0; clat < 180; clat++)
924 if (allCells[clon][clat]) allCells[clon][clat]->ClearPolyV();
926#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
927 glEnableClientState(GL_VERTEX_ARRAY);
931 if (glChartCanvas::HasNormalizedViewPort(vp)) {
933 glChartCanvas::MultMatrixViewPort(vp);
934 nvp = glChartCanvas::NormalizedViewPort(vp);
939 for (clon = clonmin; clon < clonmax; clon++) {
941 while (clonx < 0) clonx += 360;
942 while (clonx >= 360) clonx -= 360;
944 for (clat = clatmin; clat < clatmax; clat++) {
945 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
946 if (allCells[clonx][clat + 90] == NULL) {
949 allCells[clonx][clat + 90] = cel;
951 cel = allCells[clonx][clat + 90];
956 if (vp.m_projection_type != PROJECTION_MERCATOR &&
957 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
959 else if (pnt.GetDC())
967 if (vp.
clon - clonn > 180)
969 else if (vp.
clon - clonn < -180)
975 cel->drawMapPlain(pnt, dx, nvp, seaColor, landColor, idl);
981#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
983 if (glChartCanvas::HasNormalizedViewPort(vp)) glPopMatrix();
984 glDisableClientState(GL_VERTEX_ARRAY);
991void GshhsPolyReader::drawGshhsPolyMapSeaBorders(
ocpnDC &pnt,
ViewPort &vp) {
993 int clonmin, clonmax, clatmax, clatmin;
994 LLBBox bbox = vp.GetBBox();
995 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
996 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
998 int dx, clon, clonx, clat;
1001 for (clon = clonmin; clon < clonmax; clon++) {
1003 while (clonx < 0) clonx += 360;
1004 while (clonx >= 360) clonx -= 360;
1006 for (clat = clatmin; clat < clatmax; clat++) {
1007 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
1008 if (allCells[clonx][clat + 90] == NULL) {
1011 allCells[clonx][clat + 90] = cel;
1013 cel = allCells[clonx][clat + 90];
1016 cel->drawSeaBorderLines(pnt, dx, vp);
1022int GshhsPolygon::readInt4() {
1025 unsigned char buf[4];
1028 unsigned char in[4];
1031 nb += fread(&in, 1, 4, file);
1045int GshhsPolygon::readInt2() {
1048 unsigned char buf[4];
1052 nb += fread(&v.buf[0], 2, 1, file);
1057 return v.buf[1] << 8 | v.buf[0];
1060GshhsPolygon::GshhsPolygon(FILE *file_) {
1066 west = readInt4() * 1e-6;
1067 east = readInt4() * 1e-6;
1068 south = readInt4() * 1e-6;
1069 north = readInt4() * 1e-6;
1072 if (((flag >> 8) & 255) >= 7) {
1073 areaFull = readInt4();
1074 container = readInt4();
1075 ancestor = readInt4();
1077 greenwich = (flag >> 16) & 1;
1078 antarctic = (west == 0 && east == 360);
1080 double x = 0, y = 0;
1081 for (
int i = 0; i < n; i++) {
1082 x = readInt4() * 1e-6;
1083 if (greenwich && x > 270) x -= 360;
1084 y = readInt4() * 1e-6;
1088 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, y));
1089 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, -90));
1094 greenwich = (flag >> 16) & 1;
1095 antarctic = (west == 0 && east == 360);
1097 for (
int i = 0; i < n; i++) {
1098 double x = 0, y = 0;
1099 x = readInt4() * 1e-6;
1100 if (greenwich && x > 270) x -= 360;
1101 y = readInt4() * 1e-6;
1110GshhsPolygon::~GshhsPolygon() {
1111 std::vector<GshhsPoint *>::iterator itp;
1112 for (itp = lsPoints.begin(); itp != lsPoints.end(); itp++) {
1121GshhsReader::GshhsReader() {
1122 maxQualityAvailable = -1;
1123 minQualityAvailable = -1;
1125 for (
int i = 0; i < 5; i++) {
1126 qualityAvailable[i] =
false;
1127 if (GshhsReader::gshhsFilesExists(i)) {
1128 qualityAvailable[i] =
true;
1129 if (minQualityAvailable < 0) minQualityAvailable = i;
1130 maxQualityAvailable = i;
1134 if (maxQualityAvailable < 0) {
1136 "Unable to initialize background world map. No GSHHS datafiles "
1138 msg += gWorldMapLocation;
1151 for (
int qual = 0; qual < 5; qual++) {
1152 lsPoly_boundaries[qual] =
new std::vector<GshhsPolygon *>;
1153 lsPoly_rivers[qual] =
new std::vector<GshhsPolygon *>;
1160int GshhsReader::ReadPolyVersion() {
1161 return gshhsPoly_reader->ReadPolyVersion();
1166GshhsReader::~GshhsReader() {
1168 delete gshhsPoly_reader;
1172void GshhsReader::clearLists() {
1173 std::vector<GshhsPolygon *>::iterator itp;
1174 for (
int qual = 0; qual < 5; qual++) {
1175 for (itp = lsPoly_boundaries[qual]->begin();
1176 itp != lsPoly_boundaries[qual]->end(); itp++) {
1180 for (itp = lsPoly_rivers[qual]->begin(); itp != lsPoly_rivers[qual]->end();
1186 lsPoly_boundaries[qual]->clear();
1187 lsPoly_rivers[qual]->clear();
1188 delete lsPoly_boundaries[qual];
1189 delete lsPoly_rivers[qual];
1194wxString GshhsReader::getNameExtension(
int quality) {
1219wxString GshhsReader::getFileName_Land(
int quality) {
1220 wxString ext = GshhsReader::getNameExtension(quality);
1222 gWorldMapLocation + wxString::Format(
"poly-%c-1.dat", ext.GetChar(0));
1226wxString GshhsReader::getFileName_boundaries(
int quality) {
1227 wxString ext = GshhsReader::getNameExtension(quality);
1229 gWorldMapLocation + wxString::Format(
"wdb_borders_%c.b", ext.GetChar(0));
1233wxString GshhsReader::getFileName_rivers(
int quality) {
1234 wxString ext = GshhsReader::getNameExtension(quality);
1236 gWorldMapLocation + wxString::Format(
"wdb_rivers_%c.b", ext.GetChar(0));
1241bool GshhsReader::gshhsFilesExists(
int quality) {
1242 if (!wxFile::Access(GshhsReader::getFileName_Land(quality), wxFile::read))
1254void GshhsReader::LoadQuality(
int newQuality)
1256 if (quality == newQuality)
return;
1258 wxStopWatch perftimer;
1262 quality = newQuality;
1265 else if (quality > 4)
1268 gshhsPoly_reader->InitializeLoadQuality(quality);
1270 if( lsPoly_boundaries[quality]->size() == 0 ) {
1271 fname = getFileName_boundaries( quality );
1272 file = fopen( fname.mb_str(),
"rb" );
1274 if( file != NULL ) {
1281 if( poly->getLevel() < 2 )
1282 lsPoly_boundaries[quality]->push_back( poly );
1290 if( lsPoly_rivers[quality]->size() == 0 ) {
1291 fname = getFileName_rivers( quality );
1292 file = fopen( fname.mb_str(),
"rb" );
1293 if( file != NULL ) {
1299 lsPoly_rivers[quality]->push_back( poly );
1307 wxLogMessage(
"Loading World Chart Q=%d in %ld ms.", quality,
1312std::vector<GshhsPolygon *> &GshhsReader::getList_boundaries() {
1313 return *lsPoly_boundaries[quality];
1316std::vector<GshhsPolygon *> &GshhsReader::getList_rivers() {
1317 return *lsPoly_rivers[quality];
1322int GshhsReader::GSHHS_scaledPoints(
GshhsPolygon *pol, wxPoint *pts,
1325 box.Set(pol->south, pol->west + declon, pol->north, pol->east + declon);
1326 if (vp.GetBBox().IntersectOut(box))
return 0;
1330 wxPoint2DDouble p1 = GetDoublePixFromLL(vp, pol->west + declon, pol->north);
1331 wxPoint2DDouble p2 = GetDoublePixFromLL(vp, pol->east + declon, pol->south);
1333 if (p1.m_x == p2.m_x && p1.m_y == p2.m_y)
return 0;
1336 std::vector<GshhsPoint *>::iterator itp;
1337 int xx, yy, oxx = 0, oyy = 0;
1340 for (itp = (pol->lsPoints).begin(); itp != (pol->lsPoints).end(); itp++) {
1341 x = (*itp)->lon + declon;
1343 wxPoint2DDouble p = GetDoublePixFromLL(vp, y, x);
1344 xx = p.m_x, yy = p.m_y;
1345 if (j == 0 || (oxx != xx || oyy != yy)) {
1358void GshhsReader::GsshDrawLines(
ocpnDC &pnt, std::vector<GshhsPolygon *> &lst,
1360 std::vector<GshhsPolygon *>::iterator iter;
1362 wxPoint *pts = NULL;
1367 pts =
new wxPoint[nbmax];
1370 for (i = 0, iter = lst.begin(); iter != lst.end(); iter++, i++) {
1373 if (nbmax < pol->n + 2) {
1376 pts =
new wxPoint[nbmax];
1380 nbp = GSHHS_scaledPoints(pol, pts, 0, vp);
1382 if (pol->isAntarctic()) {
1385 pnt.DrawLines(nbp, pts);
1388 pnt.DrawLines(nbp, pts);
1390 pnt.
DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1394 nbp = GSHHS_scaledPoints(pol, pts, -360, 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);
1413 wxColor
const &seaColor,
1414 wxColor
const &landColor) {
1415 LoadQuality(selectBestQuality(vp));
1416 gshhsPoly_reader->drawGshhsPolyMapPlain(pnt, vp, seaColor, landColor);
1421 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1422 gshhsPoly_reader->drawGshhsPolyMapSeaBorders(pnt, vp);
1427 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1430 wxPen *pen = wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxPENSTYLE_DOT);
1433 wxPen *pen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 80), 2,
1434 wxPENSTYLE_LONG_DASH);
1437 GsshDrawLines(pnt, getList_boundaries(), vp,
false);
1442 GsshDrawLines(pnt, getList_rivers(), vp,
false);
1446int GshhsReader::selectBestQuality(
ViewPort &vp) {
1447 int bestQuality = 0;
1449 if (vp.
chart_scale < 500000 && qualityAvailable[4])
1451 else if (vp.
chart_scale < 2000000 && qualityAvailable[3])
1453 else if (vp.
chart_scale < 8000000 && qualityAvailable[2])
1455 else if (vp.
chart_scale < 20000000 && qualityAvailable[1])
1457 else if (qualityAvailable[0])
1460 while (!qualityAvailable[bestQuality] &&
1466 while (!qualityAvailable[bestQuality]) {
1468 if (bestQuality < 0)
break;
1484void gshhsCrossesLandInit() {
1485 wxLogMessage(
"GSHHSChart::gshhsCrossesLandInit()");
1486 if (!gshhs_reader) {
1490 int bestQuality = 4;
1491 while (!gshhs_reader->qualityAvailable[bestQuality] && bestQuality > 0)
1493 gshhs_reader->LoadQuality(bestQuality);
1494 wxLogMessage(
"GSHHG: Loaded quality %d for land crossing detection.",
1498void gshhsCrossesLandReset() {
1499 wxLogMessage(
"GSHHSChart::gshhsCrossesLandReset()");
1500 if (gshhs_reader)
delete gshhs_reader;
1501 gshhs_reader = NULL;
1502 gshhsCrossesLandInit();
1505bool gshhsCrossesLand(
double lat1,
double lon1,
double lat2,
double lon2) {
1506 if (!gshhs_reader) {
1507 gshhsCrossesLandInit();
1509 if (lon1 < 0) lon1 += 360;
1510 if (lon2 < 0) lon2 += 360;
1512 wxLineF trajectWorld(lon1, lat1, lon2, lat2);
1513 return gshhs_reader->crossing1(trajectWorld);
General chart base definitions.
Wrapper class for OpenGL shader programs.
ViewPort - Core geographic projection and coordinate transformation engine.
int pix_height
Height of the viewport in physical pixels.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Global variables stored in configuration file.
OpenGL chart rendering canvas.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Layer to use wxDC or opengl.