37#include <wx/progdlg.h>
39#include <wx/stopwatch.h>
40#include <wx/tokenzr.h>
56#include "user_colors.h"
59#include "androidUTIL.h"
66extern ColorScheme GetColorScheme();
69extern s52plib *ps52plib;
75bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
77static bool IsSingleChart(
ChartBase *chart) {
78 if (chart ==
nullptr)
return false;
83 if (cc && cc->m_singleChart == chart) {
93int ChartStack::GetCurrentEntrydbIndex() {
94 if (nEntry && (CurrentStackEntry >= 0) )
95 return DBIndex[CurrentStackEntry];
100void ChartStack::SetCurrentEntryFromdbIndex(
int current_db_index) {
101 for (
int i = 0; i < nEntry; i++) {
102 if (current_db_index == DBIndex[i]) CurrentStackEntry = i;
106int ChartStack::GetDBIndex(
int stack_index) {
107 if ((stack_index >= 0) && (stack_index < nEntry) && (stack_index < MAXSTACK))
108 return DBIndex[stack_index];
113void ChartStack::SetDBIndex(
int stack_index,
int db_index) {
114 if ((stack_index >= 0) && (stack_index < nEntry) && (stack_index < MAXSTACK))
115 DBIndex[stack_index] = db_index;
118bool ChartStack::DoesStackContaindbIndex(
int db_index) {
119 for (
int i = 0; i < nEntry; i++) {
120 if (db_index == DBIndex[i])
return true;
126void ChartStack::AddChart(
int db_add) {
131 int db_index = db_add;
138 SetDBIndex(j - 1, db_index);
148 for (
int id = 0;
id < j - 1;
id++) {
149 if (GetDBIndex(
id) != -1) {
150 auto &pm =
ChartData->GetChartTableEntry(GetDBIndex(
id));
152 for (
int jd =
id + 1; jd < j; jd++) {
153 if (GetDBIndex(jd) != -1) {
154 auto &pn =
ChartData->GetChartTableEntry(GetDBIndex(jd));
155 if (pm.GetFileTime() && pn.GetFileTime()) {
156 if (labs(pm.GetFileTime() - pn.GetFileTime()) <
158 if (pn.GetpFileName()->IsSameAs(*(pm.GetpFileName())))
169 if (GetDBIndex(
id) == -1) {
172 int db_index = GetDBIndex(jd);
173 SetDBIndex(jd - 1, db_index);
190 for (
int i = 0; i < j - 1; i++) {
193 ChartData->GetChartTableEntry(GetDBIndex(i + 1));
195 if (n.GetScale() < m.GetScale()) {
197 SetDBIndex(i, GetDBIndex(i + 1));
198 SetDBIndex(i + 1, ti);
210 pChartCache =
new wxArrayPtrVoid;
219 if (g_memCacheLimit) {
221 msg.Printf(
"ChartDB Cache policy: Application target is %d MBytes",
222 g_memCacheLimit / 1024);
226 msg.Printf(
"ChartDB Cache policy: Max open chart limit is %d.",
231 m_checkGroupIndex[0] = m_checkGroupIndex[1] = -1;
232 m_checkedTileOnly[0] = m_checkedTileOnly[1] =
false;
243 ArrayOfCDI &dir_array_check) {
244 m_dir_array = dir_array_check;
245 return ChartDatabase::Read(filename);
250void ChartDB::DeleteCacheEntry(
CacheEntry *pce,
bool bDelTexture,
251 const wxString &msg) {
254 if (msg != wxEmptyString) {
255 wxLogMessage(
"%s%s", msg.c_str(), ch->GetFullPath().c_str());
269 pChartCache->Remove(pce);
274void ChartDB::DeleteCacheEntry(
int i,
bool bDelTexture,
const wxString &msg) {
276 if (pce) DeleteCacheEntry(pce, bDelTexture, msg);
279void ChartDB::PurgeCache() {
283 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
284 unsigned int nCache = pChartCache->GetCount();
285 for (
unsigned int i = 0; i < nCache; i++) {
286 DeleteCacheEntry(0,
true);
288 pChartCache->Clear();
290 m_cache_mutex.Unlock();
294void ChartDB::PurgeCachePlugins() {
296 wxLogMessage(
"Chart cache PlugIn purge");
298 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
299 unsigned int nCache = pChartCache->GetCount();
305 if (CHART_TYPE_PLUGIN == Ch->GetChartType()) {
306 DeleteCacheEntry(pce,
true);
308 nCache = pChartCache->GetCount();
315 m_cache_mutex.Unlock();
319void ChartDB::ClearCacheInUseFlags() {
320 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
321 unsigned int nCache = pChartCache->GetCount();
322 for (
unsigned int i = 0; i < nCache; i++) {
324 pce->b_in_use =
false;
326 m_cache_mutex.Unlock();
333void ChartDB::PurgeCacheUnusedCharts(
double factor) {
335 if (g_memCacheLimit) {
336 if (wxMUTEX_NO_ERROR == m_cache_mutex.TryLock()) {
340 int mem_limit = g_memCacheLimit * factor;
342 int nl = pChartCache->GetCount();
344 wxString msg(
"Purging unused chart from cache: ");
346 while ((mem_used > mem_limit) && (nl > 0)) {
347 if (pChartCache->GetCount() < 2) {
352 CacheEntry *pce = FindOldestDeleteCandidate(
false);
355 DeleteCacheEntry(pce,
false , msg);
366 m_cache_mutex.Unlock();
370 else if (g_nCacheLimit) {
371 if (wxMUTEX_NO_ERROR == m_cache_mutex.TryLock()) {
373 double fac10 = factor * 10;
374 int chart_limit = g_nCacheLimit * fac10 / 10;
376 int nl = pChartCache->GetCount();
378 wxString msg(
"Purging unused chart from cache: ");
379 while ((nl > chart_limit) && (nl > 0)) {
380 if (pChartCache->GetCount() < 2) {
385 CacheEntry *pce = FindOldestDeleteCandidate(
false);
388 DeleteCacheEntry(pce,
false , msg);
393 nl = pChartCache->GetCount();
396 m_cache_mutex.Unlock();
405ChartBase *ChartDB::GetChart(
const wxChar *theFilePath,
407 wxFileName fn(theFilePath);
409 if (!fn.FileExists()) {
411 if (!wxDir::Exists(theFilePath)) {
412 wxLogMessage(
" ...file does not exist: %s", theFilePath);
418 wxString chartExt = fn.GetExt().Upper();
420 if (chartExt ==
"XZ") {
421 wxString npath = theFilePath;
422 npath = npath.Left(npath.length() - 3);
423 wxFileName fn(npath);
424 chartExt = fn.GetExt().Upper();
427 if (chartExt ==
"KAP") {
429 }
else if (chartExt ==
"GEO") {
431 }
else if (chartExt ==
"MBTILES") {
433 }
else if (chartExt ==
"000" || chartExt ==
"S57") {
436 }
else if (chart_desc.m_descriptor_type == PLUGIN_DESCRIPTOR) {
443 wxRegEx rxName(
"[0-9]+");
444 wxRegEx rxExt(
"[A-G]");
445 if (rxName.Matches(fn.GetName()) && rxExt.Matches(chartExt))
456bool ChartDB::IsChartDirectoryExcluded(
const std::string &chart_file) {
466int ChartDB::BuildChartStack(
ChartStack *cstk,
float lat,
float lon,
int db_add,
468 BuildChartStack(cstk, lat, lon, groupIndex);
470 if (db_add >= 0) cstk->AddChart(db_add);
475int ChartDB::BuildChartStack(
ChartStack *cstk,
float lat,
float lon,
480 if (!IsValid())
return 0;
484 int nEntry = GetChartTableEntries();
486 for (
int db_index = 0; db_index < nEntry; db_index++) {
490 if (IsChartDirectoryExcluded(cte.GetFullPath()))
continue;
493 bool b_group_add =
false;
494 if (groupIndex > 0) {
495 const int ng = cte.GetGroupArray().size();
496 for (
int ig = 0; ig < ng; ig++) {
497 if (groupIndex == cte.GetGroupArray()[ig]) {
505 bool b_writable_add =
true;
509 wxFileName fn(cte.GetFullSystemPath());
510 if (!androidIsDirWritable(fn.GetPath())) b_writable_add =
false;
513 bool b_pos_add =
false;
514 if (b_group_add && b_writable_add) {
518 if (cte.GetChartType() == CHART_TYPE_PLUGIN) {
523 if (CheckPositionWithinChart(db_index, lat, lon) && (j < MAXSTACK))
527 else if ((cte.GetLonMax() > 180.) && (cte.GetLonMin() < 180.)) {
528 if (CheckPositionWithinChart(db_index, lat, lon + 360.) &&
533 else if ((cte.GetLonMax() > 180.) && (cte.GetLonMin() > 180.)) {
534 if (CheckPositionWithinChart(db_index, lat, lon + 360.) &&
540 bool b_available =
true;
542 if (b_group_add && b_pos_add && (cte.GetChartType() == CHART_TYPE_PLUGIN)) {
544 if (!IsChartAvailable(db_index)) {
545 pcte->SetAvailable(
false);
548 pcte->SetAvailable(
true);
553 if (b_group_add && b_pos_add && b_available) {
556 cstk->SetDBIndex(j - 1, db_index);
572 for (
int id = 0;
id < j - 1;
id++) {
573 if (cstk->GetDBIndex(
id) != -1) {
574 const ChartTableEntry &ctem = GetChartTableEntry(cstk->GetDBIndex(
id));
576 for (
int jd =
id + 1; jd < j; jd++) {
577 if (cstk->GetDBIndex(jd) != -1) {
579 GetChartTableEntry(cstk->GetDBIndex(jd));
580 bool bsameTime =
false;
581 if (ctem.GetFileTime() && cten.GetFileTime()) {
582 if (labs(ctem.GetFileTime() - cten.GetFileTime()) < 60)
585 if (ctem.GetChartEditionDate() == cten.GetChartEditionDate())
589 if (cten.GetpFileName()->IsSameAs(*(ctem.GetpFileName())))
590 cstk->SetDBIndex(jd, -1);
599 if (cstk->GetDBIndex(
id) == -1) {
602 int db_index = cstk->GetDBIndex(jd);
603 cstk->SetDBIndex(jd - 1, db_index);
620 for (i = 0; i < j - 1; i++) {
622 const ChartTableEntry &n = GetChartTableEntry(cstk->GetDBIndex(i + 1));
624 if (n.GetScale() < m.GetScale()) {
625 ti = cstk->GetDBIndex(i);
626 cstk->SetDBIndex(i, cstk->GetDBIndex(i + 1));
627 cstk->SetDBIndex(i + 1, ti);
633 cstk->b_valid =
true;
638bool ChartDB::IsChartInGroup(
const int db_index,
const int group) {
642 bool b_in_group =
false;
644 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
645 if (group == pt->GetGroupArray()[ig]) {
656bool ChartDB::IsENCInGroup(
const int groupIndex) {
660 for (
int db_index = 0; db_index < GetChartTableEntries(); db_index++) {
664 bool b_group_add =
false;
665 if (groupIndex > 0) {
666 const int ng = cte.GetGroupArray().size();
667 for (
int ig = 0; ig < ng; ig++) {
668 if (groupIndex == cte.GetGroupArray()[ig]) {
677 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
687bool ChartDB::IsNonMBTileInGroup(
const int groupIndex) {
692 for (
int db_index = 0; db_index < GetChartTableEntries(); db_index++) {
696 bool b_group_add =
false;
697 if (groupIndex > 0) {
698 const int ng = cte.GetGroupArray().size();
699 for (
int ig = 0; ig < ng; ig++) {
700 if (groupIndex == cte.GetGroupArray()[ig]) {
709 if (cte.GetChartType() != CHART_TYPE_MBTILES) {
722bool ChartDB::CheckPositionWithinChart(
int index,
float lat,
float lon) {
727 if ((lat <= pt->GetLatMax()) && (lat >= pt->GetLatMin()) &&
728 (lon >= pt->GetLonMin()) && (lon <= pt->GetLonMax())) {
731 bool bInside = G_FloatPtInPolygon((
MyFlPoint *)pt->GetpPlyTable(),
732 pt->GetnPlyEntries(), lon, lat);
735 if (pt->GetnAuxPlyEntries()) {
736 for (
int k = 0; k < pt->GetnAuxPlyEntries(); k++) {
738 G_FloatPtInPolygon((
MyFlPoint *)pt->GetpAuxPlyTableEntry(k),
739 pt->GetAuxCntTableEntry(k), lon, lat);
740 if (bAuxInside)
return true;
756 if ((pa == 0) || (pb == 0))
return false;
757 if ((!pa->b_valid) || (!pb->b_valid))
return false;
758 if (pa->nEntry != pb->nEntry)
return false;
760 for (
int i = 0; i < pa->nEntry; i++) {
761 if (pa->GetDBIndex(i) != pb->GetDBIndex(i))
return false;
771 if ((pa == 0) || (pb == 0))
return false;
772 pa->nEntry = pb->nEntry;
774 for (
int i = 0; i < pa->nEntry; i++) pa->SetDBIndex(i, pb->GetDBIndex(i));
776 pa->CurrentStackEntry = pb->CurrentStackEntry;
778 pa->b_valid = pb->b_valid;
783wxString ChartDB::GetFullPath(
ChartStack *ps,
int stackindex) {
784 int dbIndex = ps->GetDBIndex(stackindex);
785 return GetChartTableEntry(dbIndex).GetFullSystemPath();
792int ChartDB::GetCSPlyPoint(
ChartStack *ps,
int stackindex,
int plyindex,
793 float *lat,
float *lon) {
794 int dbIndex = ps->GetDBIndex(stackindex);
795 wxASSERT(dbIndex >= 0);
798 if (entry.GetnPlyEntries()) {
799 float *fp = entry.GetpPlyTable();
806 return entry.GetnPlyEntries();
812int ChartDB::GetStackChartScale(
ChartStack *ps,
int stackindex,
char *buf,
814 int dbindex = ps->GetDBIndex(stackindex);
815 wxASSERT(dbindex >= 0);
818 int sc = entry.GetScale();
819 if (buf) sprintf(buf,
"%d", sc);
827int ChartDB::GetStackEntry(
ChartStack *ps, wxString fp) {
828 for (
int i = 0; i < ps->nEntry; i++) {
830 if (fp.IsSameAs(entry.GetFullSystemPath()))
return i;
839ChartTypeEnum ChartDB::GetCSChartType(
ChartStack *ps,
int stackindex) {
841 int dbindex = ps->GetDBIndex(stackindex);
843 return (ChartTypeEnum)GetChartTableEntry(dbindex).GetChartType();
845 return CHART_TYPE_UNKNOWN;
848ChartFamilyEnum ChartDB::GetCSChartFamily(
ChartStack *ps,
int stackindex) {
850 int dbindex = ps->GetDBIndex(stackindex);
854 ChartTypeEnum type = (ChartTypeEnum)entry.GetChartType();
857 return CHART_FAMILY_RASTER;
859 return CHART_FAMILY_RASTER;
861 return CHART_FAMILY_VECTOR;
862 case CHART_TYPE_CM93:
863 return CHART_FAMILY_VECTOR;
864 case CHART_TYPE_CM93COMP:
865 return CHART_FAMILY_VECTOR;
866 case CHART_TYPE_DUMMY:
867 return CHART_FAMILY_RASTER;
869 return CHART_FAMILY_UNKNOWN;
873 return CHART_FAMILY_UNKNOWN;
876std::vector<int> ChartDB::GetCSArray(
ChartStack *ps) {
877 std::vector<int> ret;
880 ret.reserve(ps->nEntry);
881 for (
int i = 0; i < ps->nEntry; i++) {
882 ret.push_back(ps->GetDBIndex(i));
889bool ChartDB::IsChartInCache(
int dbindex) {
890 bool bInCache =
false;
893 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
894 unsigned int nCache = pChartCache->GetCount();
895 for (
unsigned int i = 0; i < nCache; i++) {
897 if (pce->dbIndex == dbindex) {
898 if (pce->pChart != 0 && ((
ChartBase *)pce->pChart)->IsReadyToRender())
903 m_cache_mutex.Unlock();
909bool ChartDB::IsChartInCache(wxString path) {
910 bool bInCache =
false;
911 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
913 unsigned int nCache = pChartCache->GetCount();
914 for (
unsigned int i = 0; i < nCache; i++) {
916 if (pce->FullPath == path) {
917 if (pce->pChart != 0 && ((
ChartBase *)pce->pChart)->IsReadyToRender())
923 m_cache_mutex.Unlock();
928bool ChartDB::IsChartLocked(
int index) {
929 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
930 unsigned int nCache = pChartCache->GetCount();
931 for (
unsigned int i = 0; i < nCache; i++) {
933 if (pce->dbIndex == index) {
934 bool ret = pce->n_lock > 0;
935 m_cache_mutex.Unlock();
939 m_cache_mutex.Unlock();
945bool ChartDB::LockCacheChart(
int index) {
948 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
949 unsigned int nCache = pChartCache->GetCount();
950 for (
unsigned int i = 0; i < nCache; i++) {
952 if (pce->dbIndex == index) {
958 m_cache_mutex.Unlock();
963void ChartDB::UnLockCacheChart(
int index) {
965 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
966 unsigned int nCache = pChartCache->GetCount();
967 for (
unsigned int i = 0; i < nCache; i++) {
969 if (pce->dbIndex == index) {
970 if (pce->n_lock > 0) pce->n_lock--;
974 m_cache_mutex.Unlock();
978void ChartDB::UnLockAllCacheCharts() {
980 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
981 unsigned int nCache = pChartCache->GetCount();
982 for (
unsigned int i = 0; i < nCache; i++) {
984 if (pce->n_lock > 0) pce->n_lock--;
986 m_cache_mutex.Unlock();
993ChartBase *ChartDB::OpenChartFromDB(
int index, ChartInitFlag init_flag) {
994 return OpenChartUsingCache(index, init_flag);
997ChartBase *ChartDB::OpenChartFromDB(wxString chart_path,
998 ChartInitFlag init_flag) {
999 int dbii = FinddbIndex(chart_path);
1000 return OpenChartUsingCache(dbii, init_flag);
1004 ChartInitFlag init_flag) {
1005 return OpenChartUsingCache(pStack->GetDBIndex(StackEntry), init_flag);
1008ChartBase *ChartDB::OpenChartFromDBAndLock(
int index, ChartInitFlag init_flag,
1010 wxCriticalSectionLocker locker(m_critSect);
1011 ChartBase *pret = OpenChartUsingCache(index, init_flag);
1012 if (lock && pret) LockCacheChart(index);
1016ChartBase *ChartDB::OpenChartFromDBAndLock(wxString chart_path,
1017 ChartInitFlag init_flag) {
1018 int dbii = FinddbIndex(chart_path);
1019 return OpenChartFromDBAndLock(dbii, init_flag);
1022CacheEntry *ChartDB::FindOldestDeleteCandidate(
bool blog) {
1025 unsigned int nCache = pChartCache->GetCount();
1027 if (blog) wxLogMessage(
"Searching chart cache for oldest entry");
1028 int LRUTime = m_ticks;
1030 for (
unsigned int i = 0; i < nCache; i++) {
1032 if (pce->RecentTime < LRUTime && !pce->n_lock) {
1033 if (!IsSingleChart((
ChartBase *)(pce->pChart))) {
1034 LRUTime = pce->RecentTime;
1039 int dt = m_ticks - LRUTime;
1044 if (!pce->n_lock && !IsSingleChart(pDeleteCandidate)) {
1046 wxLogMessage(
"Oldest unlocked cache index is %d, delta t is %d",
1051 wxLogMessage(
"All chart in cache locked, size: %d", nCache);
1057ChartBase *ChartDB::OpenChartUsingCache(
int dbindex, ChartInitFlag init_flag) {
1058 if ((dbindex < 0) || (dbindex > GetChartTableEntries() - 1))
return NULL;
1063 wxString ChartFullPath = cte.GetFullSystemPath();
1064 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1065 ChartFamilyEnum chart_family = (ChartFamilyEnum)cte.GetChartFamily();
1068 msg1.Printf(
"OpenChartUsingCache: type %d ", chart_type);
1071 if (cte.GetLatMax() > 90.0)
1078 bool bInCache =
false;
1082 wxMutexLocker lock(m_cache_mutex);
1084 unsigned int nCache = pChartCache->GetCount();
1086 for (
unsigned int i = 0; i < nCache; i++) {
1088 if (pce->FullPath == ChartFullPath) {
1097 msg.Printf(
"OpenChartUsingCache, IN cache: cache size: %d\n",
1098 (
int)pChartCache->GetCount());
1100 if (FULL_INIT == init_flag)
1102 if (Ch->IsReadyToRender()) {
1104 pce->RecentTime = m_ticks;
1105 pce->b_in_use =
true;
1112 old_lock = pce->n_lock;
1113 pChartCache->Remove(pce);
1121 pce->RecentTime = m_ticks;
1122 pce->b_in_use =
true;
1133 if (g_memCacheLimit) {
1139 msg.Printf(
"OpenChartUsingCache, NOT in cache: cache size: %d\n",
1140 (
int)pChartCache->GetCount());
1143 msg1.Printf(
" OpenChartUsingCache: type %d ", chart_type);
1144 wxLogMessage(msg1 + ChartFullPath);
1146 if ((mem_used > g_memCacheLimit * 8 / 10) &&
1147 (pChartCache->GetCount() > 2)) {
1148 wxString msg(
"Removing oldest chart from cache: ");
1150 CacheEntry *pce = FindOldestDeleteCandidate(
true);
1151 if (pce == 0)
break;
1154 DeleteCacheEntry(pce,
true, msg);
1157 if ((mem_used < g_memCacheLimit * 8 / 10) ||
1158 (pChartCache->GetCount() <= 2))
1169 unsigned int nCache = pChartCache->GetCount();
1170 if (nCache > (
unsigned int)g_nCacheLimit && nCache > 2) {
1171 wxString msg(
"Removing oldest chart from cache: ");
1172 while (nCache > (
unsigned int)g_nCacheLimit) {
1173 CacheEntry *pce = FindOldestDeleteCandidate(
true);
1174 if (pce == 0)
break;
1176 DeleteCacheEntry(pce,
true, msg);
1187 wxLogMessage(
"Creating new chart");
1189 if (chart_type == CHART_TYPE_KAP)
1192 else if (chart_type == CHART_TYPE_GEO)
1195 else if (chart_type == CHART_TYPE_MBTILES)
1198 else if (chart_type == CHART_TYPE_S57) {
1203 Chs57->SetNativeScale(cte.GetScale());
1208 ext.NLAT = cte.GetLatMax();
1209 ext.SLAT = cte.GetLatMin();
1210 ext.WLON = cte.GetLonMin();
1211 ext.ELON = cte.GetLonMax();
1212 Chs57->SetFullExtent(ext);
1215 else if (chart_type == CHART_TYPE_CM93) {
1220 Chcm93->SetNativeScale(cte.GetScale());
1225 ext.NLAT = cte.GetLatMax();
1226 ext.SLAT = cte.GetLatMin();
1227 ext.WLON = cte.GetLonMin();
1228 ext.ELON = cte.GetLonMax();
1229 Chcm93->SetFullExtent(ext);
1232 else if (chart_type == CHART_TYPE_CM93COMP) {
1238 Chcm93->SetNativeScale(cte.GetScale());
1243 ext.NLAT = cte.GetLatMax();
1244 ext.SLAT = cte.GetLatMin();
1245 ext.WLON = cte.GetLonMin();
1246 ext.ELON = cte.GetLonMax();
1247 Chcm93->SetFullExtent(ext);
1250 else if (chart_type == CHART_TYPE_PLUGIN) {
1251 wxFileName fn(ChartFullPath);
1252 wxString ext = fn.GetExt();
1254 wxString ext_upper = ext.MakeUpper();
1255 wxString ext_lower = ext.MakeLower();
1256 wxString chart_class_name;
1261 for (
auto &cd : m_ChartClassDescriptorArray) {
1262 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
1263 if (cd.m_search_mask == ext_upper) {
1264 chart_class_name = cd.m_class_name;
1267 if (cd.m_search_mask == ext_lower) {
1268 chart_class_name = cd.m_class_name;
1271 if (ChartFullPath.Matches(cd.m_search_mask)) {
1272 chart_class_name = cd.m_class_name;
1279 if (chart_class_name.Len()) {
1282 if (chart_family == CHART_FAMILY_VECTOR) LoadS57();
1288 wxLogMessage(
"Unknown chart type");
1294 s52plib *plib = ps52plib;
1295 wxString msg_fn(ChartFullPath);
1296 msg_fn.Replace(
"%",
"%%");
1299 if ((chart_family != CHART_FAMILY_VECTOR) ||
1300 ((chart_family == CHART_FAMILY_VECTOR) && plib)) {
1301 wxLogMessage(wxString::Format(
"Initializing Chart %s", msg_fn.c_str()));
1303 ir = Ch->Init(ChartFullPath, init_flag);
1304 Ch->SetColorScheme(user_colors::GetColorScheme());
1306 wxLogMessage(wxString::Format(
" No PLIB, Skipping vector chart %s",
1309 ir = INIT_FAIL_REMOVE;
1312 if (INIT_OK == ir) {
1318 pce->FullPath = ChartFullPath;
1320 pce->dbIndex = dbindex;
1323 pce->RecentTime = m_ticks;
1324 pce->n_lock = old_lock;
1326 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1327 pChartCache->Add((
void *)pce);
1328 m_cache_mutex.Unlock();
1343 if (chart_type == CHART_TYPE_MBTILES) {
1344 wxFileName tileFile(ChartFullPath);
1346 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
1348 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1350 if (!CheckAnyCanvasExclusiveTileGroup() ||
1351 (tileSizeMB.GetLo() > 5000)) {
1354 bool b_clicked =
false;
1358 switch (g_canvasConfig) {
1360 cc = config_array.Item(0);
1364 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1366 cc = config_array.Item(1);
1370 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1374 cc = config_array.Item(0);
1378 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1385 switch (g_canvasConfig) {
1387 cc = config_array.Item(0);
1390 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1392 cc = config_array.Item(1);
1395 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1399 cc = config_array.Item(0);
1402 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1409 }
else if (INIT_FAIL_REMOVE == ir)
1412 wxString::Format(
"Problem initializing Chart %s", msg_fn.c_str()));
1419 DisableChart(ChartFullPath);
1420 }
else if ((INIT_FAIL_RETRY == ir) ||
1421 (INIT_FAIL_NOERROR ==
1424 wxLogMessage(wxString::Format(
1425 "Recoverable problem initializing Chart %s", msg_fn.c_str()));
1430 if (INIT_OK != ir) {
1433 wxString::Format(
" OpenChartFromStack... Error opening "
1434 "chart %s ... return code %d",
1435 msg_fn.c_str(), ir));
1449bool ChartDB::DeleteCacheChart(
ChartBase *pDeleteCandidate) {
1450 bool retval =
false;
1452 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1453 if (!IsSingleChart(pDeleteCandidate)) {
1456 for (
unsigned int i = 0; i < pChartCache->GetCount(); i++) {
1458 if ((
ChartBase *)(pce->pChart) == pDeleteCandidate) {
1464 if (pce->n_lock > 0) pce->n_lock--;
1466 if (pce->n_lock == 0) {
1467 DeleteCacheEntry(pce);
1472 m_cache_mutex.Unlock();
1480void ChartDB::ApplyColorSchemeToCachedCharts(ColorScheme cs) {
1489 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1490 unsigned int nCache = pChartCache->GetCount();
1491 for (
unsigned int i = 0; i < nCache; i++) {
1494 if (Ch) Ch->SetColorScheme(cs,
true);
1497 m_cache_mutex.Unlock();
1507ChartBase *ChartDB::OpenStackChartConditional(
1508 ChartStack *ps,
int index_start,
bool bSearchDir, ChartTypeEnum New_Type,
1509 ChartFamilyEnum New_Family_Fallback) {
1515 if (bSearchDir == 1)
1521 index = index_start;
1523 while ((index >= 0) && (index < ps->nEntry)) {
1524 ChartTypeEnum chart_type = (ChartTypeEnum)GetCSChartType(ps, index);
1525 if ((chart_type == New_Type) || (New_Type == CHART_TYPE_DONTCARE)) {
1526 ptc = OpenChartFromStack(ps, index);
1527 if (NULL != ptc)
break;
1529 index += delta_index;
1535 index = index_start;
1537 while ((index >= 0) && (index < ps->nEntry)) {
1538 ChartFamilyEnum chart_family = GetCSChartFamily(ps, index);
1539 if (chart_family == New_Family_Fallback) {
1540 ptc = OpenChartFromStack(ps, index);
1542 if (NULL != ptc)
break;
1544 index += delta_index;
1551wxXmlDocument ChartDB::GetXMLDescription(
int dbIndex,
bool b_getGeom) {
1553 if (!IsValid() || (dbIndex >= GetChartTableEntries()))
return doc;
1555 bool b_remove = !IsChartInCache(dbIndex);
1557 wxXmlNode *pcell_node = NULL;
1562 ChartBase *pc = OpenChartFromDB(dbIndex, HEADER_ONLY);
1563 b_remove = !IsChartInCache(dbIndex);
1566 if (CHART_FAMILY_RASTER == (ChartFamilyEnum)cte.GetChartFamily()) {
1567 pcell_node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"chart");
1569 wxString path = GetDBChartFileName(dbIndex);
1570 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"path");
1571 pcell_node->AddChild(node);
1572 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", path);
1573 node->AddChild(tnode);
1575 wxFileName name(path);
1576 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"name");
1577 pcell_node->AddChild(node);
1578 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", name.GetName());
1579 node->AddChild(tnode);
1582 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lname");
1583 pcell_node->AddChild(node);
1584 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetName());
1585 node->AddChild(tnode);
1589 scale.Printf(
"%d", cte.GetScale());
1590 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cscale");
1591 pcell_node->AddChild(node);
1592 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"",
scale);
1593 node->AddChild(tnode);
1595 wxDateTime file_date(cte.GetFileTime());
1596 file_date.MakeUTC();
1597 wxString sfile_date = file_date.FormatISODate();
1599 sfile_date += file_date.FormatISOTime();
1601 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"local_file_datetime_iso8601");
1602 pcell_node->AddChild(node);
1603 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sfile_date);
1604 node->AddChild(tnode);
1607 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"source_edition");
1608 pcell_node->AddChild(node);
1609 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetSE());
1610 node->AddChild(tnode);
1612 wxDateTime sdt = pc->GetEditionDate();
1613 wxString ssdt =
"Unknown";
1614 if (sdt.IsValid()) ssdt = sdt.Format(
"%Y%m%d");
1616 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"source_date");
1617 pcell_node->AddChild(node);
1618 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", ssdt);
1619 node->AddChild(tnode);
1625 if (s == "raster_edition")
1626 if (s == "ntm_edition")
1628 if (s == "ntm_date")
1629 if (s == "source_edition_last_correction")
1630 if (s == "raster_edition_last_correction")
1631 if (s == "ntm_edition_last_correction")
1635 else if (CHART_FAMILY_VECTOR == (ChartFamilyEnum)cte.GetChartFamily()) {
1636 pcell_node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cell");
1638 wxString path = GetDBChartFileName(dbIndex);
1639 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"path");
1640 pcell_node->AddChild(node);
1641 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", path);
1642 node->AddChild(tnode);
1644 wxFileName name(path);
1645 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"name");
1646 pcell_node->AddChild(node);
1647 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", name.GetName());
1648 node->AddChild(tnode);
1651 scale.Printf(
"%d", cte.GetScale());
1652 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cscale");
1653 pcell_node->AddChild(node);
1654 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"",
scale);
1655 node->AddChild(tnode);
1657 wxDateTime file_date(cte.GetFileTime());
1658 file_date.MakeUTC();
1659 wxString sfile_date = file_date.FormatISODate();
1661 sfile_date += file_date.FormatISOTime();
1663 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"local_file_datetime_iso8601");
1664 pcell_node->AddChild(node);
1665 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sfile_date);
1666 node->AddChild(tnode);
1669 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"edtn");
1670 pcell_node->AddChild(node);
1671 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetSE());
1672 node->AddChild(tnode);
1677 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"isdt");
1678 pcell_node->AddChild(node);
1679 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pcs57->GetISDT());
1680 node->AddChild(tnode);
1682 wxString LastUpdateDate;
1684 pcs57->ValidateAndCountUpdates(path,
"", LastUpdateDate,
false);
1687 supdn.Printf(
"%d", updn);
1688 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"updn");
1689 pcell_node->AddChild(node);
1690 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", supdn);
1691 node->AddChild(tnode);
1693 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"uadt");
1694 pcell_node->AddChild(node);
1695 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", LastUpdateDate);
1696 node->AddChild(tnode);
1700 if (pcell_node && b_getGeom) {
1701 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cov");
1702 pcell_node->AddChild(node);
1705 if (cte.GetnPlyEntries()) {
1706 wxXmlNode *panelnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"panel");
1707 node->AddChild(panelnode);
1710 panel_no.Printf(
"%d", 0);
1711 wxXmlNode *anode =
new wxXmlNode(wxXML_TEXT_NODE,
"", panel_no);
1712 panelnode->AddChild(anode);
1714 float *pf = cte.GetpPlyTable();
1715 for (
int j = 0; j < cte.GetnPlyEntries(); j++) {
1716 wxXmlNode *vnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"vertex");
1717 panelnode->AddChild(vnode);
1719 wxXmlNode *latnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lat");
1720 vnode->AddChild(latnode);
1724 sl.Printf(
"%.5f", l);
1725 wxXmlNode *vtnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sl);
1726 latnode->AddChild(vtnode);
1728 wxXmlNode *lonnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lon");
1729 vnode->AddChild(lonnode);
1733 sll.Printf(
"%.5f", ll);
1734 wxXmlNode *vtlnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sll);
1735 lonnode->AddChild(vtlnode);
1739 for (
int i = 0; i < cte.GetnAuxPlyEntries(); i++) {
1740 wxXmlNode *panelnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"panel");
1741 node->AddChild(panelnode);
1744 panel_no.Printf(
"%d", i + 1);
1745 wxXmlNode *anode =
new wxXmlNode(wxXML_TEXT_NODE,
"", panel_no);
1746 panelnode->AddChild(anode);
1748 float *pf = cte.GetpAuxPlyTableEntry(i);
1749 for (
int j = 0; j < cte.GetAuxCntTableEntry(i); j++) {
1750 wxXmlNode *vnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"vertex");
1751 panelnode->AddChild(vnode);
1753 wxXmlNode *latnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lat");
1754 vnode->AddChild(latnode);
1758 sl.Printf(
"%.5f", l);
1759 wxXmlNode *vtnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sl);
1760 latnode->AddChild(vtnode);
1762 wxXmlNode *lonnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lon");
1763 vnode->AddChild(lonnode);
1767 sll.Printf(
"%.5f", ll);
1768 wxXmlNode *vtlnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sll);
1769 lonnode->AddChild(vtlnode);
1774 doc.SetRoot(pcell_node);
1776 if (b_remove) DeleteCacheChart(pc);
1781bool ChartDB::CheckExclusiveTileGroup(
int canvasIndex) {
1789 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1791 switch (g_canvasConfig) {
1793 if (canvasIndex == 0) {
1794 cc = config_array.Item(0);
1795 if (cc) canvas = cc->
canvas;
1797 cc = config_array.Item(1);
1798 if (cc) canvas = cc->
canvas;
1803 cc = config_array.Item(0);
1804 if (cc) canvas = cc->
canvas;
1807 if (!canvas)
return false;
1810 if (canvas->m_groupIndex == m_checkGroupIndex[canvasIndex])
1811 return m_checkedTileOnly[canvasIndex];
1814 bool rv = IsNonMBTileInGroup(canvas->m_groupIndex);
1816 m_checkGroupIndex[canvasIndex] = canvas->m_groupIndex;
1817 m_checkedTileOnly[canvasIndex] = !rv;
1822bool ChartDB::CheckAnyCanvasExclusiveTileGroup() {
1830 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1832 switch (g_canvasConfig) {
1834 cc = config_array.Item(0);
1838 if (canvas->m_groupIndex == m_checkGroupIndex[0])
1839 rv |= m_checkedTileOnly[0];
1843 cc = config_array.Item(1);
1847 if (canvas->m_groupIndex == m_checkGroupIndex[1])
1848 rv |= m_checkedTileOnly[1];
1854 cc = config_array.Item(0);
1858 if (canvas->m_groupIndex == m_checkGroupIndex[0])
1859 rv |= m_checkedTileOnly[0];
1890bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y)
1906 for (i = 0, ppt = rgpts; i < wnumpts - 1; i++, ppt++) {
1909 if (Intersect(pt0, pt2, *ppt, *(ppt1))) wnumintsct++;
1913 if (Intersect(pt0, pt2, *ppt, *rgpts)) wnumintsct++;
1919 if (!(wnumintsct & 1)) {
1920 for (i = 0, ppt = rgpts; i < wnumpts; i++, ppt++) {
1921 if (((*ppt).x == x) && ((*ppt).y == y))
return true;
1942 return (((CCW(p1, p2, p3) * CCW(p1, p2, p4)) <= 0) &&
1943 ((CCW(p3, p4, p1) * CCW(p3, p4, p2) <= 0)));
1973 return ((dx1 * dy2 > dy1 * dx2) ? 1 : -1);
Chart canvas configuration state
std::vector< std::string > ChartDirectoryExcludedVector
Global instance.
ChartDB * ChartData
Global instance.
Charts database management
std::vector< std::string > ChartDirectoryExcludedVector
Global instance.
ChartDB * ChartData
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
Generic Chart canvas base.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
Manages the chart database and provides access to chart data.
bool LoadBinary(const wxString &filename, ArrayOfCDI &dir_array_check)
Load the chart database from a binary file.
Represents a KAP format chart, derived from ChartBaseBSB.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
Encapsulates persistent canvas configuration.
ChartCanvas * canvas
Pointer to associated chart canvas.
Represents a single CM93 chart at a specific scale.
Represents a composite CM93 chart covering multiple scales.
Represents an S57 format electronic navigational chart in OpenCPN.
Class cm93chart and helpers – CM93 chart state.
Config file user configuration interface.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
bool startswith(const std::string &str, const std::string &prefix)
Return true if s starts with given prefix.
Miscellaneous utilities, many of which string related.
Represents an entry in the chart table, containing information about a single chart.
ThumbWin * pthumbwin
Global instance.