31#include <wx/stopwatch.h>
33#include <wx/tokenzr.h>
48#include "androidUTIL.h"
58#include <wx/progdlg.h>
65extern ColorScheme GetColorScheme();
68extern s52plib *ps52plib;
74bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
80int ChartStack::GetCurrentEntrydbIndex() {
81 if (nEntry && (CurrentStackEntry >= 0) )
82 return DBIndex[CurrentStackEntry];
87void ChartStack::SetCurrentEntryFromdbIndex(
int current_db_index) {
88 for (
int i = 0; i < nEntry; i++) {
89 if (current_db_index == DBIndex[i]) CurrentStackEntry = i;
93int ChartStack::GetDBIndex(
int stack_index) {
94 if ((stack_index >= 0) && (stack_index < nEntry) && (stack_index < MAXSTACK))
95 return DBIndex[stack_index];
100void ChartStack::SetDBIndex(
int stack_index,
int db_index) {
101 if ((stack_index >= 0) && (stack_index < nEntry) && (stack_index < MAXSTACK))
102 DBIndex[stack_index] = db_index;
105bool ChartStack::DoesStackContaindbIndex(
int db_index) {
106 for (
int i = 0; i < nEntry; i++) {
107 if (db_index == DBIndex[i])
return true;
113void ChartStack::AddChart(
int db_add) {
118 int db_index = db_add;
125 SetDBIndex(j - 1, db_index);
135 for (
int id = 0;
id < j - 1;
id++) {
136 if (GetDBIndex(
id) != -1) {
139 for (
int jd =
id + 1; jd < j; jd++) {
140 if (GetDBIndex(jd) != -1) {
142 if (pm->GetFileTime() && pn->GetFileTime()) {
143 if (labs(pm->GetFileTime() - pn->GetFileTime()) <
145 if (pn->GetpFileName()->IsSameAs(*(pm->GetpFileName())))
156 if (GetDBIndex(
id) == -1) {
159 int db_index = GetDBIndex(jd);
160 SetDBIndex(jd - 1, db_index);
177 for (
int i = 0; i < j - 1; i++) {
180 ChartData->GetChartTableEntry(GetDBIndex(i + 1));
182 if (n.GetScale() < m.GetScale()) {
184 SetDBIndex(i, GetDBIndex(i + 1));
185 SetDBIndex(i + 1, ti);
197 pChartCache =
new wxArrayPtrVoid;
206 if (g_memCacheLimit) {
208 msg.Printf(
"ChartDB Cache policy: Application target is %d MBytes",
209 g_memCacheLimit / 1024);
213 msg.Printf(
"ChartDB Cache policy: Max open chart limit is %d.",
218 m_checkGroupIndex[0] = m_checkGroupIndex[1] = -1;
219 m_checkedTileOnly[0] = m_checkedTileOnly[1] =
false;
230 ArrayOfCDI &dir_array_check) {
231 m_dir_array = dir_array_check;
232 return ChartDatabase::Read(filename);
237void ChartDB::DeleteCacheEntry(
CacheEntry *pce,
bool bDelTexture,
238 const wxString &msg) {
241 if (msg != wxEmptyString) {
242 wxLogMessage(
"%s%s", msg.c_str(), ch->GetFullPath().c_str());
256 pChartCache->Remove(pce);
261void ChartDB::DeleteCacheEntry(
int i,
bool bDelTexture,
const wxString &msg) {
263 if (pce) DeleteCacheEntry(pce, bDelTexture, msg);
266void ChartDB::PurgeCache() {
270 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
271 unsigned int nCache = pChartCache->GetCount();
272 for (
unsigned int i = 0; i < nCache; i++) {
273 DeleteCacheEntry(0,
true);
275 pChartCache->Clear();
277 m_cache_mutex.Unlock();
281void ChartDB::PurgeCachePlugins() {
283 wxLogMessage(
"Chart cache PlugIn purge");
285 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
286 unsigned int nCache = pChartCache->GetCount();
292 if (CHART_TYPE_PLUGIN == Ch->GetChartType()) {
293 DeleteCacheEntry(pce,
true);
295 nCache = pChartCache->GetCount();
302 m_cache_mutex.Unlock();
306void ChartDB::ClearCacheInUseFlags() {
307 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
308 unsigned int nCache = pChartCache->GetCount();
309 for (
unsigned int i = 0; i < nCache; i++) {
311 pce->b_in_use =
false;
313 m_cache_mutex.Unlock();
320void ChartDB::PurgeCacheUnusedCharts(
double factor) {
322 if (g_memCacheLimit) {
323 if (wxMUTEX_NO_ERROR == m_cache_mutex.TryLock()) {
327 int mem_limit = g_memCacheLimit * factor;
329 int nl = pChartCache->GetCount();
331 wxString msg(
"Purging unused chart from cache: ");
333 while ((mem_used > mem_limit) && (nl > 0)) {
334 if (pChartCache->GetCount() < 2) {
339 CacheEntry *pce = FindOldestDeleteCandidate(
false);
342 DeleteCacheEntry(pce,
false , msg);
353 m_cache_mutex.Unlock();
357 else if (g_nCacheLimit) {
358 if (wxMUTEX_NO_ERROR == m_cache_mutex.TryLock()) {
360 double fac10 = factor * 10;
361 int chart_limit = g_nCacheLimit * fac10 / 10;
363 int nl = pChartCache->GetCount();
365 wxString msg(
"Purging unused chart from cache: ");
366 while ((nl > chart_limit) && (nl > 0)) {
367 if (pChartCache->GetCount() < 2) {
372 CacheEntry *pce = FindOldestDeleteCandidate(
false);
375 DeleteCacheEntry(pce,
false , msg);
380 nl = pChartCache->GetCount();
383 m_cache_mutex.Unlock();
392ChartBase *ChartDB::GetChart(
const wxChar *theFilePath,
394 wxFileName fn(theFilePath);
396 if (!fn.FileExists()) {
398 if (!wxDir::Exists(theFilePath)) {
399 wxLogMessage(
" ...file does not exist: %s", theFilePath);
405 wxString chartExt = fn.GetExt().Upper();
407 if (chartExt ==
"XZ") {
408 wxString npath = theFilePath;
409 npath = npath.Left(npath.length() - 3);
410 wxFileName fn(npath);
411 chartExt = fn.GetExt().Upper();
414 if (chartExt ==
"KAP") {
416 }
else if (chartExt ==
"GEO") {
418 }
else if (chartExt ==
"MBTILES") {
420 }
else if (chartExt ==
"000" || chartExt ==
"S57") {
423 }
else if (chart_desc.m_descriptor_type == PLUGIN_DESCRIPTOR) {
430 wxRegEx rxName(
"[0-9]+");
431 wxRegEx rxExt(
"[A-G]");
432 if (rxName.Matches(fn.GetName()) && rxExt.Matches(chartExt))
443bool ChartDB::IsChartDirectoryExcluded(
const std::string &chart_file) {
453int ChartDB::BuildChartStack(
ChartStack *cstk,
float lat,
float lon,
int db_add,
455 BuildChartStack(cstk, lat, lon, groupIndex);
457 if (db_add >= 0) cstk->AddChart(db_add);
462int ChartDB::BuildChartStack(
ChartStack *cstk,
float lat,
float lon,
467 if (!IsValid())
return 0;
471 int nEntry = GetChartTableEntries();
473 for (
int db_index = 0; db_index < nEntry; db_index++) {
477 if (IsChartDirectoryExcluded(cte.GetFullPath()))
continue;
480 bool b_group_add =
false;
481 if (groupIndex > 0) {
482 const int ng = cte.GetGroupArray().size();
483 for (
int ig = 0; ig < ng; ig++) {
484 if (groupIndex == cte.GetGroupArray()[ig]) {
492 bool b_writable_add =
true;
496 wxFileName fn(cte.GetFullSystemPath());
497 if (!androidIsDirWritable(fn.GetPath())) b_writable_add =
false;
500 bool b_pos_add =
false;
501 if (b_group_add && b_writable_add) {
505 if (cte.GetChartType() == CHART_TYPE_PLUGIN) {
510 if (CheckPositionWithinChart(db_index, lat, lon) && (j < MAXSTACK))
514 else if ((cte.GetLonMax() > 180.) && (cte.GetLonMin() < 180.)) {
515 if (CheckPositionWithinChart(db_index, lat, lon + 360.) &&
520 else if ((cte.GetLonMax() > 180.) && (cte.GetLonMin() > 180.)) {
521 if (CheckPositionWithinChart(db_index, lat, lon + 360.) &&
527 bool b_available =
true;
529 if (b_group_add && b_pos_add && (cte.GetChartType() == CHART_TYPE_PLUGIN)) {
531 if (!IsChartAvailable(db_index)) {
532 pcte->SetAvailable(
false);
535 pcte->SetAvailable(
true);
540 if (b_group_add && b_pos_add && b_available) {
543 cstk->SetDBIndex(j - 1, db_index);
559 for (
int id = 0;
id < j - 1;
id++) {
560 if (cstk->GetDBIndex(
id) != -1) {
561 const ChartTableEntry &ctem = GetChartTableEntry(cstk->GetDBIndex(
id));
563 for (
int jd =
id + 1; jd < j; jd++) {
564 if (cstk->GetDBIndex(jd) != -1) {
566 GetChartTableEntry(cstk->GetDBIndex(jd));
567 bool bsameTime =
false;
568 if (ctem.GetFileTime() && cten.GetFileTime()) {
569 if (labs(ctem.GetFileTime() - cten.GetFileTime()) < 60)
572 if (ctem.GetChartEditionDate() == cten.GetChartEditionDate())
576 if (cten.GetpFileName()->IsSameAs(*(ctem.GetpFileName())))
577 cstk->SetDBIndex(jd, -1);
586 if (cstk->GetDBIndex(
id) == -1) {
589 int db_index = cstk->GetDBIndex(jd);
590 cstk->SetDBIndex(jd - 1, db_index);
607 for (i = 0; i < j - 1; i++) {
609 const ChartTableEntry &n = GetChartTableEntry(cstk->GetDBIndex(i + 1));
611 if (n.GetScale() < m.GetScale()) {
612 ti = cstk->GetDBIndex(i);
613 cstk->SetDBIndex(i, cstk->GetDBIndex(i + 1));
614 cstk->SetDBIndex(i + 1, ti);
620 cstk->b_valid =
true;
625bool ChartDB::IsChartInGroup(
const int db_index,
const int group) {
629 bool b_in_group =
false;
631 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
632 if (group == pt->GetGroupArray()[ig]) {
643bool ChartDB::IsENCInGroup(
const int groupIndex) {
647 for (
int db_index = 0; db_index < GetChartTableEntries(); db_index++) {
651 bool b_group_add =
false;
652 if (groupIndex > 0) {
653 const int ng = cte.GetGroupArray().size();
654 for (
int ig = 0; ig < ng; ig++) {
655 if (groupIndex == cte.GetGroupArray()[ig]) {
664 if (cte.GetChartFamily() == CHART_FAMILY_VECTOR) {
674bool ChartDB::IsNonMBTileInGroup(
const int groupIndex) {
679 for (
int db_index = 0; db_index < GetChartTableEntries(); db_index++) {
683 bool b_group_add =
false;
684 if (groupIndex > 0) {
685 const int ng = cte.GetGroupArray().size();
686 for (
int ig = 0; ig < ng; ig++) {
687 if (groupIndex == cte.GetGroupArray()[ig]) {
696 if (cte.GetChartType() != CHART_TYPE_MBTILES) {
709bool ChartDB::CheckPositionWithinChart(
int index,
float lat,
float lon) {
714 if ((lat <= pt->GetLatMax()) && (lat >= pt->GetLatMin()) &&
715 (lon >= pt->GetLonMin()) && (lon <= pt->GetLonMax())) {
718 bool bInside = G_FloatPtInPolygon((
MyFlPoint *)pt->GetpPlyTable(),
719 pt->GetnPlyEntries(), lon, lat);
722 if (pt->GetnAuxPlyEntries()) {
723 for (
int k = 0; k < pt->GetnAuxPlyEntries(); k++) {
725 G_FloatPtInPolygon((
MyFlPoint *)pt->GetpAuxPlyTableEntry(k),
726 pt->GetAuxCntTableEntry(k), lon, lat);
727 if (bAuxInside)
return true;
743 if ((pa == 0) || (pb == 0))
return false;
744 if ((!pa->b_valid) || (!pb->b_valid))
return false;
745 if (pa->nEntry != pb->nEntry)
return false;
747 for (
int i = 0; i < pa->nEntry; i++) {
748 if (pa->GetDBIndex(i) != pb->GetDBIndex(i))
return false;
758 if ((pa == 0) || (pb == 0))
return false;
759 pa->nEntry = pb->nEntry;
761 for (
int i = 0; i < pa->nEntry; i++) pa->SetDBIndex(i, pb->GetDBIndex(i));
763 pa->CurrentStackEntry = pb->CurrentStackEntry;
765 pa->b_valid = pb->b_valid;
770wxString ChartDB::GetFullPath(
ChartStack *ps,
int stackindex) {
771 int dbIndex = ps->GetDBIndex(stackindex);
772 return GetChartTableEntry(dbIndex).GetFullSystemPath();
779int ChartDB::GetCSPlyPoint(
ChartStack *ps,
int stackindex,
int plyindex,
780 float *lat,
float *lon) {
781 int dbIndex = ps->GetDBIndex(stackindex);
782 wxASSERT(dbIndex >= 0);
785 if (entry.GetnPlyEntries()) {
786 float *fp = entry.GetpPlyTable();
793 return entry.GetnPlyEntries();
799int ChartDB::GetStackChartScale(
ChartStack *ps,
int stackindex,
char *buf,
801 int dbindex = ps->GetDBIndex(stackindex);
802 wxASSERT(dbindex >= 0);
805 int sc = entry.GetScale();
806 if (buf) sprintf(buf,
"%d", sc);
814int ChartDB::GetStackEntry(
ChartStack *ps, wxString fp) {
815 for (
int i = 0; i < ps->nEntry; i++) {
817 if (fp.IsSameAs(entry.GetFullSystemPath()))
return i;
826ChartTypeEnum ChartDB::GetCSChartType(
ChartStack *ps,
int stackindex) {
828 int dbindex = ps->GetDBIndex(stackindex);
830 return (ChartTypeEnum)GetChartTableEntry(dbindex).GetChartType();
832 return CHART_TYPE_UNKNOWN;
835ChartFamilyEnum ChartDB::GetCSChartFamily(
ChartStack *ps,
int stackindex) {
837 int dbindex = ps->GetDBIndex(stackindex);
841 ChartTypeEnum type = (ChartTypeEnum)entry.GetChartType();
844 return CHART_FAMILY_RASTER;
846 return CHART_FAMILY_RASTER;
848 return CHART_FAMILY_VECTOR;
849 case CHART_TYPE_CM93:
850 return CHART_FAMILY_VECTOR;
851 case CHART_TYPE_CM93COMP:
852 return CHART_FAMILY_VECTOR;
853 case CHART_TYPE_DUMMY:
854 return CHART_FAMILY_RASTER;
856 return CHART_FAMILY_UNKNOWN;
860 return CHART_FAMILY_UNKNOWN;
863std::vector<int> ChartDB::GetCSArray(
ChartStack *ps) {
864 std::vector<int> ret;
867 ret.reserve(ps->nEntry);
868 for (
int i = 0; i < ps->nEntry; i++) {
869 ret.push_back(ps->GetDBIndex(i));
876bool ChartDB::IsChartInCache(
int dbindex) {
877 bool bInCache =
false;
880 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
881 unsigned int nCache = pChartCache->GetCount();
882 for (
unsigned int i = 0; i < nCache; i++) {
884 if (pce->dbIndex == dbindex) {
885 if (pce->pChart != 0 && ((
ChartBase *)pce->pChart)->IsReadyToRender())
890 m_cache_mutex.Unlock();
896bool ChartDB::IsChartInCache(wxString path) {
897 bool bInCache =
false;
898 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
900 unsigned int nCache = pChartCache->GetCount();
901 for (
unsigned int i = 0; i < nCache; i++) {
903 if (pce->FullPath == path) {
904 if (pce->pChart != 0 && ((
ChartBase *)pce->pChart)->IsReadyToRender())
910 m_cache_mutex.Unlock();
915bool ChartDB::IsChartLocked(
int index) {
916 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
917 unsigned int nCache = pChartCache->GetCount();
918 for (
unsigned int i = 0; i < nCache; i++) {
920 if (pce->dbIndex == index) {
921 bool ret = pce->n_lock > 0;
922 m_cache_mutex.Unlock();
926 m_cache_mutex.Unlock();
932bool ChartDB::LockCacheChart(
int index) {
935 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
936 unsigned int nCache = pChartCache->GetCount();
937 for (
unsigned int i = 0; i < nCache; i++) {
939 if (pce->dbIndex == index) {
945 m_cache_mutex.Unlock();
950void ChartDB::UnLockCacheChart(
int index) {
952 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
953 unsigned int nCache = pChartCache->GetCount();
954 for (
unsigned int i = 0; i < nCache; i++) {
956 if (pce->dbIndex == index) {
957 if (pce->n_lock > 0) pce->n_lock--;
961 m_cache_mutex.Unlock();
965void ChartDB::UnLockAllCacheCharts() {
967 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
968 unsigned int nCache = pChartCache->GetCount();
969 for (
unsigned int i = 0; i < nCache; i++) {
971 if (pce->n_lock > 0) pce->n_lock--;
973 m_cache_mutex.Unlock();
980ChartBase *ChartDB::OpenChartFromDB(
int index, ChartInitFlag init_flag) {
981 return OpenChartUsingCache(index, init_flag);
984ChartBase *ChartDB::OpenChartFromDB(wxString chart_path,
985 ChartInitFlag init_flag) {
986 int dbii = FinddbIndex(chart_path);
987 return OpenChartUsingCache(dbii, init_flag);
991 ChartInitFlag init_flag) {
992 return OpenChartUsingCache(pStack->GetDBIndex(StackEntry), init_flag);
995ChartBase *ChartDB::OpenChartFromDBAndLock(
int index, ChartInitFlag init_flag,
997 wxCriticalSectionLocker locker(m_critSect);
998 ChartBase *pret = OpenChartUsingCache(index, init_flag);
999 if (lock && pret) LockCacheChart(index);
1003ChartBase *ChartDB::OpenChartFromDBAndLock(wxString chart_path,
1004 ChartInitFlag init_flag) {
1005 int dbii = FinddbIndex(chart_path);
1006 return OpenChartFromDBAndLock(dbii, init_flag);
1009CacheEntry *ChartDB::FindOldestDeleteCandidate(
bool blog) {
1012 unsigned int nCache = pChartCache->GetCount();
1014 if (blog) wxLogMessage(
"Searching chart cache for oldest entry");
1015 int LRUTime = m_ticks;
1017 for (
unsigned int i = 0; i < nCache; i++) {
1019 if (pce->RecentTime < LRUTime && !pce->n_lock) {
1020 if (!isSingleChart((
ChartBase *)(pce->pChart))) {
1021 LRUTime = pce->RecentTime;
1026 int dt = m_ticks - LRUTime;
1031 if (!pce->n_lock && !isSingleChart(pDeleteCandidate)) {
1033 wxLogMessage(
"Oldest unlocked cache index is %d, delta t is %d",
1038 wxLogMessage(
"All chart in cache locked, size: %d", nCache);
1044ChartBase *ChartDB::OpenChartUsingCache(
int dbindex, ChartInitFlag init_flag) {
1045 if ((dbindex < 0) || (dbindex > GetChartTableEntries() - 1))
return NULL;
1050 wxString ChartFullPath = cte.GetFullSystemPath();
1051 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1052 ChartFamilyEnum chart_family = (ChartFamilyEnum)cte.GetChartFamily();
1055 msg1.Printf(
"OpenChartUsingCache: type %d ", chart_type);
1058 if (cte.GetLatMax() > 90.0)
1065 bool bInCache =
false;
1069 wxMutexLocker lock(m_cache_mutex);
1071 unsigned int nCache = pChartCache->GetCount();
1073 for (
unsigned int i = 0; i < nCache; i++) {
1075 if (pce->FullPath == ChartFullPath) {
1084 msg.Printf(
"OpenChartUsingCache, IN cache: cache size: %d\n",
1085 (
int)pChartCache->GetCount());
1087 if (FULL_INIT == init_flag)
1089 if (Ch->IsReadyToRender()) {
1091 pce->RecentTime = m_ticks;
1092 pce->b_in_use =
true;
1099 old_lock = pce->n_lock;
1100 pChartCache->Remove(pce);
1108 pce->RecentTime = m_ticks;
1109 pce->b_in_use =
true;
1120 if (g_memCacheLimit) {
1126 msg.Printf(
"OpenChartUsingCache, NOT in cache: cache size: %d\n",
1127 (
int)pChartCache->GetCount());
1130 msg1.Printf(
" OpenChartUsingCache: type %d ", chart_type);
1131 wxLogMessage(msg1 + ChartFullPath);
1133 if ((mem_used > g_memCacheLimit * 8 / 10) &&
1134 (pChartCache->GetCount() > 2)) {
1135 wxString msg(
"Removing oldest chart from cache: ");
1137 CacheEntry *pce = FindOldestDeleteCandidate(
true);
1138 if (pce == 0)
break;
1141 DeleteCacheEntry(pce,
true, msg);
1144 if ((mem_used < g_memCacheLimit * 8 / 10) ||
1145 (pChartCache->GetCount() <= 2))
1156 unsigned int nCache = pChartCache->GetCount();
1157 if (nCache > (
unsigned int)g_nCacheLimit && nCache > 2) {
1158 wxString msg(
"Removing oldest chart from cache: ");
1159 while (nCache > (
unsigned int)g_nCacheLimit) {
1160 CacheEntry *pce = FindOldestDeleteCandidate(
true);
1161 if (pce == 0)
break;
1163 DeleteCacheEntry(pce,
true, msg);
1174 wxLogMessage(
"Creating new chart");
1176 if (chart_type == CHART_TYPE_KAP)
1179 else if (chart_type == CHART_TYPE_GEO)
1182 else if (chart_type == CHART_TYPE_MBTILES)
1185 else if (chart_type == CHART_TYPE_S57) {
1190 Chs57->SetNativeScale(cte.GetScale());
1195 ext.NLAT = cte.GetLatMax();
1196 ext.SLAT = cte.GetLatMin();
1197 ext.WLON = cte.GetLonMin();
1198 ext.ELON = cte.GetLonMax();
1199 Chs57->SetFullExtent(ext);
1202 else if (chart_type == CHART_TYPE_CM93) {
1207 Chcm93->SetNativeScale(cte.GetScale());
1212 ext.NLAT = cte.GetLatMax();
1213 ext.SLAT = cte.GetLatMin();
1214 ext.WLON = cte.GetLonMin();
1215 ext.ELON = cte.GetLonMax();
1216 Chcm93->SetFullExtent(ext);
1219 else if (chart_type == CHART_TYPE_CM93COMP) {
1225 Chcm93->SetNativeScale(cte.GetScale());
1230 ext.NLAT = cte.GetLatMax();
1231 ext.SLAT = cte.GetLatMin();
1232 ext.WLON = cte.GetLonMin();
1233 ext.ELON = cte.GetLonMax();
1234 Chcm93->SetFullExtent(ext);
1237 else if (chart_type == CHART_TYPE_PLUGIN) {
1238 wxFileName fn(ChartFullPath);
1239 wxString ext = fn.GetExt();
1241 wxString ext_upper = ext.MakeUpper();
1242 wxString ext_lower = ext.MakeLower();
1243 wxString chart_class_name;
1248 for (
auto &cd : m_ChartClassDescriptorArray) {
1249 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
1250 if (cd.m_search_mask == ext_upper) {
1251 chart_class_name = cd.m_class_name;
1254 if (cd.m_search_mask == ext_lower) {
1255 chart_class_name = cd.m_class_name;
1258 if (ChartFullPath.Matches(cd.m_search_mask)) {
1259 chart_class_name = cd.m_class_name;
1266 if (chart_class_name.Len()) {
1269 if (chart_family == CHART_FAMILY_VECTOR) LoadS57();
1275 wxLogMessage(
"Unknown chart type");
1281 s52plib *plib = ps52plib;
1282 wxString msg_fn(ChartFullPath);
1283 msg_fn.Replace(
"%",
"%%");
1286 if ((chart_family != CHART_FAMILY_VECTOR) ||
1287 ((chart_family == CHART_FAMILY_VECTOR) && plib)) {
1288 wxLogMessage(wxString::Format(
"Initializing Chart %s", msg_fn.c_str()));
1290 ir = Ch->Init(ChartFullPath, init_flag);
1291 Ch->SetColorScheme( GetColorScheme());
1293 wxLogMessage(wxString::Format(
" No PLIB, Skipping vector chart %s",
1296 ir = INIT_FAIL_REMOVE;
1299 if (INIT_OK == ir) {
1305 pce->FullPath = ChartFullPath;
1307 pce->dbIndex = dbindex;
1310 pce->RecentTime = m_ticks;
1311 pce->n_lock = old_lock;
1313 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1314 pChartCache->Add((
void *)pce);
1315 m_cache_mutex.Unlock();
1330 if (chart_type == CHART_TYPE_MBTILES) {
1331 wxFileName tileFile(ChartFullPath);
1333 wxULongLong tileSizeMB = tileFile.GetSize() >> 20;
1335 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1337 if (!CheckAnyCanvasExclusiveTileGroup() ||
1338 (tileSizeMB.GetLo() > 5000)) {
1341 bool b_clicked =
false;
1345 switch (g_canvasConfig) {
1347 cc = config_array.Item(0);
1351 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1353 cc = config_array.Item(1);
1357 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1361 cc = config_array.Item(0);
1365 b_clicked |= canvas->IsTileOverlayIndexInYesShow(dbindex);
1372 switch (g_canvasConfig) {
1374 cc = config_array.Item(0);
1377 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1379 cc = config_array.Item(1);
1382 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1386 cc = config_array.Item(0);
1389 if (canvas) canvas->AddTileOverlayIndexToNoShow(dbindex);
1396 }
else if (INIT_FAIL_REMOVE == ir)
1399 wxString::Format(
"Problem initializing Chart %s", msg_fn.c_str()));
1406 DisableChart(ChartFullPath);
1407 }
else if ((INIT_FAIL_RETRY == ir) ||
1408 (INIT_FAIL_NOERROR ==
1411 wxLogMessage(wxString::Format(
1412 "Recoverable problem initializing Chart %s", msg_fn.c_str()));
1417 if (INIT_OK != ir) {
1420 wxString::Format(
" OpenChartFromStack... Error opening "
1421 "chart %s ... return code %d",
1422 msg_fn.c_str(), ir));
1436bool ChartDB::DeleteCacheChart(
ChartBase *pDeleteCandidate) {
1437 bool retval =
false;
1439 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1440 if (!isSingleChart(pDeleteCandidate)) {
1443 for (
unsigned int i = 0; i < pChartCache->GetCount(); i++) {
1445 if ((
ChartBase *)(pce->pChart) == pDeleteCandidate) {
1451 if (pce->n_lock > 0) pce->n_lock--;
1453 if (pce->n_lock == 0) {
1454 DeleteCacheEntry(pce);
1459 m_cache_mutex.Unlock();
1467void ChartDB::ApplyColorSchemeToCachedCharts(ColorScheme cs) {
1472 if (wxMUTEX_NO_ERROR == m_cache_mutex.Lock()) {
1473 unsigned int nCache = pChartCache->GetCount();
1474 for (
unsigned int i = 0; i < nCache; i++) {
1477 if (Ch) Ch->SetColorScheme(cs,
true);
1480 m_cache_mutex.Unlock();
1490ChartBase *ChartDB::OpenStackChartConditional(
1491 ChartStack *ps,
int index_start,
bool bSearchDir, ChartTypeEnum New_Type,
1492 ChartFamilyEnum New_Family_Fallback) {
1498 if (bSearchDir == 1)
1504 index = index_start;
1506 while ((index >= 0) && (index < ps->nEntry)) {
1507 ChartTypeEnum chart_type = (ChartTypeEnum)GetCSChartType(ps, index);
1508 if ((chart_type == New_Type) || (New_Type == CHART_TYPE_DONTCARE)) {
1509 ptc = OpenChartFromStack(ps, index);
1510 if (NULL != ptc)
break;
1512 index += delta_index;
1518 index = index_start;
1520 while ((index >= 0) && (index < ps->nEntry)) {
1521 ChartFamilyEnum chart_family = GetCSChartFamily(ps, index);
1522 if (chart_family == New_Family_Fallback) {
1523 ptc = OpenChartFromStack(ps, index);
1525 if (NULL != ptc)
break;
1527 index += delta_index;
1534wxXmlDocument ChartDB::GetXMLDescription(
int dbIndex,
bool b_getGeom) {
1536 if (!IsValid() || (dbIndex >= GetChartTableEntries()))
return doc;
1538 bool b_remove = !IsChartInCache(dbIndex);
1540 wxXmlNode *pcell_node = NULL;
1545 ChartBase *pc = OpenChartFromDB(dbIndex, HEADER_ONLY);
1546 b_remove = !IsChartInCache(dbIndex);
1549 if (CHART_FAMILY_RASTER == (ChartFamilyEnum)cte.GetChartFamily()) {
1550 pcell_node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"chart");
1552 wxString path = GetDBChartFileName(dbIndex);
1553 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"path");
1554 pcell_node->AddChild(node);
1555 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", path);
1556 node->AddChild(tnode);
1558 wxFileName name(path);
1559 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"name");
1560 pcell_node->AddChild(node);
1561 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", name.GetName());
1562 node->AddChild(tnode);
1565 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lname");
1566 pcell_node->AddChild(node);
1567 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetName());
1568 node->AddChild(tnode);
1572 scale.Printf(
"%d", cte.GetScale());
1573 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cscale");
1574 pcell_node->AddChild(node);
1575 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"",
scale);
1576 node->AddChild(tnode);
1578 wxDateTime file_date(cte.GetFileTime());
1579 file_date.MakeUTC();
1580 wxString sfile_date = file_date.FormatISODate();
1582 sfile_date += file_date.FormatISOTime();
1584 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"local_file_datetime_iso8601");
1585 pcell_node->AddChild(node);
1586 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sfile_date);
1587 node->AddChild(tnode);
1590 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"source_edition");
1591 pcell_node->AddChild(node);
1592 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetSE());
1593 node->AddChild(tnode);
1595 wxDateTime sdt = pc->GetEditionDate();
1596 wxString ssdt =
"Unknown";
1597 if (sdt.IsValid()) ssdt = sdt.Format(
"%Y%m%d");
1599 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"source_date");
1600 pcell_node->AddChild(node);
1601 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", ssdt);
1602 node->AddChild(tnode);
1608 if (s == "raster_edition")
1609 if (s == "ntm_edition")
1611 if (s == "ntm_date")
1612 if (s == "source_edition_last_correction")
1613 if (s == "raster_edition_last_correction")
1614 if (s == "ntm_edition_last_correction")
1618 else if (CHART_FAMILY_VECTOR == (ChartFamilyEnum)cte.GetChartFamily()) {
1619 pcell_node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cell");
1621 wxString path = GetDBChartFileName(dbIndex);
1622 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"path");
1623 pcell_node->AddChild(node);
1624 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", path);
1625 node->AddChild(tnode);
1627 wxFileName name(path);
1628 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"name");
1629 pcell_node->AddChild(node);
1630 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", name.GetName());
1631 node->AddChild(tnode);
1634 scale.Printf(
"%d", cte.GetScale());
1635 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cscale");
1636 pcell_node->AddChild(node);
1637 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"",
scale);
1638 node->AddChild(tnode);
1640 wxDateTime file_date(cte.GetFileTime());
1641 file_date.MakeUTC();
1642 wxString sfile_date = file_date.FormatISODate();
1644 sfile_date += file_date.FormatISOTime();
1646 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"local_file_datetime_iso8601");
1647 pcell_node->AddChild(node);
1648 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sfile_date);
1649 node->AddChild(tnode);
1652 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"edtn");
1653 pcell_node->AddChild(node);
1654 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pc->GetSE());
1655 node->AddChild(tnode);
1660 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"isdt");
1661 pcell_node->AddChild(node);
1662 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", pcs57->GetISDT());
1663 node->AddChild(tnode);
1665 wxString LastUpdateDate;
1667 pcs57->ValidateAndCountUpdates(path,
"", LastUpdateDate,
false);
1670 supdn.Printf(
"%d", updn);
1671 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"updn");
1672 pcell_node->AddChild(node);
1673 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", supdn);
1674 node->AddChild(tnode);
1676 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"uadt");
1677 pcell_node->AddChild(node);
1678 tnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", LastUpdateDate);
1679 node->AddChild(tnode);
1683 if (pcell_node && b_getGeom) {
1684 node =
new wxXmlNode(wxXML_ELEMENT_NODE,
"cov");
1685 pcell_node->AddChild(node);
1688 if (cte.GetnPlyEntries()) {
1689 wxXmlNode *panelnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"panel");
1690 node->AddChild(panelnode);
1693 panel_no.Printf(
"%d", 0);
1694 wxXmlNode *anode =
new wxXmlNode(wxXML_TEXT_NODE,
"", panel_no);
1695 panelnode->AddChild(anode);
1697 float *pf = cte.GetpPlyTable();
1698 for (
int j = 0; j < cte.GetnPlyEntries(); j++) {
1699 wxXmlNode *vnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"vertex");
1700 panelnode->AddChild(vnode);
1702 wxXmlNode *latnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lat");
1703 vnode->AddChild(latnode);
1707 sl.Printf(
"%.5f", l);
1708 wxXmlNode *vtnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sl);
1709 latnode->AddChild(vtnode);
1711 wxXmlNode *lonnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lon");
1712 vnode->AddChild(lonnode);
1716 sll.Printf(
"%.5f", ll);
1717 wxXmlNode *vtlnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sll);
1718 lonnode->AddChild(vtlnode);
1722 for (
int i = 0; i < cte.GetnAuxPlyEntries(); i++) {
1723 wxXmlNode *panelnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"panel");
1724 node->AddChild(panelnode);
1727 panel_no.Printf(
"%d", i + 1);
1728 wxXmlNode *anode =
new wxXmlNode(wxXML_TEXT_NODE,
"", panel_no);
1729 panelnode->AddChild(anode);
1731 float *pf = cte.GetpAuxPlyTableEntry(i);
1732 for (
int j = 0; j < cte.GetAuxCntTableEntry(i); j++) {
1733 wxXmlNode *vnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"vertex");
1734 panelnode->AddChild(vnode);
1736 wxXmlNode *latnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lat");
1737 vnode->AddChild(latnode);
1741 sl.Printf(
"%.5f", l);
1742 wxXmlNode *vtnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sl);
1743 latnode->AddChild(vtnode);
1745 wxXmlNode *lonnode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"lon");
1746 vnode->AddChild(lonnode);
1750 sll.Printf(
"%.5f", ll);
1751 wxXmlNode *vtlnode =
new wxXmlNode(wxXML_TEXT_NODE,
"", sll);
1752 lonnode->AddChild(vtlnode);
1757 doc.SetRoot(pcell_node);
1759 if (b_remove) DeleteCacheChart(pc);
1764bool ChartDB::CheckExclusiveTileGroup(
int canvasIndex) {
1772 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1774 switch (g_canvasConfig) {
1776 if (canvasIndex == 0) {
1777 cc = config_array.Item(0);
1778 if (cc) canvas = cc->
canvas;
1780 cc = config_array.Item(1);
1781 if (cc) canvas = cc->
canvas;
1786 cc = config_array.Item(0);
1787 if (cc) canvas = cc->
canvas;
1790 if (!canvas)
return false;
1793 if (canvas->m_groupIndex == m_checkGroupIndex[canvasIndex])
1794 return m_checkedTileOnly[canvasIndex];
1797 bool rv = IsNonMBTileInGroup(canvas->m_groupIndex);
1799 m_checkGroupIndex[canvasIndex] = canvas->m_groupIndex;
1800 m_checkedTileOnly[canvasIndex] = !rv;
1805bool ChartDB::CheckAnyCanvasExclusiveTileGroup() {
1813 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1815 switch (g_canvasConfig) {
1817 cc = config_array.Item(0);
1821 if (canvas->m_groupIndex == m_checkGroupIndex[0])
1822 rv |= m_checkedTileOnly[0];
1826 cc = config_array.Item(1);
1830 if (canvas->m_groupIndex == m_checkGroupIndex[1])
1831 rv |= m_checkedTileOnly[1];
1837 cc = config_array.Item(0);
1841 if (canvas->m_groupIndex == m_checkGroupIndex[0])
1842 rv |= m_checkedTileOnly[0];
1873bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y)
1889 for (i = 0, ppt = rgpts; i < wnumpts - 1; i++, ppt++) {
1892 if (Intersect(pt0, pt2, *ppt, *(ppt1))) wnumintsct++;
1896 if (Intersect(pt0, pt2, *ppt, *rgpts)) wnumintsct++;
1902 if (!(wnumintsct & 1)) {
1903 for (i = 0, ppt = rgpts; i < wnumpts; i++, ppt++) {
1904 if (((*ppt).x == x) && ((*ppt).y == y))
return true;
1925 return (((CCW(p1, p2, p3) * CCW(p1, p2, p4)) <= 0) &&
1926 ((CCW(p3, p4, p1) * CCW(p3, p4, p2) <= 0)));
1956 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.
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.
Represents an entry in the chart table, containing information about a single chart.
ThumbWin * pthumbwin
Global instance.