46#include <wx/wfstream.h>
47#include <wx/tokenzr.h>
48#include <wx/filename.h>
50#include <wx/fileconf.h>
51#include <wx/mstream.h>
55#include <unordered_map>
58#include <SQLiteCpp/SQLiteCpp.h>
62#include "glChartCanvas.h"
63#include "ocpn_frame.h"
68typedef __int32 int32_t;
69typedef unsigned __int32 uint32_t;
70typedef __int64 int64_t;
71typedef unsigned __int64 uint64_t;
79static const long long lNaN = 0xfff8000000000000;
80#define NAN (*(double *)&lNaN)
119static const double OSM_zoomScale[] = {
120 5e8, 2.5e8, 1.5e8, 7.0e7, 3.5e7, 1.5e7, 1.0e7, 4.0e6, 2.0e6, 1.0e6,
121 5.0e5, 2.5e5, 1.5e5, 7.0e4, 3.5e4, 1.5e4, 8.0e3, 4.0e3, 2.0e3, 1.0e3,
126static const double OSM_zoomMPP[] = {
127 156412, 78206, 39103, 19551, 9776, 4888, 2444,
128 1222, 610, 984, 305.492, 152.746, 76.373, 38.187,
129 19.093, 9.547, 4.773, 2.387, 1.193, 0.596, 0.298,
133static const double eps = 6e-6;
137static const GLchar* tile_vertex_shader_source =
138 "attribute vec2 aPos;\n"
139 "attribute vec2 aUV;\n"
140 "uniform mat4 MVMatrix;\n"
141 "varying vec2 varCoord;\n"
143 " gl_Position = MVMatrix * vec4(aPos, 0.0, 1.0);\n"
147static const GLchar* tile_fragment_shader_source =
148 "precision lowp float;\n"
149 "uniform sampler2D uTex;\n"
150 "varying vec2 varCoord;\n"
152 " gl_FragColor = texture2D(uTex, varCoord);\n"
158#if defined(__UNIX__) && \
163 void Reset() { clock_gettime(CLOCK_REALTIME, &tp); }
167 clock_gettime(CLOCK_REALTIME, &tp_end);
168 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 +
169 (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
182static int long2tilex(
double lon,
int z) {
183 if (lon < -180) lon += 360;
185 return (
int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
188static int lat2tiley(
double lat,
int z) {
191 log(tan(lat * M_PI / 180.0) + 1.0 / cos(lat * M_PI / 180.0)) / M_PI) /
198static double tilex2long(
int x,
int z) {
return x / pow(2.0, z) * 360.0 - 180; }
200static double tiley2lat(
int y,
int z) {
201 double n = pow(2.0, z);
204 double latRad = atan(sinh(M_PI * (1 - (2 * y / n))));
205 return 180.0 / M_PI * latRad;
217 m_bAvailable =
false;
225 float latmin, lonmin, latmax, lonmax;
228 GLuint glTextureName;
239 int tile_x_min, tile_x_max;
240 int tile_y_min, tile_y_max;
242 int nx_tile, ny_tile;
245 std::unordered_map<unsigned int, mbTileDescriptor *> tileMap;
252ChartMBTiles::ChartMBTiles() {
254 m_ChartFamily = CHART_FAMILY_RASTER;
255 m_ChartType = CHART_TYPE_MBTILES;
259 m_datum_str = _T(
"WGS84");
260 m_projection = PROJECTION_WEB_MERCATOR;
261 m_imageType = wxBITMAP_TYPE_ANY;
268 m_nNoCOVREntries = 0;
270 m_pCOVRTablePoints = NULL;
272 m_pNoCOVRTablePoints = NULL;
273 m_pNoCOVRTable = NULL;
276 m_LonMin = LON_UNDEF;
277 m_LonMax = LON_UNDEF;
278 m_LatMin = LAT_UNDEF;
279 m_LatMax = LAT_UNDEF;
281#ifdef OCPN_USE_CONFIG
282 wxFileConfig *pfc = (wxFileConfig *)pConfig;
283 pfc->SetPath(_T (
"/Settings" ));
284 pfc->Read(_T (
"DebugMBTiles" ), &m_b_cdebug, 0);
289ChartMBTiles::~ChartMBTiles() {
301ThumbData *ChartMBTiles::GetThumbData() {
return NULL; }
303ThumbData *ChartMBTiles::GetThumbData(
int tnx,
int tny,
float lat,
float lon) {
307bool ChartMBTiles::UpdateThumbData(
double lat,
double lon) {
return true; }
316double ChartMBTiles::GetNormalScaleMin(
double canvas_scale_factor,
317 bool b_allow_overzoom) {
319 return (canvas_scale_factor / m_ppm_avg) /
326double ChartMBTiles::GetNormalScaleMax(
double canvas_scale_factor,
328 return (canvas_scale_factor / m_ppm_avg) *
332double ChartMBTiles::GetNearestPreferredScalePPM(
double target_scale_ppm) {
333 return target_scale_ppm;
338void ChartMBTiles::InitFromTiles(
const wxString &name) {
341 const char *name_UTF8 =
"";
342 wxCharBuffer utf8CB = name.ToUTF8();
343 if (utf8CB.data()) name_UTF8 = utf8CB.data();
345 SQLite::Database db(name_UTF8);
351 SQLite::Statement query(db,
352 "SELECT min(zoom_level) AS min_zoom, "
353 "max(zoom_level) AS max_zoom FROM tiles");
354 while (query.executeStep()) {
355 const char *colMinZoom = query.getColumn(0);
356 const char *colMaxZoom = query.getColumn(1);
358 int min_zoom = 0, max_zoom = 0;
359 sscanf(colMinZoom,
"%i", &min_zoom);
360 m_minZoom = wxMax(m_minZoom, min_zoom);
361 sscanf(colMaxZoom,
"%i", &max_zoom);
362 m_maxZoom = wxMin(m_maxZoom, max_zoom);
363 if (m_minZoom > m_maxZoom) {
367 m_minZoom = min_zoom;
368 m_maxZoom = max_zoom;
378 if (!std::isnan(m_LatMin) && !std::isnan(m_LatMax) &&
379 !std::isnan(m_LonMin) && !std::isnan(m_LonMax))
390 SQLite::Statement query1(
393 "SELECT min(tile_row) AS min_row, max(tile_row) as max_row, "
394 "min(tile_column) as min_column, max(tile_column) as max_column, "
395 "count(*) as cnt, zoom_level FROM tiles WHERE zoom_level >= %d "
396 "AND zoom_level <= %d GROUP BY zoom_level ORDER BY zoom_level ASC",
397 m_minZoom, m_maxZoom)
399 float minLat = 999., maxLat = -999.0, minLon = 999., maxLon = -999.0;
400 while (query1.executeStep()) {
401 const char *colMinRow = query1.getColumn(0);
402 const char *colMaxRow = query1.getColumn(1);
403 const char *colMinCol = query1.getColumn(2);
404 const char *colMaxCol = query1.getColumn(3);
405 const char *colCnt = query1.getColumn(4);
406 const char *colZoom = query1.getColumn(5);
408 int minRow, maxRow, minCol, maxCol, cnt, zoom;
409 sscanf(colMinRow,
"%i", &minRow);
410 sscanf(colMaxRow,
"%i", &maxRow);
411 sscanf(colMinCol,
"%i", &minCol);
412 sscanf(colMaxCol,
"%i", &maxCol);
413 sscanf(colMinRow,
"%i", &minRow);
414 sscanf(colMaxRow,
"%i", &maxRow);
415 sscanf(colCnt,
"%i", &cnt);
416 sscanf(colZoom,
"%i", &zoom);
421 minLat = wxMin(minLat, tiley2lat(minRow, zoom));
422 maxLat = wxMax(maxLat, tiley2lat(maxRow - 1, zoom));
423 minLon = wxMin(minLon, tilex2long(minCol, zoom));
424 maxLon = wxMax(maxLon, tilex2long(maxCol + 1, zoom));
433 if (std::isnan(m_LatMin)) m_LatMin = minLat;
434 if (std::isnan(m_LatMax)) m_LatMax = maxLat;
435 if (std::isnan(m_LonMin)) m_LonMin = minLon;
436 if (std::isnan(m_LonMax)) m_LonMax = maxLon;
437 }
catch (std::exception &e) {
438 const char *t = e.what();
439 wxLogMessage(
"mbtiles exception: %s", e.what());
443InitReturn ChartMBTiles::Init(
const wxString &name, ChartInitFlag init_flags) {
444 m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB;
447 m_Description = m_FullPath;
451 const char *name_UTF8 =
"";
452 wxCharBuffer utf8CB = name.ToUTF8();
453 if (utf8CB.data()) name_UTF8 = utf8CB.data();
455 SQLite::Database db(name_UTF8);
458 SQLite::Statement query(db,
"SELECT * FROM metadata ");
461 while (query.executeStep()) {
462 const char *colName = query.getColumn(0);
463 const char *colValue = query.getColumn(1);
466 if (!strncmp(colName,
"bounds", 6)) {
467 float lon1, lat1, lon2, lat2;
468 sscanf(colValue,
"%g,%g,%g,%g", &lon1, &lat1, &lon2, &lat2);
471 m_LatMax = wxMax(lat1, lat2);
472 m_LatMin = wxMin(lat1, lat2);
473 m_LonMax = wxMax(lon1, lon2);
474 m_LonMin = wxMin(lon1, lon2);
479 else if(!strncmp(colName,
"format", 6) ){
480 m_format = std::string(colValue);
484 else if (!strncmp(colName,
"minzoom", 7)) {
485 sscanf(colValue,
"%i", &m_minZoom);
486 }
else if (!strncmp(colName,
"maxzoom", 7)) {
487 sscanf(colValue,
"%i", &m_maxZoom);
490 else if (!strncmp(colName,
"description", 11)) {
491 m_Description = wxString(colValue, wxConvUTF8);
492 }
else if (!strncmp(colName,
"name", 11)) {
493 m_Name = wxString(colValue, wxConvUTF8);
494 }
else if (!strncmp(colName,
"type", 11)) {
495 m_Type = wxString(colValue, wxConvUTF8).Upper().IsSameAs(
"OVERLAY")
496 ? MBTilesType::OVERLAY
498 }
else if (!strncmp(colName,
"scheme", 11)) {
499 m_Scheme = wxString(colValue, wxConvUTF8).Upper().IsSameAs(
"XYZ")
501 : MBTilesScheme::TMS;
504 }
catch (std::exception &e) {
505 const char *t = e.what();
506 wxLogMessage(
"mbtiles exception: %s", e.what());
507 return INIT_FAIL_REMOVE;
514 m_ppm_avg = 1.0 / OSM_zoomMPP[m_minZoom];
515 m_Chart_Scale = OSM_zoomScale[m_maxZoom];
522 extentBox.Set(m_LatMin, m_LonMin, m_LatMax, m_LonMax);
524 const char *name_UTF8 =
"";
525 wxCharBuffer utf8CB = name.ToUTF8();
526 if (utf8CB.data()) name_UTF8 = utf8CB.data();
528 SQLite::Database db(name_UTF8);
530 int zoomFactor = m_minZoom;
531 int minRegionZoom = -1;
532 bool covr_populated =
false;
535 while ((zoomFactor <= m_maxZoom) && (minRegionZoom < 0)) {
536 LLRegion covrRegionZoom;
542 sprintf(qrs,
"select count(*) from tiles where zoom_level = %d ",
544 SQLite::Statement query_size(db, qrs);
546 if (query_size.executeStep()) {
547 const char *colValue = query_size.getColumn(0);
548 int tile_at_zoom = atoi(colValue);
549 m_nTiles += tile_at_zoom;
551 if (tile_at_zoom > 1000) {
553 if (!covr_populated) {
554 covr_populated =
true;
555 covrRegion = extentBox;
563 "select tile_column, tile_row from tiles where zoom_level = %d ",
567 SQLite::Statement query(db, qrs);
568 covr_populated =
true;
570 while (query.executeStep()) {
571 const char *colValue = query.getColumn(0);
572 const char *c2 = query.getColumn(1);
573 int tile_x_found = atoi(colValue);
574 int tile_y_found = atoi(c2);
576 regionZoom.Union(tile_x_found, tile_y_found - 1, 1, 1);
580 wxRegionIterator upd(regionZoom);
581 double eps_factor = eps * 100;
584 wxRect rect = upd.GetRect();
587 round(tilex2long(rect.x, zoomFactor) / eps_factor) * eps_factor;
589 round(tilex2long(rect.x + rect.width, zoomFactor) / eps_factor) *
592 round(tiley2lat(rect.y, zoomFactor) / eps_factor) * eps_factor;
594 round(tiley2lat(rect.y + rect.height, zoomFactor) / eps_factor) *
598 box.Set(latmin, lonmin, latmax, lonmax);
600 LLRegion tileRegion(box);
602 covrRegionZoom.Union(tileRegion);
605 minRegionZoom = zoomFactor;
609 covrRegion.Union(covrRegionZoom);
617 covrRegion.Intersect(extentBox);
619 m_minZoomRegion = covrRegion;
622 if (covrRegion.contours.size()) {
623 m_nCOVREntries = covrRegion.contours.size();
624 m_pCOVRTablePoints = (
int *)malloc(m_nCOVREntries *
sizeof(
int));
625 m_pCOVRTable = (
float **)malloc(m_nCOVREntries *
sizeof(
float *));
626 std::list<poly_contour>::iterator it = covrRegion.contours.begin();
627 for (
int i = 0; i < m_nCOVREntries; i++) {
628 m_pCOVRTablePoints[i] = it->size();
630 (
float *)malloc(m_pCOVRTablePoints[i] * 2 *
sizeof(
float));
631 std::list<contour_pt>::iterator jt = it->begin();
632 for (
int j = 0; j < m_pCOVRTablePoints[i]; j++) {
633 m_pCOVRTable[i][2 * j + 0] = jt->y;
634 m_pCOVRTable[i][2 * j + 1] = jt->x;
641 if (init_flags == HEADER_ONLY)
return INIT_OK;
643 InitReturn pi_ret = PostInit();
644 if (pi_ret != INIT_OK)
650InitReturn ChartMBTiles::PreInit(
const wxString &name, ChartInitFlag init_flags,
652 m_global_color_scheme = cs;
656InitReturn ChartMBTiles::PostInit(
void) {
658 const char *name_UTF8 =
"";
659 wxCharBuffer utf8CB = m_FullPath.ToUTF8();
660 if (utf8CB.data()) name_UTF8 = utf8CB.data();
662 m_pDB =
new SQLite::Database(name_UTF8);
663 m_pDB->exec(
"PRAGMA locking_mode=EXCLUSIVE");
664 m_pDB->exec(
"PRAGMA cache_size=-50000");
666 bReadyToRender =
true;
670void ChartMBTiles::PrepareTiles() {
674 for (
int i = 0; i < (m_maxZoom - m_minZoom) + 1; i++) {
682void ChartMBTiles::FlushTiles() {
683 if (!bReadyToRender || m_tileArray ==
nullptr)
return;
684 for (
int iz = 0; iz < (m_maxZoom - m_minZoom) + 1; iz++) {
687 for (
auto const &it : tzd->tileMap) {
690 if (tile->glTextureName > 0) glDeleteTextures(1, &tile->glTextureName);
698void ChartMBTiles::FlushTextures() {
699 if (m_tileArray ==
nullptr) {
702 for (
int iz = 0; iz < (m_maxZoom - m_minZoom) + 1; iz++) {
705 for (
auto const &it : tzd->tileMap) {
707 if (tile && tile->glTextureName > 0) {
708 glDeleteTextures(1, &tile->glTextureName);
709 tile->glTextureName = 0;
715void ChartMBTiles::PrepareTilesForZoom(
int zoomFactor,
bool bset_geom) {
718 m_tileArray[zoomFactor - m_minZoom] = tzd;
721 tzd->tile_x_min = long2tilex(m_LonMin + eps, zoomFactor);
722 tzd->tile_x_max = long2tilex(m_LonMax - eps, zoomFactor);
723 tzd->tile_y_min = lat2tiley(m_LatMin + eps, zoomFactor);
724 tzd->tile_y_max = lat2tiley(m_LatMax - eps, zoomFactor);
726 tzd->nx_tile = abs(tzd->tile_x_max - tzd->tile_x_min) + 1;
727 tzd->ny_tile = tzd->tile_y_max - tzd->tile_y_min + 1;
732bool ChartMBTiles::GetChartExtent(
Extent *pext) {
733 pext->NLAT = m_LatMax;
734 pext->SLAT = m_LatMin;
735 pext->ELON = m_LonMax;
736 pext->WLON = m_LonMin;
741void ChartMBTiles::SetColorScheme(ColorScheme cs,
bool bApplyImmediate) {
742 if (m_global_color_scheme != cs) {
743 m_global_color_scheme = cs;
748void ChartMBTiles::GetValidCanvasRegion(
const ViewPort &VPoint,
750 pValidRegion->Clear();
751 pValidRegion->Union(0, 0, VPoint.pix_width, VPoint.pix_height);
755LLRegion ChartMBTiles::GetValidRegion() {
return m_minZoomRegion; }
757bool ChartMBTiles::RenderViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint) {
762 if (!m_pDB)
return false;
765 if (tile->glTextureName > 0) {
766 glBindTexture(GL_TEXTURE_2D, tile->glTextureName);
770 if (!tile->m_bAvailable)
return false;
775 "select tile_data, length(tile_data) from tiles where zoom_level "
776 "= %d AND tile_column=%d AND tile_row=%d",
777 tile->m_zoomLevel, tile->tile_x, tile->tile_y);
780 SQLite::Statement query(*m_pDB, qrs);
782 int queryResult = query.tryExecuteStep();
783 if (SQLITE_DONE == queryResult) {
784 tile->m_bAvailable =
false;
787 SQLite::Column blobColumn = query.getColumn(0);
788 const void *blob = blobColumn.getBlob();
790 int length = query.getColumn(1);
792 wxMemoryInputStream blobStream(blob, length);
795 blobImage = wxImage(blobStream, wxBITMAP_TYPE_ANY);
796 int blobWidth, blobHeight;
797 unsigned char *imgdata;
799 if (blobImage.IsOk()){
800 blobWidth = blobImage.GetWidth();
801 blobHeight = blobImage.GetHeight();
803 if ((blobWidth != 256) || (blobHeight != 256))
804 blobImage.Rescale(256, 256, wxIMAGE_QUALITY_NORMAL);
805 imgdata = blobImage.GetData();
810 if ((m_global_color_scheme != GLOBAL_COLOR_SCHEME_RGB) &&
811 (m_global_color_scheme != GLOBAL_COLOR_SCHEME_DAY)) {
813 switch (m_global_color_scheme) {
814 case GLOBAL_COLOR_SCHEME_DUSK: {
818 case GLOBAL_COLOR_SCHEME_NIGHT: {
844 for (
int j = 0; j < blobHeight * blobWidth; j++) {
845 unsigned char *d = &imgdata[3 * j];
846 wxImage::RGBValue rgb(*d, *(d + 1), *(d + 2));
847 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
848 hsv.value = hsv.value * dimLevel;
849 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
851 *(d + 1) = nrgb.green;
852 *(d + 2) = nrgb.blue;
859 if (!imgdata)
return false;
861 unsigned char *teximage =
862 (
unsigned char *)malloc(stride * tex_w * tex_h);
863 bool transparent = blobImage.HasAlpha();
865 for (
int j = 0; j < tex_w * tex_h; j++) {
866 for (
int k = 0; k < 3; k++)
867 teximage[j * stride + k] = imgdata[3 * j + k];
871 if (imgdata[3 * j] == 1 && imgdata[3 * j + 1] == 0 &&
872 imgdata[3 * j + 2] == 0) {
873 teximage[j * stride + 3] = 0;
876 teximage[j * stride + 3] =
877 blobImage.GetAlpha(j % tex_w, j / tex_w);
879 teximage[j * stride + 3] = 255;
884 glGenTextures(1, &tile->glTextureName);
885 glBindTexture(GL_TEXTURE_2D, tile->glTextureName);
887 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
888 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
889 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
890 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
892 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA,
893 GL_UNSIGNED_BYTE, teximage);
900 }
catch (std::exception &e) {
901 const char *t = e.what();
902 wxLogMessage(
"mbtiles exception: %s", e.what());
909class wxPoint2DDouble;
911wxPoint2DDouble ChartMBTiles::GetDoublePixFromLL(
ViewPort &vp,
double lat,
915 double xlon = lon - eps;
917 switch (vp.m_projection_type) {
918 case PROJECTION_MERCATOR:
919 case PROJECTION_WEB_MERCATOR:
921 const double z = WGS84_semimajor_axis_meters * mercator_k0;
923 easting = (xlon - vp.clon) * DEGREE * z;
926 const double s = sin(lat * DEGREE);
927 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
929 const double s0 = sin(vp.clat * DEGREE);
930 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
936 double epix = easting * vp.view_scale_ppm;
937 double npix = northing * vp.view_scale_ppm;
942 double angle = vp.rotation;
945 dxr = epix * cos(angle) + npix * sin(angle);
946 dyr = npix * cos(angle) - epix * sin(angle);
952 return wxPoint2DDouble((vp.pix_width / 2.0) + dxr,
953 (vp.pix_height / 2.0) - dyr);
960 bool btexture = getTileTexture(tile);
962 glDisable(GL_TEXTURE_2D);
965#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
968 glEnable(GL_TEXTURE_2D);
970 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
974 float texcoords[] = {0., 1., 0., 0., 1., 0., 1., 1.};
980 p = GetDoublePixFromLL(mvp, tile->latmin, tile->lonmin);
983 p = GetDoublePixFromLL(mvp, tile->latmax, tile->lonmin);
986 p = GetDoublePixFromLL(mvp, tile->latmax, tile->lonmax);
989 p = GetDoublePixFromLL(mvp, tile->latmin, tile->lonmax);
993 if (!g_tile_shader_program) {
995 shaderProgram->addShaderFromSource(tile_vertex_shader_source, GL_VERTEX_SHADER);
996 shaderProgram->addShaderFromSource(tile_fragment_shader_source, GL_FRAGMENT_SHADER);
997 shaderProgram->linkProgram();
998 g_tile_shader_program = shaderProgram;
1005 shader->SetUniform1i(
"uTex", 0);
1007 shader->SetUniformMatrix4fv(
"MVMatrix", (GLfloat *)vp.vp_matrix_transform);
1012 shader->SetAttributePointerf(
"aPos", co1);
1013 shader->SetAttributePointerf(
"aUV", tco1);
1020 GLushort indices1[] = {0,1,3,2};
1021 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
1033 tco1[0] = texcoords[0];
1034 tco1[1] = texcoords[1];
1035 tco1[2] = texcoords[2];
1036 tco1[3] = texcoords[3];
1037 tco1[4] = texcoords[6];
1038 tco1[5] = texcoords[7];
1039 tco1[6] = texcoords[4];
1040 tco1[7] = texcoords[5];
1042 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1047 glDisable(GL_BLEND);
1052bool ChartMBTiles::RenderRegionViewOnGL(
const wxGLContext &glc,
1055 const LLRegion &Region) {
1057 if (VPoint.chart_scale > (20 * OSM_zoomScale[m_minZoom])) {
1058 if (m_nTiles > 500) {
1065 OCPNRegion screen_region(wxRect(0, 0, vp.pix_width, vp.pix_height));
1066 LLRegion screenLLRegion = vp.GetLLRegion(screen_region);
1067 LLBBox screenBox = screenLLRegion.GetBox();
1069 if ((m_LonMax - m_LonMin) > 180) {
1070 LLRegion validRegion = m_minZoomRegion;
1071 validRegion.Intersect(screenLLRegion);
1072 glChartCanvas::SetClipRegion(vp, validRegion);
1075 glChartCanvas::SetClipRegion(vp, m_minZoomRegion);
1078 glEnable(GL_TEXTURE_2D);
1080 int viewZoom = m_maxZoom;
1084 for (
int kz = m_minZoom; kz <= 19; kz++) {
1085 double db_mpp = OSM_zoomMPP[kz];
1086 double vp_mpp = 1. / vp.view_scale_ppm;
1088 if (db_mpp < vp_mpp * zoomMod) {
1094 viewZoom = wxMin(viewZoom, m_maxZoom);
1098 int zoomFactor = m_minZoom;
1104 int maxrenZoom = m_minZoom;
1106 LLBBox box = Region.GetBox();
1110 bool btwoPass =
false;
1111 if (((screenBox.GetMinLon() < -180) && (screenBox.GetMaxLon() > -180)) ||
1112 ((screenBox.GetMinLon() < 180) && (screenBox.GetMaxLon() > 180))) {
1118 while (zoomFactor <= viewZoom) {
1125 wxMin(tzd->tile_y_max, lat2tiley(box.GetMaxLat(), zoomFactor));
1127 wxMax(tzd->tile_y_min, lat2tiley(box.GetMinLat(), zoomFactor));
1128 int leftTile = long2tilex(box.GetMinLon(), zoomFactor);
1129 int rightTile = long2tilex(box.GetMaxLon(), zoomFactor);
1132 leftTile = long2tilex(-180 + eps, zoomFactor);
1133 rightTile = long2tilex(box.GetMaxLon(), zoomFactor);
1135 if (vp.clon > 0) vp.clon -= 360;
1146 for (
int i = botTile; i < topTile; i++) {
1147 if ((i > tzd->tile_y_max) || (i < tzd->tile_y_min))
continue;
1149 for (
int j = leftTile; j < rightTile + 1; j++) {
1150 if ((tzd->tile_x_max >= tzd->tile_x_min) &&
1151 ((j > tzd->tile_x_max) || (j < tzd->tile_x_min)))
1154 unsigned int index = ((i - tzd->tile_y_min) * (tzd->nx_tile + 1)) + j;
1158 if (tzd->tileMap.find(index) != tzd->tileMap.end())
1159 tile = tzd->tileMap[index];
1164 tile->m_zoomLevel = zoomFactor;
1165 tile->m_bAvailable =
true;
1167 tzd->tileMap[index] = tile;
1170 if (!tile->m_bgeomSet) {
1172 round(tilex2long(tile->tile_x, zoomFactor) / eps) * eps;
1174 round(tilex2long(tile->tile_x + 1, zoomFactor) / eps) * eps;
1176 round(tiley2lat(tile->tile_y - 1, zoomFactor) / eps) * eps;
1177 tile->latmax = round(tiley2lat(tile->tile_y, zoomFactor) / eps) * eps;
1179 tile->box.Set(tile->latmin, tile->lonmin, tile->latmax, tile->lonmax);
1180 tile->m_bgeomSet =
true;
1183 if (!Region.IntersectOut(tile->box)) {
1184 if (RenderTile(tile, zoomFactor, vp)) maxrenZoom = zoomFactor;
1192 if (vp.clon < 0) vp.clon += 360;
1197 wxMin(tzd->tile_y_max, lat2tiley(box.GetMaxLat(), zoomFactor));
1199 wxMax(tzd->tile_y_min, lat2tiley(box.GetMinLat(), zoomFactor));
1200 int leftTile = long2tilex(box.GetMinLon(), zoomFactor);
1201 int rightTile = long2tilex(-180 - eps , zoomFactor);
1203 if (rightTile < leftTile) rightTile = leftTile;
1206 for (
int i = botTile; i < topTile; i++) {
1207 for (
int j = leftTile; j < rightTile + 1; j++) {
1208 unsigned int index = ((i - tzd->tile_y_min) * (tzd->nx_tile + 1)) + j;
1214 if (tzd->tileMap.find(index) != tzd->tileMap.end())
1215 tile = tzd->tileMap[index];
1220 tile->m_zoomLevel = zoomFactor;
1221 tile->m_bAvailable =
true;
1223 tzd->tileMap[index] = tile;
1226 if (!tile->m_bgeomSet) {
1228 round(tilex2long(tile->tile_x, zoomFactor) / eps) * eps;
1230 round(tilex2long(tile->tile_x + 1, zoomFactor) / eps) * eps;
1232 round(tiley2lat(tile->tile_y - 1, zoomFactor) / eps) * eps;
1234 round(tiley2lat(tile->tile_y, zoomFactor) / eps) * eps;
1236 tile->box.Set(tile->latmin, tile->lonmin, tile->latmax,
1238 tile->m_bgeomSet =
true;
1241 if (!Region.IntersectOut(tile->box)) RenderTile(tile, zoomFactor, vp);
1249 glDisable(GL_TEXTURE_2D);
1251 m_zoomScaleFactor = 2.0 * OSM_zoomMPP[maxrenZoom] * VPoint.view_scale_ppm;
1253 glChartCanvas::DisableClipRegion();
1258bool ChartMBTiles::RenderRegionViewOnDC(wxMemoryDC &dc,
const ViewPort &VPoint,
1260 gFrame->GetPrimaryCanvas()->SetAlertString(
1261 _(
"MBTile requires OpenGL to be enabled"));