33#include <wx/arrimpl.cpp>
35#include <wx/encconv.h>
36#include <wx/progdlg.h>
38#include <wx/tokenzr.h>
45#include "LOD_reduce.h"
53#define UINT32 unsigned int
57#include "androidUTIL.h"
62static int s_dbVersion;
68static ChartFamilyEnum GetChartFamily(
int charttype) {
73 cf = CHART_FAMILY_RASTER;
76 cf = CHART_FAMILY_RASTER;
79 cf = CHART_FAMILY_VECTOR;
82 cf = CHART_FAMILY_VECTOR;
84 case CHART_TYPE_CM93COMP:
85 cf = CHART_FAMILY_VECTOR;
87 case CHART_TYPE_DUMMY:
88 cf = CHART_FAMILY_RASTER;
90 case CHART_TYPE_UNKNOWN:
91 cf = CHART_FAMILY_UNKNOWN;
94 cf = CHART_FAMILY_UNKNOWN;
104void ChartTableHeader::Read(wxInputStream &is) {
108void ChartTableHeader::Write(wxOutputStream &os) {
110 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
112 memcpy(dbVersion, vb, 4);
116bool ChartTableHeader::CheckValid() {
118 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
119 if (strncmp(vb, dbVersion,
sizeof(dbVersion))) {
122 memcpy(vbo, dbVersion, 4);
124 msg.Append(wxString(vbo, wxConvUTF8));
125 msg.Prepend(
" Warning: found incorrect chart db version: ");
131 sprintf(vb,
"V%03d", DB_VERSION_PREVIOUS);
132 if (strncmp(vb, dbVersion,
sizeof(dbVersion)))
136 " Scheduling db upgrade to current db version on "
137 "Options->Charts page visit...");
144 memcpy(vbo, dbVersion, 4);
146 msg.Append(wxString(vbo, wxConvUTF8));
147 msg.Prepend(
"Loading chart db version: ");
158void ChartTableEntry::SetScale(
int scale) {
162 if (Scale >= 1000) rounding = 5 * pow(10, log10(Scale) - 2);
165ChartTableEntry::ChartTableEntry(
ChartBase &theChart, wxString &utf8Path) {
168 char *pt = (
char *)malloc(strlen(utf8Path.mb_str(wxConvUTF8)) + 1);
169 strcpy(pt, utf8Path.mb_str(wxConvUTF8));
172 SetScale(theChart.GetNativeScale());
174 ChartType = theChart.GetChartType();
175 ChartFamily = theChart.GetChartFamily();
177 Skew = theChart.GetChartSkew();
178 ProjectionType = theChart.GetChartProjectionType();
180 wxDateTime ed = theChart.GetEditionDate();
181 if (theChart.GetEditionDate().IsValid())
182 edition_date = theChart.GetEditionDate().GetTicks();
184 wxFileName fn(theChart.GetFullPath());
185 if (fn.GetModificationTime().IsValid())
186 file_date = fn.GetModificationTime().GetTicks();
188 m_pfilename =
new wxString;
189 *m_pfilename = fn.GetFullName();
190 m_psFullPath =
new wxString;
191 *m_psFullPath = utf8Path;
192 m_fullSystemPath = utf8Path;
193 m_FullPath = std::string(pFullPath);
196 m_fullSystemPath = wxString(utf8Path.mb_str(wxConvUTF8));
200 theChart.GetChartExtent(&ext);
206 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
211 double scale_max_zoom = Scale / 4;
213 double display_ppm = 1 / .00025;
214 double meters_per_pixel_max_scale = scale_max_zoom / display_ppm;
215 double LOD_meters = meters_per_pixel_max_scale * LOD_pixels;
220 if (theChart.GetCOVREntries() == 1) {
221 nPlyEntries = theChart.GetCOVRTablePoints(0);
223 if (nPlyEntries > 5 && (LOD_meters > .01)) {
224 std::vector<int> index_keep{0, nPlyEntries - 1, 1, nPlyEntries - 2};
226 double *DPbuffer = (
double *)malloc(2 * nPlyEntries *
sizeof(
double));
228 double *pfed = DPbuffer;
231 for (
int i = 0; i < nPlyEntries; i++) {
237 DouglasPeucker(DPbuffer, 1, nPlyEntries - 2, LOD_meters / (1852 * 60),
243 for (
unsigned int i = 0; i < index_keep.size(); i++) {
244 DPbuffer[2 * index_keep[i]] += 2000.;
247 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
250 for (
int i = 0; i < nPlyEntries; i++) {
251 if (DPbuffer[2 * i] > 1000.) {
252 *pfe++ = DPbuffer[2 * i] - 2000.;
253 *pfe++ = DPbuffer[(2 * i) + 1];
258 nPlyEntries = index_keep.size();
261 float *pf = (
float *)malloc(2 * nPlyEntries *
sizeof(
float));
266 for (
int i = 0; i < nPlyEntries; i++) {
278 float *pf1 = (
float *)malloc(2 * 4 *
sizeof(
float));
282 theChart.GetChartExtent(&fext);
298 nAuxPlyEntries = theChart.GetCOVREntries();
299 wxASSERT(nAuxPlyEntries);
300 float **pfp = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
302 int *pip = (
int *)malloc(nAuxPlyEntries *
sizeof(
int));
304 for (
int j = 0; j < nAuxPlyEntries; j++) {
305 int nPE = theChart.GetCOVRTablePoints(j);
307 if (nPE > 5 && (LOD_meters > .01)) {
308 std::vector<int> index_keep{0, nPE - 1, 1, nPE - 2};
310 double *DPbuffer = (
double *)malloc(2 * nPE *
sizeof(
double));
312 double *pfed = DPbuffer;
315 for (
int i = 0; i < nPE; i++) {
321 DouglasPeucker(DPbuffer, 1, nPE - 2, LOD_meters / (1852 * 60),
327 for (
unsigned int i = 0; i < index_keep.size(); i++) {
328 DPbuffer[2 * index_keep[i]] += 2000.;
331 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
334 for (
int i = 0; i < nPE; i++) {
335 if (DPbuffer[2 * i] > 1000.) {
336 *pfe1++ = DPbuffer[2 * i] - 2000.;
337 *pfe1++ = DPbuffer[(2 * i) + 1];
342 pip[j] = index_keep.size();
346 (
float *)malloc(theChart.GetCOVRTablePoints(j) * 2 *
sizeof(float));
347 memcpy(pf_entry, theChart.GetCOVRTableHead(j),
348 theChart.GetCOVRTablePoints(j) * 2 *
sizeof(
float));
350 pip[j] = theChart.GetCOVRTablePoints(j);
360 nNoCovrPlyEntries = theChart.GetNoCOVREntries();
361 if (nNoCovrPlyEntries == 0)
return;
363 float **pfpnc = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
364 float **pft0nc = pfpnc;
365 int *pipnc = (
int *)malloc(nNoCovrPlyEntries *
sizeof(
int));
367 for (
int j = 0; j < nNoCovrPlyEntries; j++) {
369 (
float *)malloc(theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(float));
370 memcpy(pf_entry, theChart.GetNoCOVRTableHead(j),
371 theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(
float));
372 pft0nc[j] = pf_entry;
373 pipnc[j] = theChart.GetNoCOVRTablePoints(j);
376 pNoCovrPlyTable = pfpnc;
377 pNoCovrCntTable = pipnc;
382ChartTableEntry::~ChartTableEntry() {
386 for (
int i = 0; i < nAuxPlyEntries; i++) free(pAuxPlyTable[i]);
390 if (nNoCovrPlyEntries) {
391 for (
int i = 0; i < nNoCovrPlyEntries; i++) free(pNoCovrPlyTable[i]);
392 free(pNoCovrPlyTable);
393 free(pNoCovrCntTable);
405 wxDateTime mine(edition_date);
406 wxDateTime theirs(cte.edition_date);
408 if (!mine.IsValid() || !theirs.IsValid())
411 return (mine.IsEarlierThan(theirs));
415 wxDateTime mine(edition_date);
416 wxDateTime theirs(cte.edition_date);
418 if (!mine.IsValid() || !theirs.IsValid())
421 return (mine.IsEqualTo(theirs));
426static int convertChartType(
int charttype) {
429 if (s_dbVersion == 14) {
432 return CHART_TYPE_KAP;
434 return CHART_TYPE_GEO;
436 return CHART_TYPE_S57;
438 return CHART_TYPE_CM93;
440 return CHART_TYPE_CM93COMP;
442 return CHART_TYPE_UNKNOWN;
444 return CHART_TYPE_DONTCARE;
446 return CHART_TYPE_DUMMY;
448 return CHART_TYPE_UNKNOWN;
454static int convertChartFamily(
int charttype,
int chartfamily) {
455 if (s_dbVersion < 18) {
459 return CHART_FAMILY_RASTER;
462 case CHART_TYPE_CM93:
463 case CHART_TYPE_CM93COMP:
464 return CHART_FAMILY_VECTOR;
467 return CHART_FAMILY_UNKNOWN;
473bool ChartTableEntry::Read(
const ChartDatabase *pDb, wxInputStream &is) {
474 char path[4096], *cp;
480 int db_version = pD->GetVersion();
482 if (db_version == 18) {
484 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
485 pFullPath = (
char *)malloc(cp - path + 1);
486 strncpy(pFullPath, path, cp - path + 1);
487 wxLogVerbose(
" Chart %s", pFullPath);
490 m_pfilename =
new wxString;
491 wxString fullfilename(pFullPath, wxConvUTF8);
492 wxFileName fn(fullfilename);
493 *m_pfilename = fn.GetFullName();
494 m_psFullPath =
new wxString;
495 *m_psFullPath = fullfilename;
496 m_fullSystemPath = fullfilename;
497 m_FullPath = std::string(pFullPath);
500 m_fullSystemPath = wxString(fullfilename.mb_str(wxConvUTF8));
507 EntryOffset = cte.EntryOffset;
508 ChartType = cte.ChartType;
509 ChartFamily = cte.ChartFamily;
515 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
518 ProjectionType = cte.ProjectionType;
521 edition_date = cte.edition_date;
522 file_date = cte.file_date;
524 nPlyEntries = cte.nPlyEntries;
525 nAuxPlyEntries = cte.nAuxPlyEntries;
527 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
532 int npeSize = nPlyEntries * 2 *
sizeof(float);
533 pPlyTable = (
float *)malloc(npeSize);
534 is.Read(pPlyTable, npeSize);
537 if (nAuxPlyEntries) {
538 int napeSize = nAuxPlyEntries *
sizeof(int);
539 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
540 pAuxCntTable = (
int *)malloc(napeSize);
541 is.Read(pAuxCntTable, napeSize);
543 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
545 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
546 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
547 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
551 if (nNoCovrPlyEntries) {
552 int napeSize = nNoCovrPlyEntries *
sizeof(int);
553 pNoCovrCntTable = (
int *)malloc(napeSize);
554 is.Read(pNoCovrCntTable, napeSize);
556 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
557 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
558 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
559 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
560 is.Read(pNoCovrPlyTable[i], nfSize);
565 else if (db_version == 17) {
567 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
568 pFullPath = (
char *)malloc(cp - path + 1);
569 strncpy(pFullPath, path, cp - path + 1);
570 wxLogVerbose(
" Chart %s", pFullPath);
573 m_pfilename =
new wxString;
574 wxString fullfilename(pFullPath, wxConvUTF8);
575 wxFileName fn(fullfilename);
576 *m_pfilename = fn.GetFullName();
577 m_psFullPath =
new wxString;
578 *m_psFullPath = fullfilename;
579 m_FullPath = std::string(pFullPath);
586 EntryOffset = cte.EntryOffset;
587 ChartType = cte.ChartType;
593 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
596 ProjectionType = cte.ProjectionType;
599 edition_date = cte.edition_date;
600 file_date = cte.file_date;
602 nPlyEntries = cte.nPlyEntries;
603 nAuxPlyEntries = cte.nAuxPlyEntries;
605 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
610 int npeSize = nPlyEntries * 2 *
sizeof(float);
611 pPlyTable = (
float *)malloc(npeSize);
612 is.Read(pPlyTable, npeSize);
615 if (nAuxPlyEntries) {
616 int napeSize = nAuxPlyEntries *
sizeof(int);
617 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
618 pAuxCntTable = (
int *)malloc(napeSize);
619 is.Read(pAuxCntTable, napeSize);
621 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
623 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
624 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
625 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
629 if (nNoCovrPlyEntries) {
630 int napeSize = nNoCovrPlyEntries *
sizeof(int);
631 pNoCovrCntTable = (
int *)malloc(napeSize);
632 is.Read(pNoCovrCntTable, napeSize);
634 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
635 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
636 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
637 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
638 is.Read(pNoCovrPlyTable[i], nfSize);
643 else if (db_version == 16) {
645 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
647 pFullPath = (
char *)malloc(cp - path + 1);
648 strncpy(pFullPath, path, cp - path + 1);
649 wxLogVerbose(
" Chart %s", pFullPath);
652 m_pfilename =
new wxString;
653 wxString fullfilename(pFullPath, wxConvUTF8);
654 wxFileName fn(fullfilename);
655 *m_pfilename = fn.GetFullName();
656 m_psFullPath =
new wxString;
657 *m_psFullPath = fullfilename;
658 m_FullPath = std::string(pFullPath);
665 EntryOffset = cte.EntryOffset;
666 ChartType = cte.ChartType;
672 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
675 ProjectionType = cte.ProjectionType;
678 edition_date = cte.edition_date;
679 file_date = cte.file_date;
681 nPlyEntries = cte.nPlyEntries;
682 nAuxPlyEntries = cte.nAuxPlyEntries;
687 int npeSize = nPlyEntries * 2 *
sizeof(float);
688 pPlyTable = (
float *)malloc(npeSize);
689 is.Read(pPlyTable, npeSize);
692 if (nAuxPlyEntries) {
693 int napeSize = nAuxPlyEntries *
sizeof(int);
694 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
695 pAuxCntTable = (
int *)malloc(napeSize);
696 is.Read(pAuxCntTable, napeSize);
698 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
700 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
701 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
702 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
707 else if (db_version == 15) {
709 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
711 pFullPath = (
char *)malloc(cp - path + 1);
712 strncpy(pFullPath, path, cp - path + 1);
713 wxLogVerbose(
" Chart %s", pFullPath);
720 EntryOffset = cte.EntryOffset;
721 ChartType = cte.ChartType;
727 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
730 edition_date = cte.edition_date;
731 file_date = cte.file_date;
733 nPlyEntries = cte.nPlyEntries;
734 nAuxPlyEntries = cte.nAuxPlyEntries;
739 int npeSize = nPlyEntries * 2 *
sizeof(float);
740 pPlyTable = (
float *)malloc(npeSize);
741 is.Read(pPlyTable, npeSize);
744 if (nAuxPlyEntries) {
745 int napeSize = nAuxPlyEntries *
sizeof(int);
746 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
747 pAuxCntTable = (
int *)malloc(napeSize);
748 is.Read(pAuxCntTable, napeSize);
750 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
752 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
753 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
754 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
757 }
else if (db_version == 14) {
759 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
760 pFullPath = (
char *)malloc(cp - path + 1);
761 strncpy(pFullPath, path, cp - path + 1);
762 wxLogVerbose(
" Chart %s", pFullPath);
769 EntryOffset = cte.EntryOffset;
770 ChartType = cte.ChartType;
776 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
779 edition_date = cte.edition_date;
781 nPlyEntries = cte.nPlyEntries;
782 nAuxPlyEntries = cte.nAuxPlyEntries;
786 int npeSize = nPlyEntries * 2 *
sizeof(float);
787 pPlyTable = (
float *)malloc(npeSize);
788 is.Read(pPlyTable, npeSize);
791 if (nAuxPlyEntries) {
792 int napeSize = nAuxPlyEntries *
sizeof(int);
793 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
794 pAuxCntTable = (
int *)malloc(napeSize);
795 is.Read(pAuxCntTable, napeSize);
797 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
799 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
800 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
801 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
805 ChartFamily = convertChartFamily(ChartType, ChartFamily);
806 ChartType = convertChartType(ChartType);
813bool ChartTableEntry::Write(
const ChartDatabase *pDb, wxOutputStream &os) {
814 os.Write(pFullPath, strlen(pFullPath) + 1);
821 cte.EntryOffset = EntryOffset;
822 cte.ChartType = ChartType;
823 cte.ChartFamily = ChartFamily;
830 cte.edition_date = edition_date;
831 cte.file_date = file_date;
833 cte.nPlyEntries = nPlyEntries;
834 cte.nAuxPlyEntries = nAuxPlyEntries;
837 cte.ProjectionType = ProjectionType;
841 cte.nNoCovrPlyEntries = nNoCovrPlyEntries;
844 wxLogVerbose(
" Wrote Chart %s", pFullPath);
848 int npeSize = nPlyEntries * 2 *
sizeof(float);
849 os.Write(pPlyTable, npeSize);
852 if (nAuxPlyEntries) {
853 int napeSize = nAuxPlyEntries *
sizeof(int);
854 os.Write(pAuxCntTable, napeSize);
856 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries; nAuxPlyEntry++) {
857 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
858 os.Write(pAuxPlyTable[nAuxPlyEntry], nfSize);
862 if (nNoCovrPlyEntries) {
863 int ncSize = nNoCovrPlyEntries *
sizeof(int);
864 os.Write(pNoCovrCntTable, ncSize);
866 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
867 int nctSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
868 os.Write(pNoCovrPlyTable[i], nctSize);
877void ChartTableEntry::Clear() {
886 pNoCovrCntTable = NULL;
887 pNoCovrPlyTable = NULL;
889 nNoCovrPlyEntries = 0;
898void ChartTableEntry::Disable() {
902 LatMax += (float)1000.;
903 LatMin += (float)1000.;
906void ChartTableEntry::ReEnable() {
908 LatMax -= (float)1000.;
909 LatMin -= (float)1000.;
912bool ChartTableEntry::IsBasemap()
const {
913 wxFileName fn(GetFullPath());
914 return (fn.GetPath().Lower().Contains(
"basemap"));
917std::vector<float> ChartTableEntry::GetReducedPlyPoints() {
918 if (m_reducedPlyPoints.size())
return m_reducedPlyPoints;
921 float LOD_meters = 1;
923 float plylat, plylon;
924 const int nPoints = GetnPlyEntries();
926 float *fpo = GetpPlyTable();
928 double *ppd =
new double[nPoints * 2];
929 double *ppsm =
new double[nPoints * 2];
932 for (
int i = 0; i < nPoints; i++) {
934 plylon = fpo[i * 2 + 1];
937 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
945 std::vector<int> index_keep;
947 index_keep.push_back(0);
948 index_keep.push_back(nPoints - 1);
949 index_keep.push_back(1);
950 index_keep.push_back(nPoints - 2);
952 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
955 index_keep.resize(nPoints);
956 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
960 for (
int ip = 0; ip < nPoints; ip++) {
964 for (
unsigned int j = 0; j < index_keep.size(); j++) {
965 if (index_keep[j] == ip) {
966 m_reducedPlyPoints.push_back(x);
967 m_reducedPlyPoints.push_back(y);
976 int nprr = m_reducedPlyPoints.size() / 2;
978 return m_reducedPlyPoints;
981std::vector<float> ChartTableEntry::GetReducedAuxPlyPoints(
int iTable) {
983 if (!m_reducedAuxPlyPointsVector.size()) {
984 std::vector<float> vec;
985 for (
int i = 0; i < GetnAuxPlyEntries(); i++) {
986 m_reducedAuxPlyPointsVector.push_back(vec);
990 std::vector<float> vec;
993 if ((
unsigned int)iTable >= m_reducedAuxPlyPointsVector.size())
return vec;
995 if (m_reducedAuxPlyPointsVector.at(iTable).size())
996 return m_reducedAuxPlyPointsVector.at(iTable);
999 float LOD_meters = 1.0;
1001 const int nPoints = GetAuxCntTableEntry(iTable);
1002 float *fpo = GetpAuxPlyTableEntry(iTable);
1004 double *ppd =
new double[nPoints * 2];
1005 double *ppsm =
new double[nPoints * 2];
1007 double *npsm = ppsm;
1008 float plylat, plylon;
1010 for (
int i = 0; i < nPoints; i++) {
1011 plylat = fpo[i * 2];
1012 plylon = fpo[i * 2 + 1];
1015 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
1023 std::vector<int> index_keep;
1025 index_keep.push_back(0);
1026 index_keep.push_back(nPoints - 1);
1027 index_keep.push_back(1);
1028 index_keep.push_back(nPoints - 2);
1030 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
1033 index_keep.resize(nPoints);
1034 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
1037 int nnn = index_keep.size();
1040 for (
int ip = 0; ip < nPoints; ip++) {
1044 for (
unsigned int j = 0; j < index_keep.size(); j++) {
1045 if (index_keep[j] == ip) {
1056 m_reducedAuxPlyPointsVector[iTable] = vec;
1058 int nprr = vec.size() / 2;
1067WX_DEFINE_OBJARRAY(ChartTable);
1069ChartDatabase::ChartDatabase() {
1073 m_ChartTableEntryDummy.Clear();
1075 Bind(wxEVT_OCPN_CHARTTABLEENTRYTHREAD, &ChartDatabase::OnEvtThread,
this);
1077 UpdateChartClassDescriptorArray();
1082bool collision_found =
false;
1083ChartCollisionsHashMap::iterator it;
1084for (it = collision_map.begin(); it != collision_map.end(); ++it) {
1085 if (it->first.IsSameAs(file_name)) {
1089 collision_found =
true;
1097 auto ticket =
event.GetTicket();
1100 if (m_pprog && (m_jobsRemaining > 1)) {
1102 double ratio = 100. * (double)m_progcount / m_ticketcount;
1104 if (((m_progcount % m_nFileProgressQuantum) == 0)) {
1105 if (val != m_progint) {
1108 m_pprog->Update(val);
1115 if (!ticket->b_thread_safe) {
1119 ticket->m_ChartPath, ticket->m_ChartPath, tmpDescriptor);
1120 if (pnewChartTableEntry) {
1121 std::shared_ptr<ChartTableEntry> safe_ptr(pnewChartTableEntry);
1122 ticket->m_chart_table_entry = safe_ptr;
1128 wxFileName fn(ticket->m_ChartPath);
1129 bool collision_found =
false;
1130 ChartCollisionsHashMap::iterator it;
1131 for (it = m_full_collision_map.begin(); it != m_full_collision_map.end();
1133 if (it->first.IsSameAs(fn.GetFullName())) {
1137 collision_found =
true;
1144 if (!collision_found) {
1145 m_ticket_vector.push_back(ticket);
1146 m_full_collision_map[fn.GetFullName()] = 1;
1150 int remaining = --m_jobsRemaining;
1151 if (remaining == 0) {
1155 for (
auto &ticket_d : m_deferred_ticket_vector) {
1157 nullptr, PLUGIN_DESCRIPTOR);
1159 ticket_d->m_ChartPath, ticket_d->m_ChartPath, tmpDescriptor);
1160 if (pnewChartTableEntry) {
1161 std::shared_ptr<ChartTableEntry> safe_ptr(pnewChartTableEntry);
1162 ticket_d->m_chart_table_entry = safe_ptr;
1163 m_ticket_vector.push_back(ticket_d);
1166 m_deferred_ticket_vector.clear();
1175 for (
auto &ticket_valid : m_ticket_vector) {
1176 if (ticket_valid->m_chart_table_entry)
1177 active_chartTable.push_back(ticket_valid->m_chart_table_entry);
1180 m_ticket_vector.clear();
1182 FinalizeChartUpdate();
1186void ChartDatabase::FinalizeChartUpdate() {
1189 active_chartTable.erase(
1190 std::remove_if(active_chartTable.begin(), active_chartTable.end(),
1191 [](
const auto &cte) { return !cte->GetbValid(); }),
1192 active_chartTable.end());
1195 active_chartTable_pathindex.clear();
1197 for (
auto cte : active_chartTable) {
1198 active_chartTable_pathindex[cte->GetFullSystemPath()] = i;
1199 cte->SetEntryOffset(i);
1207 m_nentries = active_chartTable.size();
1213 ChartData->SaveBinary(ChartListFileName);
1214 wxLogMessage(
"Finished chart database Update");
1217 if (m_pprog) m_pprog->Destroy();
1222 if (gWorldMapLocation.empty()) {
1226 gWorldMapLocation = gDefaultWorldMapLocation;
1227 m_gshhg_chart_loc = wxEmptyString;
1231 if (gWorldMapLocation != m_gshhg_chart_loc) {
1240 gshhsCrossesLandReset();
1253bool ChartDatabase::ScrubGroupArray() {
1258 bool b_change =
false;
1259 unsigned int igroup = 0;
1260 while (igroup < g_pGroupArray->GetCount()) {
1261 bool b_chart_in_element =
false;
1264 for (
unsigned int j = 0; j < pGroup->m_element_array.size(); j++) {
1265 const wxString &element_root = pGroup->m_element_array[j].m_element_name;
1267 for (
unsigned int ic = 0;
1268 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1269 auto &cte =
ChartData->GetChartTableEntry(ic);
1270 wxString chart_full_path = cte.GetFullSystemPath();
1272 if (chart_full_path.StartsWith(element_root)) {
1273 b_chart_in_element =
true;
1279 if (!b_chart_in_element) {
1280 wxString test_string =
"GSHH";
1281 if (element_root.Upper().Contains(test_string))
1282 b_chart_in_element =
true;
1285 if (!b_chart_in_element)
1287 pGroup->m_element_array.erase(pGroup->m_element_array.begin() + j);
1299void ChartDatabase::UpdateChartClassDescriptorArray() {
1300 if (m_ChartClassDescriptorArray.empty()) {
1301 m_ChartClassDescriptorArray.push_back(
1303 m_ChartClassDescriptorArray.push_back(
1305 m_ChartClassDescriptorArray.push_back(
1307 m_ChartClassDescriptorArray.push_back(
1310 "cm93compchart",
"00300000.a",
nullptr, BUILTIN_DESCRIPTOR));
1312 "ChartMbTiles",
"*.mbtiles",
nullptr, BUILTIN_DESCRIPTOR));
1317 m_ChartClassDescriptorArray.erase(
1318 std::remove_if(m_ChartClassDescriptorArray.begin(),
1319 m_ChartClassDescriptorArray.end(),
1321 return cd.m_descriptor_type == PLUGIN_DESCRIPTOR;
1323 m_ChartClassDescriptorArray.end());
1325 wxArrayString array =
g_pi_manager->GetPlugInChartClassNameArray();
1326 for (
unsigned int j = 0; j < array.GetCount(); j++) {
1329 wxString class_name = array[j];
1332 wxString mask = cpiw->GetFileSearchMask();
1335 auto plugin_t =
g_pi_manager->GetProvidingPlugin(class_name);
1338 m_ChartClassDescriptorArray.push_back(
1348 return *active_chartTable[index];
1356 if (index < GetChartTableEntries())
1357 return (active_chartTable[index])->get();
1363bool ChartDatabase::CompareChartDirArray(ArrayOfCDI &test_array) {
1367 if (test_array.GetCount() != m_dir_array.GetCount())
return false;
1370 unsigned int nfound_outer = 0;
1372 for (
unsigned int i = 0; i < test_array.GetCount(); i++) {
1374 bfound_inner =
false;
1375 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1378 if (p.fullpath.IsSameAs(q.fullpath)) {
1379 bfound_inner =
true;
1383 if (bfound_inner) nfound_outer++;
1386 return (nfound_outer == test_array.GetCount());
1389wxString ChartDatabase::GetMagicNumberCached(wxString dir) {
1390 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1392 if (dir.IsSameAs(q.fullpath))
return q.magic_number;
1398bool ChartDatabase::Read(
const wxString &filePath) {
1404 wxFileName file(filePath);
1405 if (!file.FileExists())
return false;
1407 m_DBFileName = filePath;
1409 wxFFileInputStream ifs(filePath);
1410 if (!ifs.Ok())
return false;
1414 if (!cth.CheckValid())
return false;
1418 memcpy(vbo, cth.GetDBVersionString(), 4);
1420 m_dbversion = atoi(&vbo[1]);
1421 s_dbVersion = m_dbversion;
1423 wxLogVerbose(
"Chartdb:Reading %d directory entries, %d table entries",
1424 cth.GetDirEntries(), cth.GetTableEntries());
1425 wxLogMessage(
"Chartdb: Chart directory list follows");
1426 if (0 == cth.GetDirEntries()) wxLogMessage(
" Nil");
1429 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1432 ifs.Read(&dirlen,
sizeof(
int));
1433 while (dirlen > 0) {
1435 int alen = dirlen > 1023 ? 1023 : dirlen;
1436 if (ifs.Read(&dirbuf, alen).Eof())
goto read_error;
1439 dir.Append(wxString(dirbuf, wxConvUTF8));
1442 msg.Printf(
" Chart directory #%d: ", iDir);
1445 m_chartDirs.Add(dir);
1448 entries = cth.GetTableEntries();
1450 active_chartTable_pathindex.clear();
1451 while (entries-- && entry.Read(
this, ifs)) {
1452 active_chartTable_pathindex[entry.GetFullSystemPath()] = ind++;
1453 auto sharedPtr = std::make_shared<ChartTableEntry>(entry);
1454 active_chartTable.push_back(sharedPtr);
1459 entry.SetAvailable(
true);
1461 m_nentries = active_chartTable.size();
1466 m_nentries = active_chartTable.size();
1472bool ChartDatabase::Write(
const wxString &filePath) {
1473 wxFileName file(filePath);
1475 file.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME, wxPATH_NATIVE));
1477 if (!dir.DirExists() && !dir.Mkdir())
return false;
1479 wxFFileOutputStream ofs(filePath);
1480 if (!ofs.Ok())
return false;
1485 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1486 wxString dir1 = m_chartDirs[iDir];
1487 int dirlen = dir1.length();
1489 strncpy(s, dir1.mb_str(wxConvUTF8), 199);
1492 ofs.Write(&dirlen,
sizeof(
int));
1494 ofs.Write(s, dirlen);
1497 for (UINT32 iTable = 0; iTable < active_chartTable.size(); iTable++) {
1498 auto &cte = GetChartTableEntry(iTable);
1499 cte.Write(
this, ofs);
1503 m_dbversion = DB_VERSION_CURRENT;
1509wxString SplitPath(wxString s, wxString tkd,
int nchar,
int offset,
1515 wxStringTokenizer tkz(s, tkd);
1516 while (tkz.HasMoreTokens()) {
1517 wxString token = tkz.GetNextToken();
1518 if ((rlen + (
int)token.Len() + 1) < nchar) {
1521 rlen += token.Len() + 1;
1525 for (
int i = 0; i < offset; i++) {
1530 rlen = offset + token.Len() + 1;
1534 if (pn_split) *pn_split = ncr;
1536 return r.Mid(0, r.Len() - 1);
1539wxString ChartDatabase::GetFullChartInfo(
ChartBase *pc,
int dbIndex,
1540 int *char_width,
int *line_count) {
1543 unsigned int max_width = 0;
1545 unsigned int target_width = 60;
1551 line = _(
" Name: ");
1552 wxString longline = pc->GetName();
1555 if (longline.Find(
' ') != wxNOT_FOUND)
1560 if (longline.Len() > target_width) {
1561 line += SplitPath(pc->GetName(), tkz, target_width, 12, &ncr);
1562 max_width = wxMax(max_width, target_width + 4);
1566 max_width = wxMax(max_width, line.Len() + 4);
1575 line.Printf(
" %s: 1:%d", _(
"Scale"), pc->GetNativeScale());
1577 line.Printf(
" %s: 1:%d", _(
"Scale"), cte.GetScale());
1580 max_width = wxMax(max_width, line.Len());
1584 wxDateTime ed = pc->GetEditionDate();
1586 line = _(
" Updated: ") + ed.FormatISODate() +
"\n";
1587 max_width = wxMax(max_width, line.Len());
1592 line = _(
" Source Edition: ") + pc->GetSE() +
"\n";
1593 max_width = wxMax(max_width, line.Len());
1599 line = _(
" Depth Units: ") + pc->GetDepthUnits() +
"\n";
1600 max_width = wxMax(max_width, line.Len());
1604 line = _(
" Soundings: ") + pc->GetSoundingsDatum() +
"\n";
1605 max_width = wxMax(max_width, line.Len());
1609 line = _(
" Datum: ") + pc->GetDatumString() +
"\n";
1610 max_width = wxMax(max_width, line.Len());
1615 line = _(
" Projection: ");
1616 if (PROJECTION_UNKNOWN == cte.GetChartProjectionType())
1617 line += _(
"Unknown");
1618 else if (PROJECTION_MERCATOR == cte.GetChartProjectionType())
1619 line += _(
"Mercator");
1620 else if (PROJECTION_TRANSVERSE_MERCATOR == cte.GetChartProjectionType())
1621 line += _(
"Transverse Mercator");
1622 else if (PROJECTION_POLYCONIC == cte.GetChartProjectionType())
1623 line += _(
"Polyconic");
1624 else if (PROJECTION_WEB_MERCATOR == cte.GetChartProjectionType())
1625 line += _(
"Web Mercator (EPSG:3857)");
1627 max_width = wxMax(max_width, line.Len());
1636 if (pc && pc->GetExtraInfo().Len()) {
1637 line += pc->GetExtraInfo();
1639 max_width = wxMax(max_width, line.Len());
1646 line += pc->GetID();
1648 max_width = wxMax(max_width, line.Len());
1653 line = _(
" ChartFile: ");
1654 wxString longline = *(cte.GetpsFullPath());
1655 if (longline.Len() > target_width) {
1656 line += SplitPath(longline,
"/,\\", target_width, 15, &ncr);
1657 max_width = wxMax(max_width, target_width + 4);
1661 max_width = wxMax(max_width, line.Len() + 4);
1667 if (line_count) *line_count = lc;
1669 if (char_width) *char_width = max_width;
1679 wxGenericProgressDialog *pprog) {
1680 m_dir_array = dir_array;
1684 m_chartDirs.Clear();
1685 active_chartTable.clear();
1686 active_chartTable_pathindex.clear();
1688 Update(dir_array,
true, pprog);
1693 m_dbversion = DB_VERSION_CURRENT;
1705 virtual wxDirTraverseResult OnFile(
const wxString &filename)
override {
1706 wxFileName fn(filename);
1707 wxFileName dir(fn.GetPath());
1708 if (fn.GetFullName().Matches(
"poly-*-1.dat") &&
1709 dir.GetFullName().IsSameAs(
"GSHHG",
false)) {
1710 parent_dir = fn.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
1713 return wxDIR_CONTINUE;
1715 virtual wxDirTraverseResult OnDir(
const wxString &dirname)
override {
1717 return wxDIR_CONTINUE;
1719 wxString GetGshhsDir()
const {
return parent_dir; }
1722 wxString parent_dir;
1729wxString findGshhgDirectory(
const wxString &directory) {
1730 wxDir dir(directory);
1731 if (!dir.IsOpened()) {
1732 return wxEmptyString;
1735 dir.Traverse(traverser, wxEmptyString, wxDIR_FILES | wxDIR_DIRS);
1736 return traverser.GetGshhsDir();
1739bool ChartDatabase::UpdateChartDatabaseInplace(ArrayOfCDI &DirArray,
1740 bool b_force,
bool b_prog) {
1744 wxString longmsg = _(
"OpenCPN Chart Update");
1746 ".................................................................."
1749 m_pprog =
new wxGenericProgressDialog();
1752 m_pprog->SetFont(*qFont);
1754 m_pprog->Create(_(
"OpenCPN Chart Update"), longmsg, 100,
nullptr,
1755 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1756 wxPD_REMAINING_TIME);
1758 DimeControl(m_pprog);
1763 wxLogMessage(
"Starting chart database Update...");
1767 m_gshhg_chart_loc = gWorldMapLocation;
1768 gWorldMapLocation = wxEmptyString;
1770 Update(DirArray, b_force, m_pprog);
1781 wxGenericProgressDialog *pprog) {
1783 m_ticket_vector.clear();
1784 m_full_collision_map.clear();
1785 m_jobsRemaining = 0;
1786 m_deferred_ticket_vector.clear();
1787 m_dir_array = dir_array;
1794 for (
unsigned int i = 0; i < active_chartTable.size(); i++) {
1795 auto &cte = GetChartTableEntry(i);
1796 cte.SetValid(
false);
1799 m_chartDirs.Clear();
1801 if (bForce) active_chartTable.clear();
1803 bool lbForce = bForce;
1806 if (s_dbVersion != DB_VERSION_CURRENT) {
1807 active_chartTable.clear();
1809 s_dbVersion = DB_VERSION_CURRENT;
1810 m_dbversion = DB_VERSION_CURRENT;
1815 for (
unsigned int j = 0; j < dir_array.GetCount(); j++) {
1822 if (!androidIsDirWritable(dir_info.fullpath))
continue;
1828 wxString gshhg_dir = findGshhgDirectory(dir_info.fullpath);
1829 if (!gshhg_dir.empty()) {
1834 wxLogMessage(
"Updating GSHHG directory: %s", gshhg_dir.c_str());
1835 gWorldMapLocation = gshhg_dir;
1837 if (dir_info.fullpath.Find(
"OSMSHP") != wxNOT_FOUND) {
1838 if (!wxDir::FindFirst(dir_info.fullpath,
"basemap_*.shp").empty()) {
1839 gWorldShapefileLocation =
1840 dir_info.fullpath + wxFileName::GetPathSeparator();
1845 TraverseDirAndAddCharts(dir_info, pprog, dir_magic, lbForce);
1848 dir_info.magic_number = dir_magic;
1849 dir_array.RemoveAt(j);
1850 dir_array.Insert(dir_info, j);
1852 m_chartDirs.Add(dir_info.fullpath);
1856 if (m_chartDirs.IsEmpty() || !m_jobsRemaining) {
1857 if (m_deferred_ticket_vector.size()) {
1860 evt->SetTicket(
nullptr);
1861 m_jobsRemaining = 1;
1862 wxQueueEvent(
this, evt);
1864 FinalizeChartUpdate();
1872 m_ticketcount = m_jobsRemaining;
1873 m_nFileProgressQuantum = wxMax(m_ticketcount / 10, 2);
1874 if (pprog) pprog->Update(0, _(
"Processing charts."));
1877 const int workerCount = 4;
1879 if (m_pool.GetWorkerCount() < workerCount) {
1880 int threads_needed = workerCount - m_pool.GetWorkerCount();
1881 for (
int i = 0; i < threads_needed; ++i) {
1894int ChartDatabase::FinddbIndex(wxString PathToFind) {
1897 for(
unsigned int i=0 ; i<active_chartTable.GetCount() ; i++)
1899 if(active_chartTable[i].GetpsFullPath()->IsSameAs(PathToFind))
1905 if (active_chartTable_pathindex.find(PathToFind) !=
1906 active_chartTable_pathindex.end())
1907 return active_chartTable_pathindex[PathToFind];
1917int ChartDatabase::DisableChart(wxString &PathToDisable) {
1918 int index = FinddbIndex(PathToDisable);
1920 auto &entry = GetChartTableEntry(index);
1934int ChartDatabase::TraverseDirAndAddCharts(
ChartDirInfo &dir_info,
1935 wxGenericProgressDialog *pprog,
1936 wxString &dir_magic,
bool bForce) {
1938 wxString dir_path = dir_info.fullpath;
1940 dir_path = wxString(dir_info.fullpath.mb_str(wxConvUTF8));
1943 wxString old_magic = dir_info.magic_number;
1944 wxString new_magic = old_magic;
1945 dir_magic = old_magic;
1949 bool b_skipDetectDirChange =
false;
1950 bool b_dirchange =
false;
1953 if (!wxDir::Exists(dir_path))
return 0;
1959 bool b_cm93 = Check_CM93_Structure(dir_path);
1961 b_skipDetectDirChange =
true;
1967 if (!b_skipDetectDirChange)
1968 b_dirchange = DetectDirChange(dir_path, dir_info.fullpath, old_magic,
1971 if (!bForce && !b_dirchange) {
1972 wxString msg(
" No change detected on directory ");
1973 msg.Append(dir_path);
1979 wxFileName fn_dir(dir_path,
"stuff");
1980 unsigned int dir_path_count = fn_dir.GetDirCount();
1982 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Scan...."));
1984 int nEntries = active_chartTable.size();
1986 for (
int ic = 0; ic < nEntries; ic++) {
1987 auto &cte = GetChartTableEntry(ic);
1988 wxFileName fn(cte.GetFullSystemPath());
1990 while (fn.GetDirCount() >= dir_path_count) {
1991 if (fn.GetPath() == dir_path) {
1992 auto &cte_a = GetChartTableEntry(ic);
1993 cte_a.SetValid(
true);
2009 dir_magic = new_magic;
2012 for (
auto &cd : m_ChartClassDescriptorArray) {
2013 nAdd += SearchDirAndAddCharts(dir_info.fullpath, cd, pprog);
2019bool ChartDatabase::DetectDirChange(
const wxString &dir_path,
2020 const wxString &prog_label,
2021 const wxString &magic, wxString &new_magic,
2022 wxGenericProgressDialog *pprog) {
2023 if (pprog) pprog->SetTitle(_(
"OpenCPN Directory Scan...."));
2026 long long unsigned int nmagic;
2027 wxULongLong nacc = 0;
2029 magic.ToULongLong(&nmagic, 10);
2032 wxArrayString FileList;
2033 wxDir dir(dir_path);
2034 int n_files = dir.GetAllFiles(dir_path, &FileList);
2040 if (pprog) pprog->Update(0, prog_label);
2044 for (
int ifile = 0; ifile < n_files; ifile++) {
2045 wxFileName file(FileList[ifile]);
2050 wxString fileNameNative = file.GetFullPath();
2051 wxScopedCharBuffer fileNameUTF8 = fileNameNative.ToUTF8();
2052 hash.Update(fileNameUTF8.data(), fileNameUTF8.length());
2055 wxULongLong size = file.GetSize();
2056 wxULongLong fileSize = ((size != wxInvalidSize) ? size : 0);
2057 hash.Update(&fileSize, (
sizeof fileSize));
2060 wxDateTime t = file.GetModificationTime();
2061 wxULongLong fileTime = t.GetTicks();
2062 hash.Update(&fileTime, (
sizeof fileTime));
2066 hash.Receive(&nacc);
2069 new_magic = nacc.ToString();
2072 if (new_magic != magic)
2078bool ChartDatabase::IsChartDirUsed(
const wxString &theDir) {
2079 wxString dir(theDir);
2080 if (dir.Last() ==
'/' || dir.Last() == wxFileName::GetPathSeparator())
2084 for (UINT32 i = 0; i < active_chartTable.size(); i++) {
2085 auto &cte_u = GetChartTableEntry(i);
2086 if (cte_u.GetpsFullPath()->Matches(dir))
return true;
2095bool ChartDatabase::Check_CM93_Structure(wxString dir_name) {
2098 wxRegEx test(
"[0-9]+");
2100 wxDir dirt(dir_name);
2103 if (dirt.IsOpened())
2104 wxLogMessage(
"check_cm93 opened dir OK: " + dir_name);
2106 wxLogMessage(
"check_cm93 NOT OPENED OK: " + dir_name);
2107 wxLogMessage(
"check_cm93 returns false." + dir_name);
2111 bool b_maybe_found_cm93 =
false;
2112 bool b_cont = dirt.GetFirst(&candidate);
2115 if (test.Matches(candidate) && (candidate.Len() == 8)) {
2116 b_maybe_found_cm93 =
true;
2120 b_cont = dirt.GetNext(&candidate);
2123 if (b_maybe_found_cm93) {
2124 wxString dir_next = dir_name;
2126 dir_next += candidate;
2127 if (wxDir::Exists(dir_next)) {
2128 wxDir dir_n(dir_next);
2129 if (dirt.IsOpened()) {
2130 wxString candidate_n;
2132 wxRegEx test_n(
"^[A-Ga-g]");
2133 bool b_probably_found_cm93 =
false;
2134 bool b_cont_n = dir_n.IsOpened() && dir_n.GetFirst(&candidate_n);
2136 if (test_n.Matches(candidate_n) && (candidate_n.Len() == 1)) {
2137 b_probably_found_cm93 =
true;
2140 b_cont_n = dir_n.GetNext(&candidate_n);
2143 if (b_probably_found_cm93)
2148 wxString dir_luk = dir_next;
2150 dir_luk += candidate_n;
2151 if (wxDir::Exists(dir_luk))
return true;
2271int ChartDatabase::SearchDirAndAddCharts(wxString &dir_name_base,
2273 wxGenericProgressDialog *pprog) {
2274 wxString msg(
"Searching directory: ");
2275 msg += dir_name_base;
2277 msg += chart_desc.m_search_mask;
2280 wxString dir_name = dir_name_base;
2283 dir_name = wxString(dir_name_base.mb_str(wxConvUTF8));
2286 if (!wxDir::Exists(dir_name))
return 0;
2288 wxString filespec = chart_desc.m_search_mask.Upper();
2289 wxString lowerFileSpec = chart_desc.m_search_mask.Lower();
2290 wxString filespecXZ = filespec +
".xz";
2291 wxString lowerFileSpecXZ = lowerFileSpec +
".xz";
2295 wxArrayString FileList;
2296 int gaf_flags = wxDIR_DEFAULT;
2303 bool b_found_cm93 =
false;
2304 bool b_cm93 = Check_CM93_Structure(dir_name);
2306 if (filespec !=
"00300000.A")
2309 filespec = dir_name;
2310 b_found_cm93 =
true;
2314 if (!b_found_cm93) {
2315 wxDir dir(dir_name);
2316 dir.GetAllFiles(dir_name, &FileList, filespec, gaf_flags);
2319 if (!FileList.GetCount()) {
2320 wxArrayString afl = androidTraverseDir(dir_name, filespec);
2321 for (wxArrayString::const_iterator item = afl.begin(); item != afl.end();
2323 FileList.Add(*item);
2328 if (filespec != lowerFileSpec) {
2330 wxArrayString lowerFileList;
2331 dir.GetAllFiles(dir_name, &lowerFileList, lowerFileSpec, gaf_flags);
2334 if (!lowerFileList.GetCount()) {
2335 wxArrayString afl = androidTraverseDir(dir_name, lowerFileSpec);
2336 for (wxArrayString::const_iterator item = afl.begin();
2337 item != afl.end(); item++)
2338 lowerFileList.Add(*item);
2342 for (wxArrayString::const_iterator item = lowerFileList.begin();
2343 item != lowerFileList.end(); item++)
2344 FileList.Add(*item);
2350 dir.GetAllFiles(dir_name, &FileList, filespecXZ, gaf_flags);
2351 dir.GetAllFiles(dir_name, &FileList, lowerFileSpecXZ, gaf_flags);
2357 wxString dir_plus = dir_name;
2358 dir_plus += wxFileName::GetPathSeparator();
2359 FileList.Add(dir_plus);
2362 int nFile = FileList.GetCount();
2364 if (!nFile)
return false;
2371 bool bthis_dir_in_dB = IsChartDirUsed(dir_name);
2373 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Add...."));
2377 ChartCollisionsHashMap collision_map;
2378 int nEntry = active_chartTable.GetCount();
2379 for (
int i = 0; i < nEntry; i++) {
2380 wxString table_file_name = active_chartTable[i].GetFullSystemPath();
2381 wxFileName table_file(table_file_name);
2382 collision_map[table_file.GetFullName()] = i;
2385 int nFileProgressQuantum = wxMax(nFile / 100, 2);
2386 double rFileProgressRatio = 100.0 / wxMax(nFile, 1);
2388 for (
int ifile = 0; ifile < nFile; ifile++) {
2389 wxFileName file(FileList[ifile]);
2390 wxString full_name = file.GetFullPath();
2391 wxString file_name = file.GetFullName();
2392 wxString utf8_path = full_name;
2400 wxFileName fnbase(dir_name_base);
2401 int nDirs = fnbase.GetDirCount();
2403 wxFileName file_target(FileList[ifile]);
2405 for (
int i = 0; i < nDirs + 1;
2407 file_target.RemoveDir(0);
2409 wxString leftover_path = file_target.GetFullPath();
2411 dir_name_base + leftover_path;
2417 if (!file_name.Matches(lowerFileSpec) && !file_name.Matches(filespec) &&
2418 !file_name.Matches(lowerFileSpecXZ) && !file_name.Matches(filespecXZ) &&
2424 if (pprog && ((ifile % nFileProgressQuantum) == 0))
2425 pprog->Update(
static_cast<int>(ifile * rFileProgressRatio), utf8_path);
2428 bool bAddFinal =
true;
2433 ChartCollisionsHashMap::const_iterator collision_ptr =
2434 collision_map.find(file_name);
2435 bool collision = (collision_ptr != collision_map.end());
2436 bool file_path_is_same =
false;
2437 bool file_time_is_same =
false;
2439 wxString table_file_name;
2442 if (b_found_cm93) collision =
false;
2445 pEntry = &active_chartTable[collision_ptr->second];
2446 table_file_name = pEntry->GetFullSystemPath();
2448 bthis_dir_in_dB && full_name.IsSameAs(table_file_name);
2452 if (file_path_is_same) {
2456 time_t t_oldFile = pEntry->GetFileTime();
2457 time_t t_newFile = file.GetModificationTime().GetTicks();
2459 if (t_newFile <= t_oldFile) {
2460 file_time_is_same =
true;
2462 pEntry->SetValid(
true);
2465 pEntry->SetValid(
false);
2470 wxString msg_fn(full_name);
2471 msg_fn.Replace(
"%",
"%%");
2472 if (file_time_is_same) {
2476 wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
2478 pnewChart = CreateChartTableEntry(full_name, utf8_path, chart_desc);
2481 wxLogMessage(wxString::Format(
2482 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2486 if (!collision || !pnewChart) {
2488 }
else if (file_path_is_same) {
2489 wxLogMessage(wxString::Format(
2490 " Replacing older chart file of same path: %s", msg_fn.c_str()));
2491 }
else if (!file_time_is_same) {
2497 if (pnewChart->IsEarlierThan(*pEntry)) {
2498 wxFileName table_file(table_file_name);
2500 if (table_file.IsFileReadable()) {
2501 pEntry->SetValid(
true);
2504 wxString::Format(
" Retaining newer chart file of same name: %s",
2507 }
else if (pnewChart->IsEqualTo(*pEntry)) {
2515 pEntry->SetValid(
false);
2517 wxLogMessage(wxString::Format(
2518 " Replacing older chart file of same name: %s", msg_fn.c_str()));
2523 if (0 == b_add_msg) {
2525 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2527 collision_map[file_name] = active_chartTable.GetCount();
2528 active_chartTable.Add(pnewChart);
2531 if (pnewChart)
delete pnewChart;
2537 m_nentries = active_chartTable.GetCount();
2543int ChartDatabase::SearchDirAndAddCharts(wxString &dir_name_base,
2545 wxGenericProgressDialog *pprog) {
2546 wxString msg(
"Searching directory: ");
2547 msg += dir_name_base;
2549 msg += chart_desc.m_search_mask;
2552 wxString dir_name = dir_name_base;
2555 dir_name = wxString(dir_name_base.mb_str(wxConvUTF8));
2558 if (!wxDir::Exists(dir_name))
return 0;
2560 wxString filespec = chart_desc.m_search_mask.Upper();
2561 wxString lowerFileSpec = chart_desc.m_search_mask.Lower();
2562 wxString filespecXZ = filespec +
".xz";
2563 wxString lowerFileSpecXZ = lowerFileSpec +
".xz";
2567 wxArrayString FileList;
2568 int gaf_flags = wxDIR_DEFAULT;
2575 bool b_found_cm93 =
false;
2576 bool b_cm93 = Check_CM93_Structure(dir_name);
2578 if (filespec !=
"00300000.A")
2581 filespec = dir_name;
2582 b_found_cm93 =
true;
2586 if (!b_found_cm93) {
2587 wxDir dir(dir_name);
2588 dir.GetAllFiles(dir_name, &FileList, filespec, gaf_flags);
2591 if (!FileList.GetCount()) {
2592 wxArrayString afl = androidTraverseDir(dir_name, filespec);
2593 for (wxArrayString::const_iterator item = afl.begin(); item != afl.end();
2595 FileList.Add(*item);
2600 if (filespec != lowerFileSpec) {
2602 wxArrayString lowerFileList;
2603 dir.GetAllFiles(dir_name, &lowerFileList, lowerFileSpec, gaf_flags);
2606 if (!lowerFileList.GetCount()) {
2607 wxArrayString afl = androidTraverseDir(dir_name, lowerFileSpec);
2608 for (wxArrayString::const_iterator item = afl.begin();
2609 item != afl.end(); item++)
2610 lowerFileList.Add(*item);
2614 for (wxArrayString::const_iterator item = lowerFileList.begin();
2615 item != lowerFileList.end(); item++)
2616 FileList.Add(*item);
2622 dir.GetAllFiles(dir_name, &FileList, filespecXZ, gaf_flags);
2623 dir.GetAllFiles(dir_name, &FileList, lowerFileSpecXZ, gaf_flags);
2629 wxString dir_plus = dir_name;
2630 dir_plus += wxFileName::GetPathSeparator();
2631 FileList.Add(dir_plus);
2634 int nFile = FileList.GetCount();
2636 if (!nFile)
return false;
2645 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Add...."));
2649 ChartCollisionsHashMap collision_map;
2658 std::vector<std::shared_ptr<ChartTableEntryJobTicket>> ticket_vector;
2660 for (
int ifile = 0; ifile < nFile; ifile++) {
2661 wxFileName file(FileList[ifile]);
2662 wxString full_path = file.GetFullPath();
2663 wxString file_name = file.GetFullName();
2664 wxString utf8_path = full_path;
2672 wxFileName fnbase(dir_name_base);
2673 int nDirs = fnbase.GetDirCount();
2675 wxFileName file_target(FileList[ifile]);
2677 for (
int i = 0; i < nDirs + 1;
2679 file_target.RemoveDir(0);
2681 wxString leftover_path = file_target.GetFullPath();
2683 dir_name_base + leftover_path;
2689 if (!file_name.Matches(lowerFileSpec) && !file_name.Matches(filespec) &&
2690 !file_name.Matches(lowerFileSpecXZ) && !file_name.Matches(filespecXZ) &&
2700 bool bAddFinal =
true;
2716 if (b_found_cm93) collision =
false;
2719 pEntry = &active_chartTable[collision_ptr->second];
2720 table_file_name = pEntry->GetFullSystemPath();
2722 bthis_dir_in_dB && full_name.IsSameAs(table_file_name);
2726 if (file_path_is_same) {
2730 time_t t_oldFile = pEntry->GetFileTime();
2731 time_t t_newFile = file.GetModificationTime().GetTicks();
2733 if (t_newFile <= t_oldFile) {
2734 file_time_is_same =
true;
2736 pEntry->SetValid(
true);
2739 pEntry->SetValid(
false);
2746 bool collision_found =
false;
2747 ChartCollisionsHashMap::iterator it;
2748 for (it = collision_map.begin(); it != collision_map.end(); ++it) {
2749 if (it->first.IsSameAs(file_name)) {
2753 collision_found =
true;
2758 if (!collision_found) {
2760 auto ticket = std::make_shared<ChartTableEntryJobTicket>();
2761 ticket->m_ChartPath = full_path;
2762 ticket->m_ChartPathUTF8 = full_path;
2763 ticket->chart_desc = chart_desc;
2765 ticket_vector.push_back(ticket);
2766 collision_map[file_name] = ifile;
2772 bool file_path_is_same = ticket_found->m_ChartPath.IsSameAs(ticket->m_ChartPath);
2773 if (file_path_is_same) {
2775 time_t t_oldFile = pEntry->GetFileTime();
2776 time_t t_newFile = file.GetModificationTime().GetTicks();
2778 if (t_newFile <= t_oldFile) {
2779 file_time_is_same =
true;
2781 pEntry->SetValid(
true);
2784 pEntry->SetValid(
false);
2791 if (chart_desc.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2797 if (!provider_plugin118) {
2801 for (
auto &ticket : ticket_vector) {
2802 ticket->b_thread_safe =
false;
2803 ticket->m_provider_type = 1;
2804 ticket->provider_class_name = chart_desc.m_class_name;
2805 m_deferred_ticket_vector.push_back(ticket);
2814 for (
auto &ticket : ticket_vector) {
2815 m_pool.Push(ticket);
2823bool ChartDatabase::AddChart(wxString &chartfilename,
2825 wxGenericProgressDialog *pprog,
int isearch,
2826 bool bthis_dir_in_dB) {
2828 wxFileName file(chartfilename);
2829 wxString full_name = file.GetFullPath();
2830 wxString file_name = file.GetFullName();
2840 pprog->Update(wxMin((m_pdifile * 100) / m_pdnFile, 100), full_name);
2843 bool bAddFinal =
true;
2845 wxString msg_fn(full_name);
2846 msg_fn.Replace(
"%",
"%%");
2848 pnewChart = CreateChartTableEntry(full_name, full_name, chart_desc);
2851 wxLogMessage(wxString::Format(
2852 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2857 int nEntry = active_chartTable.size();
2858 for (
int i = 0; i < nEntry; i++) {
2859 auto &cte_a = GetChartTableEntry(i);
2860 wxString *ptable_file_name = cte_a.GetpsFullPath();
2864 if (bthis_dir_in_dB && full_name.IsSameAs(*ptable_file_name)) {
2868 auto &cte_search = GetChartTableEntry(isearch);
2869 time_t t_oldFile = cte_search.GetFileTime();
2870 time_t t_newFile = file.GetModificationTime().GetTicks();
2872 if (t_newFile <= t_oldFile) {
2874 cte_search.SetValid(
true);
2877 cte_search.SetValid(
false);
2879 wxString::Format(
" Replacing older chart file of same path: %s",
2889 wxFileName table_file(*ptable_file_name);
2891 if (table_file.GetFullName() == file_name) {
2896 if (pnewChart->IsEarlierThan(active_chartTable[isearch])) {
2898 if (table_file.IsFileReadable()) {
2899 active_chartTable[isearch].SetValid(
true);
2901 wxLogMessage(wxString::Format(
2902 " Retaining newer chart file of same name: %s",
2905 }
else if (pnewChart->IsEqualTo(active_chartTable[isearch])) {
2915 active_chartTable[isearch].SetValid(
false);
2918 wxString::Format(
" Replacing older chart file of same name: %s",
2928 if (nEntry == isearch) isearch = 0;
2933 if (0 == b_add_msg) {
2935 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2949 m_nentries = active_chartTable.size();
2954bool ChartDatabase::AddSingleChart(wxString &ChartFullPath,
2955 bool b_force_full_search) {
2957 wxFileName fn(ChartFullPath);
2958 wxString ext = fn.GetExt();
2960 wxString ext_upper = ext.MakeUpper();
2961 wxString ext_lower = ext.MakeLower();
2962 wxString dir_name = fn.GetPath();
2968 for (
auto &cd : m_ChartClassDescriptorArray) {
2969 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2970 if (cd.m_search_mask == ext_upper) {
2974 if (cd.m_search_mask == ext_lower) {
2983 bool b_recurse =
true;
2984 if (!b_force_full_search) b_recurse = IsChartDirUsed(dir_name);
2986 bool rv = AddChart(ChartFullPath, desc, NULL, 0, b_recurse);
2990 for (
unsigned int i = 0; i < active_chartTable.size(); i++) {
2991 auto &cte_r = GetChartTableEntry(i);
2992 if (!cte_r.GetbValid()) {
3000 for (
unsigned int i = 0; i < active_chartTable.size(); i++) {
3001 auto &cte_ef = GetChartTableEntry(i);
3002 cte_ef.SetEntryOffset(i);
3007 DetectDirChange(dir_name,
"",
"", new_magic, 0);
3010 bool bcfound =
false;
3011 ArrayOfCDI NewChartDirArray;
3013 ArrayOfCDI ChartDirArray = GetChartDirArray();
3014 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
3020 if (newcdi.fullpath == dir_name) {
3021 newcdi.magic_number = new_magic;
3025 NewChartDirArray.Add(newcdi);
3030 cdi.fullpath = dir_name;
3031 cdi.magic_number = new_magic;
3032 NewChartDirArray.Add(cdi);
3036 SetChartDirArray(NewChartDirArray);
3039 m_chartDirs.Clear();
3041 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
3043 m_chartDirs.Add(cdi.fullpath);
3046 m_nentries = active_chartTable.size();
3051bool ChartDatabase::RemoveSingleChart(wxString &ChartFullPath) {
3058 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
3059 if (ChartFullPath.IsSameAs(GetChartTableEntry(i).GetFullSystemPath())) {
3060 active_chartTable.RemoveAt(i);
3068 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
3069 pcte = GetpChartTableEntry(i);
3070 pcte->SetEntryOffset(i);
3074 wxFileName fn(ChartFullPath);
3075 wxString fd = fn.GetPath();
3076 if (!IsChartDirUsed(fd)) {
3078 ArrayOfCDI NewChartDirArray;
3080 ArrayOfCDI ChartDirArray = GetChartDirArray();
3081 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
3086 if (newcdi.fullpath != fd) NewChartDirArray.Add(newcdi);
3089 SetChartDirArray(NewChartDirArray);
3093 m_chartDirs.Clear();
3094 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
3096 m_chartDirs.Add(cdi.fullpath);
3099 m_nentries = active_chartTable.GetCount();
3109ChartBase *ChartDatabase::GetChart(
const wxChar *theFilePath,
3120 const wxString &filePath, wxString &utf8Path,
3123 wxString msg_fn(filePath);
3124 msg_fn.Replace(
"%",
"%%");
3125 wxLogMessage(wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
3127 ChartBase *pch = GetChart(filePath, chart_desc);
3130 wxString::Format(
" ...creation failed for %s", msg_fn.c_str()));
3134 InitReturn rc = pch->Init(filePath, HEADER_ONLY);
3136 if (rc != INIT_OK) {
3140 wxString::Format(
" ...initialization failed for %s", msg_fn.c_str()));
3145 ret_val->SetValid(
true);
3152bool ChartDatabase::GetCentroidOfLargestScaleChart(
double *clat,
double *clon,
3153 ChartFamilyEnum family) {
3155 int cur_max_scale = 0;
3157 int nEntry = active_chartTable.size();
3159 for (
int i = 0; i < nEntry; i++) {
3160 auto &cte_fam = GetChartTableEntry(i);
3161 if (GetChartFamily(cte_fam.GetChartType()) == family) {
3162 if (cte_fam.GetScale() > cur_max_scale) {
3163 cur_max_scale = cte_fam.GetScale();
3169 if (cur_max_i == -1)
3172 auto &cte_sel = GetChartTableEntry(cur_max_i);
3173 *clat = (cte_sel.GetLatMax() + cte_sel.GetLatMin()) / 2.;
3174 *clon = (cte_sel.GetLonMin() + cte_sel.GetLonMax()) / 2.;
3182int ChartDatabase::GetDBChartProj(
int dbIndex) {
3183 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3184 auto &cte = GetChartTableEntry(dbIndex);
3185 return cte.GetChartProjectionType();
3187 return PROJECTION_UNKNOWN;
3193int ChartDatabase::GetDBChartFamily(
int dbIndex) {
3194 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3195 auto &cte = GetChartTableEntry(dbIndex);
3196 return cte.GetChartFamily();
3198 return CHART_FAMILY_UNKNOWN;
3204wxString ChartDatabase::GetDBChartFileName(
int dbIndex) {
3205 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3206 auto &cte = GetChartTableEntry(dbIndex);
3207 return wxString(cte.GetFullSystemPath());
3215int ChartDatabase::GetDBChartType(
int dbIndex) {
3216 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3217 auto &cte = GetChartTableEntry(dbIndex);
3218 return cte.GetChartType();
3226float ChartDatabase::GetDBChartSkew(
int dbIndex) {
3227 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3228 auto &cte = GetChartTableEntry(dbIndex);
3229 return cte.GetChartSkew();
3237int ChartDatabase::GetDBChartScale(
int dbIndex) {
3238 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3239 auto &cte = GetChartTableEntry(dbIndex);
3240 return cte.GetScale();
3248bool ChartDatabase::GetDBBoundingBox(
int dbIndex, LLBBox &box) {
3249 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3250 auto &entry = GetChartTableEntry(dbIndex);
3251 box.Set(entry.GetLatMin(), entry.GetLonMin(), entry.GetLatMax(),
3258const LLBBox &ChartDatabase::GetDBBoundingBox(
int dbIndex) {
3259 if ((bValid) && (dbIndex >= 0)) {
3260 auto &entry = GetChartTableEntry(dbIndex);
3261 return entry.GetBBox();
3263 return m_dummy_bbox;
3270int ChartDatabase::GetDBPlyPoint(
int dbIndex,
int plyindex,
float *lat,
3272 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3274 if (entry.GetnPlyEntries()) {
3275 float *fp = entry.GetpPlyTable();
3277 if (lat) *lat = *fp;
3279 if (lon) *lon = *fp;
3281 return entry.GetnPlyEntries();
3289int ChartDatabase::GetDBAuxPlyPoint(
int dbIndex,
int plyindex,
int ply,
3290 float *lat,
float *lon) {
3291 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3293 if (entry.GetnAuxPlyEntries()) {
3294 float *fp = entry.GetpAuxPlyTableEntry(ply);
3297 if (lat) *lat = *fp;
3299 if (lon) *lon = *fp;
3302 return entry.GetAuxCntTableEntry(ply);
3307int ChartDatabase::GetnAuxPlyEntries(
int dbIndex) {
3308 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3310 return entry.GetnAuxPlyEntries();
3318std::vector<float> ChartDatabase::GetReducedPlyPoints(
int dbIndex) {
3319 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3321 return cte.GetReducedPlyPoints();
3324 std::vector<float> dummy;
3331std::vector<float> ChartDatabase::GetReducedAuxPlyPoints(
int dbIndex,
3333 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3334 auto &cte = GetChartTableEntry(dbIndex);
3335 return cte.GetReducedAuxPlyPoints(iTable);
3338 std::vector<float> dummy;
3342bool ChartDatabase::IsChartAvailable(
int dbIndex) {
3343 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
3344 auto &cte = GetChartTableEntry(dbIndex);
3347 if (cte.GetChartType() != CHART_TYPE_PLUGIN)
return true;
3349 wxString *path = cte.GetpsFullPath();
3350 wxFileName fn(*path);
3351 wxString ext = fn.GetExt();
3353 wxString ext_upper = ext.MakeUpper();
3354 wxString ext_lower = ext.MakeLower();
3359 for (
auto &cd : m_ChartClassDescriptorArray) {
3360 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
3361 wxString search_mask = cd.m_search_mask;
3363 if (search_mask == ext_upper) {
3366 if (search_mask == ext_lower) {
3369 if (path->Matches(search_mask)) {
3379void ChartDatabase::ApplyGroupArray(ChartGroupArray *pGroupArray) {
3380 wxString separator(wxFileName::GetPathSeparator());
3382 for (
unsigned int ic = 0; ic < active_chartTable.size(); ic++) {
3383 auto &cte = GetChartTableEntry(ic);
3385 cte.ClearGroupArray();
3387 wxString *chart_full_path = cte.GetpsFullPath();
3389 for (
unsigned int igroup = 0; igroup < pGroupArray->GetCount(); igroup++) {
3390 ChartGroup *pGroup = pGroupArray->Item(igroup);
3391 for (
const auto &elem : pGroup->m_element_array) {
3392 wxString element_root = elem.m_element_name;
3398 if (!chart_full_path->IsSameAs(element_root))
3399 element_root.Append(
3401 if (chart_full_path->StartsWith(element_root)) {
3403 for (
unsigned int k = 0; k < elem.m_missing_name_array.size(); k++) {
3404 const wxString &missing_item = elem.m_missing_name_array[k];
3405 if (chart_full_path->StartsWith(missing_item)) {
3406 if (chart_full_path->IsSameAs(
3412 if (wxDir::Exists(missing_item))
3421 if (b_add) cte.AddIntToGroupArray(igroup + 1);
General chart base definitions.
ChartDB * ChartData
Global instance.
Define threaded chart database classes.
ChartGroupArray * g_pGroupArray
Global instance.
Basic chart info storage.
ChartGroupArray * g_pGroupArray
Global instance.
Base class for all chart types.
Manages a database of charts, including reading, writing, and querying chart information.
bool Create(ArrayOfCDI &dir_array, wxGenericProgressDialog *pprog)
Creates a new chart database from a list of directories.
bool Update(ArrayOfCDI &dir_array, bool bForce, wxGenericProgressDialog *pprog)
Updates the chart database.
Represents a user-defined collection of logically related charts.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
Class for computing hash of arbitrary length.
EventVar options_on_finalize_chartdbs
Notified when chartdbs async operations complete, to finalize settings.
EventVar on_finalize_chartdbs
Notified when chartdbs async operations complete, to reload charts.
Base class for OpenCPN plugins.
Hash of arbitrary length.
Misc GUI event vars, a singleton.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.