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:
130 land.Set(land.Red() * dim, land.Green() * dim, land.Blue() * dim);
131 water.Set(water.Red() * dim, water.Green() * dim, water.Blue() * dim);
134void GSHHSChart::SetColorsDirect(wxColour newLand, wxColour newWater) {
139void GSHHSChart::Reset() {
140 if (reader)
delete reader;
144int GSHHSChart::GetMinAvailableQuality() {
146 return reader->GetMinAvailableQuality();
149int GSHHSChart::GetMaxAvailableQuality() {
151 return reader->GetMaxAvailableQuality();
157 if (reader->GetPolyVersion() < 210 || reader->GetPolyVersion() > 240) {
159 "GSHHS World chart files have wrong version. Found %d, expected "
161 reader->GetPolyVersion());
164 "Background world map loaded from GSHHS datafiles found in: " +
169 reader->drawContinents(dc, vp, water, land);
175GshhsPolyCell::GshhsPolyCell(FILE *fpoly_,
int x0_,
int y0_,
182 for (
int i = 0; i < 6; i++) polyv[i] = NULL;
186 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++) high_res_map[i] = NULL;
189GshhsPolyCell::~GshhsPolyCell() {
192 for (
int i = 0; i < GSSH_SUBM * GSSH_SUBM; i++)
delete high_res_map[i];
193 for (
int i = 0; i < 6; i++)
delete[] polyv[i];
196void GshhsPolyCell::ClearPolyV() {
197 for (
int i = 0; i < 6; i++) {
203void GshhsPolyCell::ReadPoly(contour_list &poly) {
206 int32_t num_vertices, num_contours;
208 if (fread(&num_contours,
sizeof num_contours, 1, fpoly) != 1)
goto fail;
210 for (
int c = 0; c < num_contours; c++) {
212 if (fread(&value,
sizeof value, 1, fpoly) !=
214 fread(&value,
sizeof value, 1, fpoly) != 1)
217 num_vertices = value;
220 for (
int v = 0; v < num_vertices; v++) {
221 if (fread(&X,
sizeof X, 1, fpoly) != 1 ||
222 fread(&Y,
sizeof Y, 1, fpoly) != 1)
225 tmp_contour.push_back(wxRealPoint(X * GSHHS_SCL, Y * GSHHS_SCL));
227 poly.push_back(tmp_contour);
232 wxLogMessage(
"gshhs ReadPoly failed");
235void GshhsPolyCell::ReadPolygonFile() {
241 tab_data = (x0cell / header->pasx) * (180 / header->pasy) +
242 (y0cell + 90) / header->pasy;
244 if (fread(&pos_data,
sizeof(
int), 1, fpoly) != 1)
goto fail;
246 fseek(fpoly, pos_data, SEEK_SET);
256 wxLogMessage(
"gshhs ReadPolygon failed");
259wxPoint2DDouble GetDoublePixFromLL(
ViewPort &vp,
double lat,
double lon) {
261 p.m_x -= vp.rv_rect.x, p.m_y -= vp.rv_rect.y;
265void GshhsPolyCell::DrawPolygonFilled(
ocpnDC &pnt, contour_list *p,
double dx,
266 ViewPort &vp, wxColor
const &color) {
280 for (c = 0; c < p->size(); c++) {
281 if (!p->at(c).size())
continue;
283 wxPoint *poly_pt =
new wxPoint[p->at(c).size()];
285 contour &cp = p->at(c);
288 for (v = 0; v < p->at(c).size(); v++) {
289 wxRealPoint &ccp = cp.at(v);
290 wxPoint2DDouble q = GetDoublePixFromLL(vp, ccp.y, ccp.x + dx);
291 if (std::isnan(q.m_x)) {
296 x = q.m_x, y = q.m_y;
298 if (v == 0 || x != x_old || y != y_old) {
299 poly_pt[pointCount].x = x;
300 poly_pt[pointCount].y = y;
307 if (pointCount > 1) pnt.DrawPolygonTessellated(pointCount, poly_pt, 0, 0);
327static std::list<float_2Dpt> g_pv;
328static std::list<GLvertex *> g_vertexes;
329static int g_type, g_pos;
330static float_2Dpt g_p1, g_p2;
332void __CALL_CONVENTION gshhscombineCallback(GLdouble coords[3],
333 GLdouble *vertex_data[4],
335 GLdouble **dataOut) {
338 vertex =
new GLvertex();
339 g_vertexes.push_back(vertex);
341 vertex->info.x = coords[0];
342 vertex->info.y = coords[1];
344 *dataOut = vertex->data;
347void __CALL_CONVENTION gshhsvertexCallback(GLvoid *arg) {
349 vertex = (GLvertex *)arg;
351 p.y = vertex->info.x;
352 p.x = vertex->info.y;
355 if (g_type != GL_TRIANGLES) {
357 g_pv.push_back(g_p1);
358 g_pv.push_back(g_p2);
361 if (g_type == GL_TRIANGLE_STRIP)
372void __CALL_CONVENTION gshhserrorCallback(GLenum errorCode) {
373 const GLubyte *estring;
374 estring = gluErrorString(errorCode);
378void __CALL_CONVENTION gshhsbeginCallback(GLenum type) {
381 case GL_TRIANGLE_STRIP:
382 case GL_TRIANGLE_FAN:
386 printf(
"tess unhandled begin type: %d\n", type);
392void __CALL_CONVENTION gshhsendCallback() {}
394void GshhsPolyCell::DrawPolygonFilledGL(
ocpnDC &pnt, contour_list *p,
395 float_2Dpt **pv,
int *pvc,
ViewPort &vp,
396 wxColor
const &color,
bool idl) {
403 for (
unsigned int c = 0; c < p->size(); c++) {
404 if (!p->at(c).size())
continue;
406 contour &cp = p->at(c);
408 GLUtesselator *tobj = gluNewTess();
410 gluTessCallback(tobj, GLU_TESS_VERTEX, (_GLUfuncptr)&gshhsvertexCallback);
411 gluTessCallback(tobj, GLU_TESS_BEGIN, (_GLUfuncptr)&gshhsbeginCallback);
412 gluTessCallback(tobj, GLU_TESS_END, (_GLUfuncptr)&gshhsendCallback);
413 gluTessCallback(tobj, GLU_TESS_COMBINE,
414 (_GLUfuncptr)&gshhscombineCallback);
415 gluTessCallback(tobj, GLU_TESS_ERROR, (_GLUfuncptr)&gshhserrorCallback);
417 gluTessNormal(tobj, 0, 0, 1);
418 gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
420 gluTessBeginPolygon(tobj, NULL);
421 gluTessBeginContour(tobj);
423 for (
unsigned int v = 0; v < p->at(c).size(); v++) {
424 wxRealPoint &ccp = cp.at(v);
426 if (v == 0 || ccp != cp.at(v - 1)) {
427 GLvertex *vertex =
new GLvertex();
428 g_vertexes.push_back(vertex);
431 if (glChartCanvas::HasNormalizedViewPort(vp))
432 q = GetDoublePixFromLL(vp, ccp.y, ccp.x);
434 q.m_x = ccp.y, q.m_y = ccp.x;
436 if (vp.m_projection_type != PROJECTION_POLAR) {
440 if (idl && ccp.x == 180) {
441 if (vp.m_projection_type != PROJECTION_MERCATOR &&
442 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
447 vertex->info.x = q.m_x;
448 vertex->info.y = q.m_y;
450 gluTessVertex(tobj, (GLdouble *)vertex, (GLdouble *)vertex);
454 gluTessEndContour(tobj);
455 gluTessEndPolygon(tobj);
458 for (std::list<GLvertex *>::iterator it = g_vertexes.begin();
459 it != g_vertexes.end(); it++)
464 *pv =
new float_2Dpt[g_pv.size()];
466 for (std::list<float_2Dpt>::iterator it = g_pv.begin(); it != g_pv.end();
474#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
478 if (!vertex_shader) {
480 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
481 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
482 glCompileShader(vertex_shader);
483 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
485 glGetShaderInfoLog(vertex_shader, INFOLOG_LEN, NULL, infoLog);
486 printf(
"ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
490 if (!fragment_shader) {
492 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
493 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
494 glCompileShader(fragment_shader);
495 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
497 glGetShaderInfoLog(fragment_shader, INFOLOG_LEN, NULL, infoLog);
498 printf(
"ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
502 if (!shader_program) {
504 shader_program = glCreateProgram();
505 glAttachShader(shader_program, vertex_shader);
506 glAttachShader(shader_program, fragment_shader);
507 glLinkProgram(shader_program);
508 glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
510 glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
511 printf(
"ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
520 mat4x4_scale_aniso(mvp, m, 2.0 / (
float)vp.
pix_width,
524 if (glChartCanvas::HasNormalizedViewPort(vp)) {
526 GLint pos = glGetAttribLocation(color_tri_shader_program,
"position");
527 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 2 *
sizeof(
float), *pv);
528 glEnableVertexAttribArray(pos);
534 GLint tmatloc = glGetUniformLocation(color_tri_shader_program,
"TransformMatrix");
535 glUniformMatrix4fv(tmatloc, 1, GL_FALSE, (
const GLfloat*)m);
537 glUseProgram(color_tri_shader_program);
538 glDrawArrays(GL_TRIANGLES, 0, *pvc);
541 float *pvt =
new float[2 * (*pvc)];
542 for (
int i = 0; i < *pvc; i++) {
543 float_2Dpt *pc = *pv + i;
546 pvt[(i * 2) + 1] = q.m_y;
549 GLShaderProgram *shader = pcolor_tri_shader_program[pnt.m_canvasIndex];
553 colorv[0] = color.Red() / float(256);
554 colorv[1] = color.Green() / float(256);
555 colorv[2] = color.Blue() / float(256);
557 shader->SetUniform4fv(
"color", colorv);
559 shader->SetAttributePointerf(
"position", pvt);
561 glDrawArrays(GL_TRIANGLES, 0, *pvc);
564 glDeleteBuffers(1, &vbo);
573#define DRAW_POLY_FILLED(POLY, COL) \
574 if (POLY) DrawPolygonFilled(pnt, POLY, dx, vp, COL);
575#define DRAW_POLY_FILLED_GL(NUM, COL) \
576 DrawPolygonFilledGL(pnt, &poly##NUM, &polyv[NUM], &polyc[NUM], vp, COL, idl);
578void GshhsPolyCell::drawMapPlain(
ocpnDC &pnt,
double dx,
ViewPort &vp,
579 wxColor seaColor, wxColor landColor,
583#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
584#define NORM_FACTOR 4096.0
585 if (dx && (vp.m_projection_type == PROJECTION_MERCATOR ||
586 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
588 40058986 * NORM_FACTOR;
590 glTranslated(dx > 0 ? ts : -ts, 0, 0);
593 DRAW_POLY_FILLED_GL(1, landColor);
594 DRAW_POLY_FILLED_GL(2, seaColor);
595 DRAW_POLY_FILLED_GL(3, landColor);
596 DRAW_POLY_FILLED_GL(4, seaColor);
597 DRAW_POLY_FILLED_GL(5, landColor);
599#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
600 if (dx) glPopMatrix();
606 DRAW_POLY_FILLED(&poly1, landColor);
607 DRAW_POLY_FILLED(&poly2, seaColor);
608 DRAW_POLY_FILLED(&poly3, landColor);
609 DRAW_POLY_FILLED(&poly4, seaColor);
610 DRAW_POLY_FILLED(&poly5, landColor);
614void GshhsPolyCell::DrawPolygonContour(
ocpnDC &pnt, contour_list *p,
double dx,
616 double x1, y1, x2, y2;
617 double long_max, lat_max, long_min, lat_min;
619 long_min = (double)x0cell;
620 lat_min = (double)y0cell;
621 long_max = ((double)x0cell + (
double)header->pasx);
622 lat_max = ((double)y0cell + (
double)header->pasy);
626 for (
unsigned int i = 0; i < p->size(); i++) {
627 if (!p->at(i).size())
continue;
630 for (v = 0; v < (p->at(i).size() - 1); v++) {
631 x1 = p->at(i).at(v).x;
632 y1 = p->at(i).at(v).y;
633 x2 = p->at(i).at(v + 1).x;
634 y2 = p->at(i).at(v + 1).y;
637 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
638 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
639 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
640 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
641 pnt.
DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
645 x1 = p->at(i).at(v).x;
646 y1 = p->at(i).at(v).y;
647 x2 = p->at(i).at(0).x;
648 y2 = p->at(i).at(0).y;
650 if ((((x1 == x2) && ((x1 == long_min) || (x1 == long_max))) ||
651 ((y1 == y2) && ((y1 == lat_min) || (y1 == lat_max)))) == 0) {
652 wxPoint2DDouble AB = GetDoublePixFromLL(vp, x1 + dx, y1);
653 wxPoint2DDouble CD = GetDoublePixFromLL(vp, x2 + dx, y1);
654 pnt.
DrawLine(AB.m_x, AB.m_y, CD.m_x, CD.m_y);
659#define DRAW_POLY_CONTOUR(POLY) \
660 if (POLY) DrawPolygonContour(pnt, POLY, dx, vp);
662void GshhsPolyCell::drawSeaBorderLines(
ocpnDC &pnt,
double dx,
ViewPort &vp) {
664 DRAW_POLY_CONTOUR(&poly1)
665 DRAW_POLY_CONTOUR(&poly2)
666 DRAW_POLY_CONTOUR(&poly3)
667 DRAW_POLY_CONTOUR(&poly4)
668 DRAW_POLY_CONTOUR(&poly5)
673GshhsPolyReader::GshhsPolyReader(
int quality) {
676 for (
int i = 0; i < 360; i++) {
677 for (
int j = 0; j < 180; j++) {
678 allCells[i][j] = NULL;
682 polyHeader.version = -1;
683 InitializeLoadQuality(quality);
687GshhsPolyReader::~GshhsPolyReader() {
688 for (
int i = 0; i < 360; i++) {
689 for (
int j = 0; j < 180; j++) {
690 if (allCells[i][j] != NULL) {
691 delete allCells[i][j];
692 allCells[i][j] = NULL;
703int GshhsPolyReader::ReadPolyVersion() {
704 wxString fname = GshhsReader::getFileName_Land(0);
705 if (fpoly) fclose(fpoly);
706 fpoly = fopen(fname.mb_str(),
"rb");
709 if (!fpoly)
return 0;
711 readPolygonFileHeader(fpoly, &polyHeader);
713 return polyHeader.version;
716void GshhsPolyReader::InitializeLoadQuality(
719 if (currentQuality != quality) {
720 currentQuality = quality;
722 wxString fname = GshhsReader::getFileName_Land(quality);
724 if (fpoly) fclose(fpoly);
726 fpoly = fopen(fname.mb_str(),
"rb");
727 if (fpoly) readPolygonFileHeader(fpoly, &polyHeader);
729 for (
int i = 0; i < 360; i++) {
730 for (
int j = 0; j < 180; j++) {
731 if (allCells[i][j] != NULL) {
732 delete allCells[i][j];
733 allCells[i][j] = NULL;
740static inline bool my_intersects(
const wxLineF &line1,
const wxLineF &line2) {
741 double x1 = line1.m_p1.x, y1 = line1.m_p1.y, x2 = line1.m_p2.x,
743 double x3 = line2.m_p1.x, y3 = line2.m_p1.y, x4 = line2.m_p2.x,
748 double ax = x2 - x1, ay = y2 - y1;
749 double bx = x3 - x4, by = y3 - y4;
750 double cx = x1 - x3, cy = y1 - y3;
752#define INTER_LIMIT 1e-7
753 double denominator = ay * bx - ax * by;
754 if (denominator < 1e-10) {
755 if (fabs((y1 * ax - ay * x1) * bx - (y3 * bx - by * x3) * ax) > INTER_LIMIT)
757 if (fabs((x1 * ay - ax * y1) * by - (x3 * by - bx * y3) * ay) > INTER_LIMIT)
763 const double reciprocal = 1 / denominator;
764 const double na = (by * cx - bx * cy) * reciprocal;
766 if (na < -INTER_LIMIT || na > 1 + INTER_LIMIT)
return false;
768 const double nb = (ax * cy - ay * cx) * reciprocal;
769 if (nb < -INTER_LIMIT || nb > 1 + INTER_LIMIT)
return false;
774bool GshhsPolyReader::crossing1(
wxLineF trajectWorld) {
775 double x1 = trajectWorld.p1().x, y1 = trajectWorld.p1().y;
776 double x2 = trajectWorld.p2().x, y2 = trajectWorld.p2().y;
778 int clonmin, clonmax, clatmax, clatmin;
779 clonmin = (int)floor(GSSH_SUBM * wxMin(x1, x2));
780 clonmax = (int)ceil(GSSH_SUBM * wxMax(x1, x2));
783 clonmin += GSSH_SUBM * 360;
784 clonmax += GSSH_SUBM * 360;
787 if (clonmax - clonmin > GSSH_SUBM * 180) {
788 clonmin = (int)floor(GSSH_SUBM * wxMax(x1, x2)) - GSSH_SUBM * 360;
789 clonmax = (int)ceil(GSSH_SUBM * wxMin(x1, x2));
792 clatmin = (int)floor(GSSH_SUBM * wxMin(y1, y2));
793 clatmax = (int)ceil(GSSH_SUBM * wxMax(y1, y2));
794 wxASSERT(clatmin >= -GSSH_SUBM * 90 && clatmax <= GSSH_SUBM * 89);
800 int clon, clonx, clat;
801 for (clon = clonmin; clon < clonmax; clon++) {
803 while (clonx < 0) clonx += GSSH_SUBM * 360;
804 while (clonx >= GSSH_SUBM * 360) clonx -= GSSH_SUBM * 360;
806 wxASSERT(clonx >= 0 && clonx < GSSH_SUBM * 360);
808 if (clonx < GSSH_SUBM * 180) {
809 if (x1 > 180) x1 -= 360;
810 if (x2 > 180) x2 -= 360;
812 if (x1 < 180) x1 += 360;
813 if (x2 < 180) x2 += 360;
816 wxLineF rtrajectWorld(x1, y1, x2, y2);
818 for (clat = clatmin; clat < clatmax; clat++) {
819 int cloni = clonx / GSSH_SUBM,
820 clati = (GSSH_SUBM * 90 + clat) / GSSH_SUBM;
826 cel =
new GshhsPolyCell(fpoly, cloni, clati - 90, &polyHeader);
832 int hash = GSSH_SUBM * (GSSH_SUBM * (90 - clati) + clat - cloni) + clonx;
833 std::vector<wxLineF> *&high_res_map = cel->high_res_map[hash];
834 wxASSERT(hash >= 0 && hash < GSSH_SUBM * GSSH_SUBM);
839 contour_list &poly1 = cel->getPoly1();
841 double minlat = (double)clat / GSSH_SUBM,
842 maxlat = (
double)(clat + 1) / GSSH_SUBM;
843 double minlon = (double)clonx / GSSH_SUBM,
844 maxlon = (
double)(clonx + 1) / GSSH_SUBM;
845 high_res_map =
new std::vector<wxLineF>;
846 for (
unsigned int pi = 0; pi < poly1.size(); pi++) {
847 contour &c = poly1[pi];
848 double lx = c[c.size() - 1].x, ly = c[c.size() - 1].y;
852 int lstatex = lx < minlon ? -1 : lx > maxlon ? 1 : 0;
853 int lstatey = ly < minlat ? -1 : ly > maxlat ? 1 : 0;
855 for (
unsigned int pj = 0; pj < c.size(); pj++) {
856 double clon = c[pj].x, clat = c[pj].y;
861 if (lx == clon && ly == clat)
continue;
863 int statex = clon < minlon ? -1 : clon > maxlon ? 1 : 0;
864 int statey = clat < minlat ? -1 : clat > maxlat ? 1 : 0;
866 if ((!statex || lstatex != statex) &&
867 (!statey || lstatey != statey))
868 high_res_map->push_back(
wxLineF(lx, ly, clon, clat));
870 lx = clon, ly = clat;
871 lstatex = statex, lstatey = statey;
878 for (std::vector<wxLineF>::iterator it2 = high_res_map->begin();
879 it2 != high_res_map->end(); it2++)
880 if (my_intersects(rtrajectWorld, *it2))
return true;
887void GshhsPolyReader::readPolygonFileHeader(FILE *polyfile,
889 fseek(polyfile, 0, SEEK_SET);
891 wxLogMessage(
"gshhs ReadPolygonFileHeader failed");
895void GshhsPolyReader::drawGshhsPolyMapPlain(
ocpnDC &pnt,
ViewPort &vp,
896 wxColor
const &seaColor,
897 wxColor
const &landColor) {
900 pnt.SetPen(wxNullPen);
902 int clonmin, clonmax, clatmax, clatmin;
903 LLBBox bbox = vp.GetBBox();
904 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
905 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
906 if (clatmin <= 0) clatmin--;
907 if (clatmax >= 0) clatmax++;
908 if (clonmin <= 0) clonmin--;
909 if (clonmax >= 0) clonmax++;
910 int dx, clon, clonx, clat;
917 if (vp.m_projection_type != last_rendered_vp.m_projection_type ||
918 (last_rendered_vp.m_projection_type == PROJECTION_POLAR &&
919 last_rendered_vp.
clat * vp.
clat <= 0)) {
920 last_rendered_vp = vp;
921 for (
int clon = 0; clon < 360; clon++)
922 for (
int clat = 0; clat < 180; clat++)
923 if (allCells[clon][clat]) allCells[clon][clat]->ClearPolyV();
925#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
926 glEnableClientState(GL_VERTEX_ARRAY);
930 if (glChartCanvas::HasNormalizedViewPort(vp)) {
932 glChartCanvas::MultMatrixViewPort(vp);
933 nvp = glChartCanvas::NormalizedViewPort(vp);
938 for (clon = clonmin; clon < clonmax; clon++) {
940 while (clonx < 0) clonx += 360;
941 while (clonx >= 360) clonx -= 360;
943 for (clat = clatmin; clat < clatmax; clat++) {
944 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
945 if (allCells[clonx][clat + 90] == NULL) {
948 allCells[clonx][clat + 90] = cel;
950 cel = allCells[clonx][clat + 90];
955 if (vp.m_projection_type != PROJECTION_MERCATOR &&
956 vp.m_projection_type != PROJECTION_EQUIRECTANGULAR)
958 else if (pnt.GetDC())
966 if (vp.
clon - clonn > 180)
968 else if (vp.
clon - clonn < -180)
974 cel->drawMapPlain(pnt, dx, nvp, seaColor, landColor, idl);
980#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
982 if (glChartCanvas::HasNormalizedViewPort(vp)) glPopMatrix();
983 glDisableClientState(GL_VERTEX_ARRAY);
990void GshhsPolyReader::drawGshhsPolyMapSeaBorders(
ocpnDC &pnt,
ViewPort &vp) {
992 int clonmin, clonmax, clatmax, clatmin;
993 LLBBox bbox = vp.GetBBox();
994 clonmin = bbox.GetMinLon(), clonmax = bbox.GetMaxLon(),
995 clatmin = bbox.GetMinLat(), clatmax = bbox.GetMaxLat();
997 int dx, clon, clonx, clat;
1000 for (clon = clonmin; clon < clonmax; clon++) {
1002 while (clonx < 0) clonx += 360;
1003 while (clonx >= 360) clonx -= 360;
1005 for (clat = clatmin; clat < clatmax; clat++) {
1006 if (clonx >= 0 && clonx <= 359 && clat >= -90 && clat <= 89) {
1007 if (allCells[clonx][clat + 90] == NULL) {
1010 allCells[clonx][clat + 90] = cel;
1012 cel = allCells[clonx][clat + 90];
1015 cel->drawSeaBorderLines(pnt, dx, vp);
1021int GshhsPolygon::readInt4() {
1024 unsigned char buf[4];
1027 unsigned char in[4];
1030 nb += fread(&in, 1, 4, file);
1044int GshhsPolygon::readInt2() {
1047 unsigned char buf[4];
1051 nb += fread(&v.buf[0], 2, 1, file);
1056 return v.buf[1] << 8 | v.buf[0];
1059GshhsPolygon::GshhsPolygon(FILE *file_) {
1065 west = readInt4() * 1e-6;
1066 east = readInt4() * 1e-6;
1067 south = readInt4() * 1e-6;
1068 north = readInt4() * 1e-6;
1071 if (((flag >> 8) & 255) >= 7) {
1072 areaFull = readInt4();
1073 container = readInt4();
1074 ancestor = readInt4();
1076 greenwich = (flag >> 16) & 1;
1077 antarctic = (west == 0 && east == 360);
1079 double x = 0, y = 0;
1080 for (
int i = 0; i < n; i++) {
1081 x = readInt4() * 1e-6;
1082 if (greenwich && x > 270) x -= 360;
1083 y = readInt4() * 1e-6;
1087 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, y));
1088 lsPoints.insert(lsPoints.begin(),
new GshhsPoint(360, -90));
1093 greenwich = (flag >> 16) & 1;
1094 antarctic = (west == 0 && east == 360);
1096 for (
int i = 0; i < n; i++) {
1097 double x = 0, y = 0;
1098 x = readInt4() * 1e-6;
1099 if (greenwich && x > 270) x -= 360;
1100 y = readInt4() * 1e-6;
1109GshhsPolygon::~GshhsPolygon() {
1110 std::vector<GshhsPoint *>::iterator itp;
1111 for (itp = lsPoints.begin(); itp != lsPoints.end(); itp++) {
1120GshhsReader::GshhsReader() {
1121 maxQualityAvailable = -1;
1122 minQualityAvailable = -1;
1124 for (
int i = 0; i < 5; i++) {
1125 qualityAvailable[i] =
false;
1126 if (GshhsReader::gshhsFilesExists(i)) {
1127 qualityAvailable[i] =
true;
1128 if (minQualityAvailable < 0) minQualityAvailable = i;
1129 maxQualityAvailable = i;
1133 if (maxQualityAvailable < 0) {
1135 "Unable to initialize background world map. No GSHHS datafiles "
1137 msg += gWorldMapLocation;
1150 for (
int qual = 0; qual < 5; qual++) {
1151 lsPoly_boundaries[qual] =
new std::vector<GshhsPolygon *>;
1152 lsPoly_rivers[qual] =
new std::vector<GshhsPolygon *>;
1159int GshhsReader::ReadPolyVersion() {
1160 return gshhsPoly_reader->ReadPolyVersion();
1165GshhsReader::~GshhsReader() {
1167 delete gshhsPoly_reader;
1171void GshhsReader::clearLists() {
1172 std::vector<GshhsPolygon *>::iterator itp;
1173 for (
int qual = 0; qual < 5; qual++) {
1174 for (itp = lsPoly_boundaries[qual]->begin();
1175 itp != lsPoly_boundaries[qual]->end(); itp++) {
1179 for (itp = lsPoly_rivers[qual]->begin(); itp != lsPoly_rivers[qual]->end();
1185 lsPoly_boundaries[qual]->clear();
1186 lsPoly_rivers[qual]->clear();
1187 delete lsPoly_boundaries[qual];
1188 delete lsPoly_rivers[qual];
1193wxString GshhsReader::getNameExtension(
int quality) {
1218wxString GshhsReader::getFileName_Land(
int quality) {
1219 wxString ext = GshhsReader::getNameExtension(quality);
1221 gWorldMapLocation + wxString::Format(
"poly-%c-1.dat", ext.GetChar(0));
1225wxString GshhsReader::getFileName_boundaries(
int quality) {
1226 wxString ext = GshhsReader::getNameExtension(quality);
1228 gWorldMapLocation + wxString::Format(
"wdb_borders_%c.b", ext.GetChar(0));
1232wxString GshhsReader::getFileName_rivers(
int quality) {
1233 wxString ext = GshhsReader::getNameExtension(quality);
1235 gWorldMapLocation + wxString::Format(
"wdb_rivers_%c.b", ext.GetChar(0));
1240bool GshhsReader::gshhsFilesExists(
int quality) {
1241 if (!wxFile::Access(GshhsReader::getFileName_Land(quality), wxFile::read))
1253void GshhsReader::LoadQuality(
int newQuality)
1255 if (quality == newQuality)
return;
1257 wxStopWatch perftimer;
1261 quality = newQuality;
1264 else if (quality > 4)
1267 gshhsPoly_reader->InitializeLoadQuality(quality);
1269 if( lsPoly_boundaries[quality]->size() == 0 ) {
1270 fname = getFileName_boundaries( quality );
1271 file = fopen( fname.mb_str(),
"rb" );
1273 if( file != NULL ) {
1280 if( poly->getLevel() < 2 )
1281 lsPoly_boundaries[quality]->push_back( poly );
1289 if( lsPoly_rivers[quality]->size() == 0 ) {
1290 fname = getFileName_rivers( quality );
1291 file = fopen( fname.mb_str(),
"rb" );
1292 if( file != NULL ) {
1298 lsPoly_rivers[quality]->push_back( poly );
1306 wxLogMessage(
"Loading World Chart Q=%d in %ld ms.", quality,
1311std::vector<GshhsPolygon *> &GshhsReader::getList_boundaries() {
1312 return *lsPoly_boundaries[quality];
1315std::vector<GshhsPolygon *> &GshhsReader::getList_rivers() {
1316 return *lsPoly_rivers[quality];
1321int GshhsReader::GSHHS_scaledPoints(
GshhsPolygon *pol, wxPoint *pts,
1324 box.Set(pol->south, pol->west + declon, pol->north, pol->east + declon);
1325 if (vp.GetBBox().IntersectOut(box))
return 0;
1329 wxPoint2DDouble p1 = GetDoublePixFromLL(vp, pol->west + declon, pol->north);
1330 wxPoint2DDouble p2 = GetDoublePixFromLL(vp, pol->east + declon, pol->south);
1332 if (p1.m_x == p2.m_x && p1.m_y == p2.m_y)
return 0;
1335 std::vector<GshhsPoint *>::iterator itp;
1336 int xx, yy, oxx = 0, oyy = 0;
1339 for (itp = (pol->lsPoints).begin(); itp != (pol->lsPoints).end(); itp++) {
1340 x = (*itp)->lon + declon;
1342 wxPoint2DDouble p = GetDoublePixFromLL(vp, y, x);
1343 xx = p.m_x, yy = p.m_y;
1344 if (j == 0 || (oxx != xx || oyy != yy)) {
1357void GshhsReader::GsshDrawLines(
ocpnDC &pnt, std::vector<GshhsPolygon *> &lst,
1359 std::vector<GshhsPolygon *>::iterator iter;
1361 wxPoint *pts = NULL;
1366 pts =
new wxPoint[nbmax];
1369 for (i = 0, iter = lst.begin(); iter != lst.end(); iter++, i++) {
1372 if (nbmax < pol->n + 2) {
1375 pts =
new wxPoint[nbmax];
1379 nbp = GSHHS_scaledPoints(pol, pts, 0, vp);
1381 if (pol->isAntarctic()) {
1384 pnt.DrawLines(nbp, pts);
1387 pnt.DrawLines(nbp, pts);
1389 pnt.
DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1393 nbp = GSHHS_scaledPoints(pol, pts, -360, vp);
1395 if (pol->isAntarctic()) {
1398 pnt.DrawLines(nbp, pts);
1401 pnt.DrawLines(nbp, pts);
1403 pnt.
DrawLine(pts[0].x, pts[0].y, pts[nbp - 1].x, pts[nbp - 1].y);
1412 wxColor
const &seaColor,
1413 wxColor
const &landColor) {
1414 LoadQuality(selectBestQuality(vp));
1415 gshhsPoly_reader->drawGshhsPolyMapPlain(pnt, vp, seaColor, landColor);
1420 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1421 gshhsPoly_reader->drawGshhsPolyMapSeaBorders(pnt, vp);
1426 pnt.SetBrush(*wxTRANSPARENT_BRUSH);
1429 wxPen *pen = wxThePenList->FindOrCreatePen(*wxBLACK, 1, wxPENSTYLE_DOT);
1432 wxPen *pen = wxThePenList->FindOrCreatePen(wxColor(0, 0, 0, 80), 2,
1433 wxPENSTYLE_LONG_DASH);
1436 GsshDrawLines(pnt, getList_boundaries(), vp,
false);
1441 GsshDrawLines(pnt, getList_rivers(), vp,
false);
1445int GshhsReader::selectBestQuality(
ViewPort &vp) {
1446 int bestQuality = 0;
1448 if (vp.
chart_scale < 500000 && qualityAvailable[4])
1450 else if (vp.
chart_scale < 2000000 && qualityAvailable[3])
1452 else if (vp.
chart_scale < 8000000 && qualityAvailable[2])
1454 else if (vp.
chart_scale < 20000000 && qualityAvailable[1])
1456 else if (qualityAvailable[0])
1459 while (!qualityAvailable[bestQuality] &&
1465 while (!qualityAvailable[bestQuality]) {
1467 if (bestQuality < 0)
break;
1483void gshhsCrossesLandInit() {
1484 wxLogMessage(
"GSHHSChart::gshhsCrossesLandInit()");
1485 if (!gshhs_reader) {
1489 int bestQuality = 4;
1490 while (!gshhs_reader->qualityAvailable[bestQuality] && bestQuality > 0)
1492 gshhs_reader->LoadQuality(bestQuality);
1493 wxLogMessage(
"GSHHG: Loaded quality %d for land crossing detection.",
1497void gshhsCrossesLandReset() {
1498 wxLogMessage(
"GSHHSChart::gshhsCrossesLandReset()");
1499 if (gshhs_reader)
delete gshhs_reader;
1500 gshhs_reader = NULL;
1501 gshhsCrossesLandInit();
1504bool gshhsCrossesLand(
double lat1,
double lon1,
double lat2,
double lon2) {
1505 if (!gshhs_reader) {
1506 gshhsCrossesLandInit();
1508 if (lon1 < 0) lon1 += 360;
1509 if (lon2 < 0) lon2 += 360;
1511 wxLineF trajectWorld(lon1, lat1, lon2, lat2);
1512 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.