32#include <wx/arrimpl.cpp>
33#include <wx/encconv.h>
35#include <wx/progdlg.h>
36#include <wx/tokenzr.h>
41#include "pluginmanager.h"
45#include "LOD_reduce.h"
48#define UINT32 unsigned int
51#ifdef __OCPN__ANDROID__
52#include "androidUTIL.h"
56extern wxString gWorldMapLocation;
58static int s_dbVersion;
64bool FindMatchingFile(
const wxString &theDir,
const wxChar *theRegEx,
65 int nameLength, wxString &theMatch) {
67 wxRegEx rePattern(theRegEx);
68 for (
bool fileFound = dir.GetFirst(&theMatch); fileFound;
69 fileFound = dir.GetNext(&theMatch))
70 if (theMatch.length() == (
unsigned int)nameLength &&
71 rePattern.Matches(theMatch))
76static ChartFamilyEnum GetChartFamily(
int charttype) {
81 cf = CHART_FAMILY_RASTER;
84 cf = CHART_FAMILY_RASTER;
87 cf = CHART_FAMILY_VECTOR;
90 cf = CHART_FAMILY_VECTOR;
92 case CHART_TYPE_CM93COMP:
93 cf = CHART_FAMILY_VECTOR;
95 case CHART_TYPE_DUMMY:
96 cf = CHART_FAMILY_RASTER;
98 case CHART_TYPE_UNKNOWN:
99 cf = CHART_FAMILY_UNKNOWN;
102 cf = CHART_FAMILY_UNKNOWN;
112void ChartTableHeader::Read(wxInputStream &is) {
116void ChartTableHeader::Write(wxOutputStream &os) {
118 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
120 memcpy(dbVersion, vb, 4);
124bool ChartTableHeader::CheckValid() {
126 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
127 if (strncmp(vb, dbVersion,
sizeof(dbVersion))) {
130 memcpy(vbo, dbVersion, 4);
132 msg.Append(wxString(vbo, wxConvUTF8));
133 msg.Prepend(wxT(
" Warning: found incorrect chart db version: "));
139 sprintf(vb,
"V%03d", DB_VERSION_PREVIOUS);
140 if (strncmp(vb, dbVersion,
sizeof(dbVersion)))
144 _T(
" Scheduling db upgrade to current db version on ")
145 _T(
"Options->Charts page visit..."));
152 memcpy(vbo, dbVersion, 4);
154 msg.Append(wxString(vbo, wxConvUTF8));
155 msg.Prepend(wxT(
"Loading chart db version: "));
166void ChartTableEntry::SetScale(
int scale) {
170 if (Scale >= 1000) rounding = 5 * pow(10, log10(Scale) - 2);
173ChartTableEntry::ChartTableEntry(
ChartBase &theChart, wxString &utf8Path) {
176 char *pt = (
char *)malloc(strlen(utf8Path.mb_str(wxConvUTF8)) + 1);
177 strcpy(pt, utf8Path.mb_str(wxConvUTF8));
180 SetScale(theChart.GetNativeScale());
182 ChartType = theChart.GetChartType();
183 ChartFamily = theChart.GetChartFamily();
185 Skew = theChart.GetChartSkew();
186 ProjectionType = theChart.GetChartProjectionType();
188 wxDateTime ed = theChart.GetEditionDate();
189 if (theChart.GetEditionDate().IsValid())
190 edition_date = theChart.GetEditionDate().GetTicks();
192 wxFileName fn(theChart.GetFullPath());
193 if (fn.GetModificationTime().IsValid())
194 file_date = fn.GetModificationTime().GetTicks();
196 m_pfilename =
new wxString;
197 *m_pfilename = fn.GetFullName();
198 m_psFullPath =
new wxString;
199 *m_psFullPath = utf8Path;
200 m_fullSystemPath = utf8Path;
202#ifdef __OCPN__ANDROID__
203 m_fullSystemPath = wxString(utf8Path.mb_str(wxConvUTF8));
207 theChart.GetChartExtent(&ext);
213 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
218 double scale_max_zoom = Scale / 4;
220 double display_ppm = 1 / .00025;
221 double meters_per_pixel_max_scale = scale_max_zoom / display_ppm;
222 double LOD_meters = meters_per_pixel_max_scale * LOD_pixels;
227 if (theChart.GetCOVREntries() == 1) {
228 nPlyEntries = theChart.GetCOVRTablePoints(0);
230 if (nPlyEntries > 5 && (LOD_meters > .01)) {
231 std::vector<int> index_keep{0, nPlyEntries - 1, 1, nPlyEntries - 2};
233 double *DPbuffer = (
double *)malloc(2 * nPlyEntries *
sizeof(
double));
235 double *pfed = DPbuffer;
238 for (
int i = 0; i < nPlyEntries; i++) {
244 DouglasPeucker(DPbuffer, 1, nPlyEntries - 2, LOD_meters / (1852 * 60),
250 for (
unsigned int i = 0; i < index_keep.size(); i++) {
251 DPbuffer[2 * index_keep[i]] += 2000.;
254 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
257 for (
int i = 0; i < nPlyEntries; i++) {
258 if (DPbuffer[2 * i] > 1000.) {
259 *pfe++ = DPbuffer[2 * i] - 2000.;
260 *pfe++ = DPbuffer[(2 * i) + 1];
265 nPlyEntries = index_keep.size();
268 float *pf = (
float *)malloc(2 * nPlyEntries *
sizeof(
float));
273 for (
int i = 0; i < nPlyEntries; i++) {
285 float *pf1 = (
float *)malloc(2 * 4 *
sizeof(
float));
289 theChart.GetChartExtent(&fext);
305 nAuxPlyEntries = theChart.GetCOVREntries();
306 wxASSERT(nAuxPlyEntries);
307 float **pfp = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
309 int *pip = (
int *)malloc(nAuxPlyEntries *
sizeof(
int));
311 for (
int j = 0; j < nAuxPlyEntries; j++) {
312 int nPE = theChart.GetCOVRTablePoints(j);
314 if (nPE > 5 && (LOD_meters > .01)) {
315 std::vector<int> index_keep{0, nPE - 1, 1, nPE - 2};
317 double *DPbuffer = (
double *)malloc(2 * nPE *
sizeof(
double));
319 double *pfed = DPbuffer;
322 for (
int i = 0; i < nPE; i++) {
328 DouglasPeucker(DPbuffer, 1, nPE - 2, LOD_meters / (1852 * 60),
334 for (
unsigned int i = 0; i < index_keep.size(); i++) {
335 DPbuffer[2 * index_keep[i]] += 2000.;
338 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
341 for (
int i = 0; i < nPE; i++) {
342 if (DPbuffer[2 * i] > 1000.) {
343 *pfe++ = DPbuffer[2 * i] - 2000.;
344 *pfe++ = DPbuffer[(2 * i) + 1];
349 pip[j] = index_keep.size();
353 (
float *)malloc(theChart.GetCOVRTablePoints(j) * 2 *
sizeof(float));
354 memcpy(pf_entry, theChart.GetCOVRTableHead(j),
355 theChart.GetCOVRTablePoints(j) * 2 *
sizeof(
float));
357 pip[j] = theChart.GetCOVRTablePoints(j);
367 nNoCovrPlyEntries = theChart.GetNoCOVREntries();
368 if (nNoCovrPlyEntries == 0)
return;
370 float **pfpnc = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
371 float **pft0nc = pfpnc;
372 int *pipnc = (
int *)malloc(nNoCovrPlyEntries *
sizeof(
int));
374 for (
int j = 0; j < nNoCovrPlyEntries; j++) {
376 (
float *)malloc(theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(float));
377 memcpy(pf_entry, theChart.GetNoCOVRTableHead(j),
378 theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(
float));
379 pft0nc[j] = pf_entry;
380 pipnc[j] = theChart.GetNoCOVRTablePoints(j);
383 pNoCovrPlyTable = pfpnc;
384 pNoCovrCntTable = pipnc;
389ChartTableEntry::~ChartTableEntry() {
393 for (
int i = 0; i < nAuxPlyEntries; i++) free(pAuxPlyTable[i]);
397 if (nNoCovrPlyEntries) {
398 for (
int i = 0; i < nNoCovrPlyEntries; i++) free(pNoCovrPlyTable[i]);
399 free(pNoCovrPlyTable);
400 free(pNoCovrCntTable);
412 wxDateTime mine(edition_date);
413 wxDateTime theirs(cte.edition_date);
415 if (!mine.IsValid() || !theirs.IsValid())
418 return (mine.IsEarlierThan(theirs));
422 wxDateTime mine(edition_date);
423 wxDateTime theirs(cte.edition_date);
425 if (!mine.IsValid() || !theirs.IsValid())
428 return (mine.IsEqualTo(theirs));
433static int convertChartType(
int charttype) {
436 if (s_dbVersion == 14) {
439 return CHART_TYPE_KAP;
441 return CHART_TYPE_GEO;
443 return CHART_TYPE_S57;
445 return CHART_TYPE_CM93;
447 return CHART_TYPE_CM93COMP;
449 return CHART_TYPE_UNKNOWN;
451 return CHART_TYPE_DONTCARE;
453 return CHART_TYPE_DUMMY;
455 return CHART_TYPE_UNKNOWN;
461static int convertChartFamily(
int charttype,
int chartfamily) {
462 if (s_dbVersion < 18) {
466 return CHART_FAMILY_RASTER;
469 case CHART_TYPE_CM93:
470 case CHART_TYPE_CM93COMP:
471 return CHART_FAMILY_VECTOR;
474 return CHART_FAMILY_UNKNOWN;
480bool ChartTableEntry::Read(
const ChartDatabase *pDb, wxInputStream &is) {
481 char path[4096], *cp;
487 int db_version = pD->GetVersion();
489 if (db_version == 18) {
491 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++)
493 pFullPath = (
char *)malloc(cp - path + 1);
494 strncpy(pFullPath, path, cp - path + 1);
495 wxLogVerbose(_T(
" Chart %s"), pFullPath);
498 m_pfilename =
new wxString;
499 wxString fullfilename(pFullPath, wxConvUTF8);
500 wxFileName fn(fullfilename);
501 *m_pfilename = fn.GetFullName();
502 m_psFullPath =
new wxString;
503 *m_psFullPath = fullfilename;
504 m_fullSystemPath = fullfilename;
506#ifdef __OCPN__ANDROID__
507 m_fullSystemPath = wxString(fullfilename.mb_str(wxConvUTF8));
514 EntryOffset = cte.EntryOffset;
515 ChartType = cte.ChartType;
516 ChartFamily = cte.ChartFamily;
522 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
525 ProjectionType = cte.ProjectionType;
528 edition_date = cte.edition_date;
529 file_date = cte.file_date;
531 nPlyEntries = cte.nPlyEntries;
532 nAuxPlyEntries = cte.nAuxPlyEntries;
534 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
539 int npeSize = nPlyEntries * 2 *
sizeof(float);
540 pPlyTable = (
float *)malloc(npeSize);
541 is.Read(pPlyTable, npeSize);
544 if (nAuxPlyEntries) {
545 int napeSize = nAuxPlyEntries *
sizeof(int);
546 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
547 pAuxCntTable = (
int *)malloc(napeSize);
548 is.Read(pAuxCntTable, napeSize);
550 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
552 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
553 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
554 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
558 if (nNoCovrPlyEntries) {
559 int napeSize = nNoCovrPlyEntries *
sizeof(int);
560 pNoCovrCntTable = (
int *)malloc(napeSize);
561 is.Read(pNoCovrCntTable, napeSize);
563 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
564 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
565 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
566 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
567 is.Read(pNoCovrPlyTable[i], nfSize);
572 else if (db_version == 17) {
574 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++)
576 pFullPath = (
char *)malloc(cp - path + 1);
577 strncpy(pFullPath, path, cp - path + 1);
578 wxLogVerbose(_T(
" Chart %s"), pFullPath);
581 m_pfilename =
new wxString;
582 wxString fullfilename(pFullPath, wxConvUTF8);
583 wxFileName fn(fullfilename);
584 *m_pfilename = fn.GetFullName();
585 m_psFullPath =
new wxString;
586 *m_psFullPath = fullfilename;
593 EntryOffset = cte.EntryOffset;
594 ChartType = cte.ChartType;
600 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
603 ProjectionType = cte.ProjectionType;
606 edition_date = cte.edition_date;
607 file_date = cte.file_date;
609 nPlyEntries = cte.nPlyEntries;
610 nAuxPlyEntries = cte.nAuxPlyEntries;
612 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
617 int npeSize = nPlyEntries * 2 *
sizeof(float);
618 pPlyTable = (
float *)malloc(npeSize);
619 is.Read(pPlyTable, npeSize);
622 if (nAuxPlyEntries) {
623 int napeSize = nAuxPlyEntries *
sizeof(int);
624 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
625 pAuxCntTable = (
int *)malloc(napeSize);
626 is.Read(pAuxCntTable, napeSize);
628 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
630 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
631 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
632 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
636 if (nNoCovrPlyEntries) {
637 int napeSize = nNoCovrPlyEntries *
sizeof(int);
638 pNoCovrCntTable = (
int *)malloc(napeSize);
639 is.Read(pNoCovrCntTable, napeSize);
641 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
642 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
643 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
644 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
645 is.Read(pNoCovrPlyTable[i], nfSize);
650 else if (db_version == 16) {
652 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++)
655 pFullPath = (
char *)malloc(cp - path + 1);
656 strncpy(pFullPath, path, cp - path + 1);
657 wxLogVerbose(_T(
" Chart %s"), pFullPath);
660 m_pfilename =
new wxString;
661 wxString fullfilename(pFullPath, wxConvUTF8);
662 wxFileName fn(fullfilename);
663 *m_pfilename = fn.GetFullName();
664 m_psFullPath =
new wxString;
665 *m_psFullPath = fullfilename;
672 EntryOffset = cte.EntryOffset;
673 ChartType = cte.ChartType;
679 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
682 ProjectionType = cte.ProjectionType;
685 edition_date = cte.edition_date;
686 file_date = cte.file_date;
688 nPlyEntries = cte.nPlyEntries;
689 nAuxPlyEntries = cte.nAuxPlyEntries;
694 int npeSize = nPlyEntries * 2 *
sizeof(float);
695 pPlyTable = (
float *)malloc(npeSize);
696 is.Read(pPlyTable, npeSize);
699 if (nAuxPlyEntries) {
700 int napeSize = nAuxPlyEntries *
sizeof(int);
701 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
702 pAuxCntTable = (
int *)malloc(napeSize);
703 is.Read(pAuxCntTable, napeSize);
705 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
707 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
708 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
709 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
714 else if (db_version == 15) {
716 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++)
719 pFullPath = (
char *)malloc(cp - path + 1);
720 strncpy(pFullPath, path, cp - path + 1);
721 wxLogVerbose(_T(
" Chart %s"), pFullPath);
728 EntryOffset = cte.EntryOffset;
729 ChartType = cte.ChartType;
735 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
738 edition_date = cte.edition_date;
739 file_date = cte.file_date;
741 nPlyEntries = cte.nPlyEntries;
742 nAuxPlyEntries = cte.nAuxPlyEntries;
747 int npeSize = nPlyEntries * 2 *
sizeof(float);
748 pPlyTable = (
float *)malloc(npeSize);
749 is.Read(pPlyTable, npeSize);
752 if (nAuxPlyEntries) {
753 int napeSize = nAuxPlyEntries *
sizeof(int);
754 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
755 pAuxCntTable = (
int *)malloc(napeSize);
756 is.Read(pAuxCntTable, napeSize);
758 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
760 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
761 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
762 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
765 }
else if (db_version == 14) {
767 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++)
769 pFullPath = (
char *)malloc(cp - path + 1);
770 strncpy(pFullPath, path, cp - path + 1);
771 wxLogVerbose(_T(
" Chart %s"), pFullPath);
778 EntryOffset = cte.EntryOffset;
779 ChartType = cte.ChartType;
785 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
788 edition_date = cte.edition_date;
790 nPlyEntries = cte.nPlyEntries;
791 nAuxPlyEntries = cte.nAuxPlyEntries;
795 int npeSize = nPlyEntries * 2 *
sizeof(float);
796 pPlyTable = (
float *)malloc(npeSize);
797 is.Read(pPlyTable, npeSize);
800 if (nAuxPlyEntries) {
801 int napeSize = nAuxPlyEntries *
sizeof(int);
802 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
803 pAuxCntTable = (
int *)malloc(napeSize);
804 is.Read(pAuxCntTable, napeSize);
806 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
808 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
809 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
810 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
814 ChartFamily = convertChartFamily(ChartType, ChartFamily);
815 ChartType = convertChartType(ChartType);
822bool ChartTableEntry::Write(
const ChartDatabase *pDb, wxOutputStream &os) {
823 os.Write(pFullPath, strlen(pFullPath) + 1);
830 cte.EntryOffset = EntryOffset;
831 cte.ChartType = ChartType;
832 cte.ChartFamily = ChartFamily;
839 cte.edition_date = edition_date;
840 cte.file_date = file_date;
842 cte.nPlyEntries = nPlyEntries;
843 cte.nAuxPlyEntries = nAuxPlyEntries;
846 cte.ProjectionType = ProjectionType;
850 cte.nNoCovrPlyEntries = nNoCovrPlyEntries;
853 wxLogVerbose(_T(
" Wrote Chart %s"), pFullPath);
857 int npeSize = nPlyEntries * 2 *
sizeof(float);
858 os.Write(pPlyTable, npeSize);
861 if (nAuxPlyEntries) {
862 int napeSize = nAuxPlyEntries *
sizeof(int);
863 os.Write(pAuxCntTable, napeSize);
865 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries; nAuxPlyEntry++) {
866 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
867 os.Write(pAuxPlyTable[nAuxPlyEntry], nfSize);
871 if (nNoCovrPlyEntries) {
872 int ncSize = nNoCovrPlyEntries *
sizeof(int);
873 os.Write(pNoCovrCntTable, ncSize);
875 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
876 int nctSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
877 os.Write(pNoCovrPlyTable[i], nctSize);
886void ChartTableEntry::Clear() {
895 pNoCovrCntTable = NULL;
896 pNoCovrPlyTable = NULL;
898 nNoCovrPlyEntries = 0;
907void ChartTableEntry::Disable() {
911 LatMax += (float)1000.;
912 LatMin += (float)1000.;
915void ChartTableEntry::ReEnable() {
917 LatMax -= (float)1000.;
918 LatMin -= (float)1000.;
922std::vector<float> ChartTableEntry::GetReducedPlyPoints() {
923 if (m_reducedPlyPoints.size())
return m_reducedPlyPoints;
926 float LOD_meters = 1;
928 float plylat, plylon;
929 const int nPoints = GetnPlyEntries();
931 float *fpo = GetpPlyTable();
933 double *ppd =
new double[nPoints * 2];
934 double *ppsm =
new double[nPoints * 2];
937 for (
int i = 0; i < nPoints; i++) {
939 plylon = fpo[i * 2 + 1];
942 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
950 std::vector<int> index_keep;
952 index_keep.push_back(0);
953 index_keep.push_back(nPoints - 1);
954 index_keep.push_back(1);
955 index_keep.push_back(nPoints - 2);
957 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
960 index_keep.resize(nPoints);
961 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
965 for (
int ip = 0; ip < nPoints; ip++) {
969 for (
unsigned int j = 0; j < index_keep.size(); j++) {
970 if (index_keep[j] == ip) {
971 m_reducedPlyPoints.push_back(x);
972 m_reducedPlyPoints.push_back(y);
981 int nprr = m_reducedPlyPoints.size() / 2;
983 return m_reducedPlyPoints;
986std::vector<float> ChartTableEntry::GetReducedAuxPlyPoints(
int iTable) {
988 if (!m_reducedAuxPlyPointsVector.size()) {
989 std::vector<float> vec;
990 for (
int i = 0; i < GetnAuxPlyEntries(); i++) {
991 m_reducedAuxPlyPointsVector.push_back(vec);
995 std::vector<float> vec;
998 if ((
unsigned int)iTable >= m_reducedAuxPlyPointsVector.size())
return vec;
1000 if (m_reducedAuxPlyPointsVector.at(iTable).size())
1001 return m_reducedAuxPlyPointsVector.at(iTable);
1004 float LOD_meters = 1.0;
1006 const int nPoints = GetAuxCntTableEntry(iTable);
1007 float *fpo = GetpAuxPlyTableEntry(iTable);
1009 double *ppd =
new double[nPoints * 2];
1010 double *ppsm =
new double[nPoints * 2];
1012 double *npsm = ppsm;
1013 float plylat, plylon;
1015 for (
int i = 0; i < nPoints; i++) {
1016 plylat = fpo[i * 2];
1017 plylon = fpo[i * 2 + 1];
1020 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
1028 std::vector<int> index_keep;
1030 index_keep.push_back(0);
1031 index_keep.push_back(nPoints - 1);
1032 index_keep.push_back(1);
1033 index_keep.push_back(nPoints - 2);
1035 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
1038 index_keep.resize(nPoints);
1039 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
1042 int nnn = index_keep.size();
1045 for (
int ip = 0; ip < nPoints; ip++) {
1049 for (
unsigned int j = 0; j < index_keep.size(); j++) {
1050 if (index_keep[j] == ip) {
1061 m_reducedAuxPlyPointsVector[iTable] = vec;
1063 int nprr = vec.size() / 2;
1072WX_DEFINE_OBJARRAY(ChartTable);
1073WX_DEFINE_OBJARRAY(ArrayOfChartClassDescriptor);
1075ChartDatabase::ChartDatabase() {
1079 m_ChartTableEntryDummy.Clear();
1081 UpdateChartClassDescriptorArray();
1084void ChartDatabase::UpdateChartClassDescriptorArray(
void) {
1085 m_ChartClassDescriptorArray.Clear();
1092 m_ChartClassDescriptorArray.Add(pcd);
1095 m_ChartClassDescriptorArray.Add(pcd);
1098 m_ChartClassDescriptorArray.Add(pcd);
1101 m_ChartClassDescriptorArray.Add(pcd);
1103 BUILTIN_DESCRIPTOR);
1104 m_ChartClassDescriptorArray.Add(pcd);
1106 BUILTIN_DESCRIPTOR);
1107 m_ChartClassDescriptorArray.Add(pcd);
1112 wxArrayString array = g_pi_manager->GetPlugInChartClassNameArray();
1113 for (
unsigned int j = 0; j < array.GetCount(); j++) {
1116 wxString class_name = array[j];
1119 wxString mask = cpiw->GetFileSearchMask();
1126 m_ChartClassDescriptorArray.Add(picd);
1134const ChartTableEntry &ChartDatabase::GetChartTableEntry(
int index)
const {
1135 if (index < GetChartTableEntries())
1136 return active_chartTable[index];
1138 return m_ChartTableEntryDummy;
1142 if (index < GetChartTableEntries())
1143 return &active_chartTable[index];
1148bool ChartDatabase::CompareChartDirArray(ArrayOfCDI &test_array) {
1152 if (test_array.GetCount() != m_dir_array.GetCount())
return false;
1155 unsigned int nfound_outer = 0;
1157 for (
unsigned int i = 0; i < test_array.GetCount(); i++) {
1159 bfound_inner =
false;
1160 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1163 if (p.fullpath.IsSameAs(q.fullpath)) {
1164 bfound_inner =
true;
1168 if (bfound_inner) nfound_outer++;
1171 return (nfound_outer == test_array.GetCount());
1174wxString ChartDatabase::GetMagicNumberCached(wxString dir) {
1175 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1177 if (dir.IsSameAs(q.fullpath))
return q.magic_number;
1183bool ChartDatabase::Read(
const wxString &filePath) {
1189 wxFileName file(filePath);
1190 if (!file.FileExists())
return false;
1192 m_DBFileName = filePath;
1194 wxFFileInputStream ifs(filePath);
1195 if (!ifs.Ok())
return false;
1199 if (!cth.CheckValid())
return false;
1203 memcpy(vbo, cth.GetDBVersionString(), 4);
1205 m_dbversion = atoi(&vbo[1]);
1206 s_dbVersion = m_dbversion;
1208 wxLogVerbose(wxT(
"Chartdb:Reading %d directory entries, %d table entries"),
1209 cth.GetDirEntries(), cth.GetTableEntries());
1210 wxLogMessage(_T(
"Chartdb: Chart directory list follows"));
1211 if (0 == cth.GetDirEntries()) wxLogMessage(_T(
" Nil"));
1214 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1217 ifs.Read(&dirlen,
sizeof(
int));
1218 while (dirlen > 0) {
1220 int alen = dirlen > 1023 ? 1023 : dirlen;
1221 if (ifs.Read(&dirbuf, alen).Eof())
goto read_error;
1224 dir.Append(wxString(dirbuf, wxConvUTF8));
1227 msg.Printf(wxT(
" Chart directory #%d: "), iDir);
1230 m_chartDirs.Add(dir);
1233 entries = cth.GetTableEntries();
1234 active_chartTable.Alloc(entries);
1235 active_chartTable_pathindex.clear();
1236 while (entries-- && entry.Read(
this, ifs)) {
1237 active_chartTable_pathindex[entry.GetFullSystemPath()] = ind++;
1238 active_chartTable.Add(entry);
1243 entry.SetAvailable(
true);
1245 m_nentries = active_chartTable.GetCount();
1250 m_nentries = active_chartTable.GetCount();
1256bool ChartDatabase::Write(
const wxString &filePath) {
1257 wxFileName file(filePath);
1259 file.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME, wxPATH_NATIVE));
1261 if (!dir.DirExists() && !dir.Mkdir())
return false;
1263 wxFFileOutputStream ofs(filePath);
1264 if (!ofs.Ok())
return false;
1266 ChartTableHeader cth(m_chartDirs.GetCount(), active_chartTable.GetCount());
1269 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1270 wxString &dir = m_chartDirs[iDir];
1271 int dirlen = dir.length();
1273 strncpy(s, dir.mb_str(wxConvUTF8), 199);
1276 ofs.Write(&dirlen,
sizeof(
int));
1278 ofs.Write(s, dirlen);
1281 for (UINT32 iTable = 0; iTable < active_chartTable.size(); iTable++)
1282 active_chartTable[iTable].Write(
this, ofs);
1285 m_dbversion = DB_VERSION_CURRENT;
1291wxString SplitPath(wxString s, wxString tkd,
int nchar,
int offset,
1297 wxStringTokenizer tkz(s, tkd);
1298 while (tkz.HasMoreTokens()) {
1299 wxString token = tkz.GetNextToken();
1300 if ((rlen + (
int)token.Len() + 1) < nchar) {
1303 rlen += token.Len() + 1;
1307 for (
int i = 0; i < offset; i++) {
1312 rlen = offset + token.Len() + 1;
1316 if (pn_split) *pn_split = ncr;
1318 return r.Mid(0, r.Len() - 1);
1321wxString ChartDatabase::GetFullChartInfo(
ChartBase *pc,
int dbIndex,
1322 int *char_width,
int *line_count) {
1325 unsigned int max_width = 0;
1327 unsigned int target_width = 60;
1333 line = _(
" ChartFile: ");
1334 wxString longline = *(cte.GetpsFullPath());
1336 if (longline.Len() > target_width) {
1337 line += SplitPath(longline, _T(
"/,\\"), target_width, 15, &ncr);
1338 max_width = wxMax(max_width, target_width + 4);
1342 max_width = wxMax(max_width, line.Len() + 4);
1351 line = _(
" Name: ");
1352 wxString longline = pc->GetName();
1355 if (longline.Find(
' ') != wxNOT_FOUND)
1360 if (longline.Len() > target_width) {
1361 line += SplitPath(pc->GetName(), tkz, target_width, 12, &ncr);
1362 max_width = wxMax(max_width, target_width + 4);
1366 max_width = wxMax(max_width, line.Len() + 4);
1375 line.Printf(_T(
" %s: 1:%d"), _(
"Scale"), pc->GetNativeScale());
1377 line.Printf(_T(
" %s: 1:%d"), _(
"Scale"), cte.GetScale());
1380 max_width = wxMax(max_width, line.Len());
1387 line += pc->GetID();
1389 max_width = wxMax(max_width, line.Len());
1394 line = _(
" Depth Units: ");
1395 line += pc->GetDepthUnits();
1397 max_width = wxMax(max_width, line.Len());
1402 line = _(
" Soundings: ");
1403 line += pc->GetSoundingsDatum();
1405 max_width = wxMax(max_width, line.Len());
1410 line = _(
" Datum: ");
1411 line += pc->GetDatumString();
1413 max_width = wxMax(max_width, line.Len());
1418 line = _(
" Projection: ");
1419 if (PROJECTION_UNKNOWN == cte.GetChartProjectionType())
1420 line += _(
"Unknown");
1421 else if (PROJECTION_MERCATOR == cte.GetChartProjectionType())
1422 line += _(
"Mercator");
1423 else if (PROJECTION_TRANSVERSE_MERCATOR == cte.GetChartProjectionType())
1424 line += _(
"Transverse Mercator");
1425 else if (PROJECTION_POLYCONIC == cte.GetChartProjectionType())
1426 line += _(
"Polyconic");
1427 else if (PROJECTION_WEB_MERCATOR == cte.GetChartProjectionType())
1428 line += _(
"Web Mercator (EPSG:3857)");
1430 max_width = wxMax(max_width, line.Len());
1436 line = _(
" Source Edition: ");
1437 line += pc->GetSE();
1439 max_width = wxMax(max_width, line.Len());
1444 wxDateTime ed = pc->GetEditionDate();
1446 line = _(
" Updated: ");
1447 line += ed.FormatISODate();
1449 max_width = wxMax(max_width, line.Len());
1456 if (pc && pc->GetExtraInfo().Len()) {
1457 line += pc->GetExtraInfo();
1459 max_width = wxMax(max_width, line.Len());
1465 if (line_count) *line_count = lc;
1467 if (char_width) *char_width = max_width;
1476bool ChartDatabase::Create(ArrayOfCDI &dir_array,
1477 wxGenericProgressDialog *pprog) {
1478 m_dir_array = dir_array;
1482 m_chartDirs.Clear();
1483 active_chartTable.Clear();
1484 active_chartTable_pathindex.clear();
1486 Update(dir_array,
true, pprog);
1491 m_dbversion = DB_VERSION_CURRENT;
1500bool ChartDatabase::Update(ArrayOfCDI &dir_array,
bool bForce,
1501 wxGenericProgressDialog *pprog) {
1502 m_dir_array = dir_array;
1508 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
1509 active_chartTable[i].SetValid(
false);
1511 m_chartDirs.Clear();
1513 if (bForce) active_chartTable.Clear();
1515 bool lbForce = bForce;
1518 if (s_dbVersion != DB_VERSION_CURRENT) {
1519 active_chartTable.Clear();
1521 s_dbVersion = DB_VERSION_CURRENT;
1522 m_dbversion = DB_VERSION_CURRENT;
1527 for (
unsigned int j = 0; j < dir_array.GetCount(); j++) {
1533#ifdef __OCPN__ANDROID__
1534 if (!androidIsDirWritable(dir_info.fullpath))
1540 if (dir_info.fullpath.Find(_T(
"GSHHG")) != wxNOT_FOUND) {
1541 if (!wxDir::FindFirst(dir_info.fullpath,
"poly-*-1.dat").empty()) {
1546 gWorldMapLocation = dir_info.fullpath + wxFileName::GetPathSeparator();
1550 TraverseDirAndAddCharts(dir_info, pprog, dir_magic, lbForce);
1554 dir_info.magic_number = dir_magic;
1555 dir_array.RemoveAt(j);
1556 dir_array.Insert(dir_info, j);
1558 m_chartDirs.Add(dir_info.fullpath);
1561 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1562 if (!active_chartTable[i].GetbValid()) {
1563 active_chartTable.RemoveAt(i);
1569 active_chartTable_pathindex.clear();
1570 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1571 active_chartTable_pathindex[active_chartTable[i].GetFullSystemPath()] = i;
1572 active_chartTable[i].SetEntryOffset(i);
1575 m_nentries = active_chartTable.GetCount();
1586int ChartDatabase::FinddbIndex(wxString PathToFind) {
1589 for(
unsigned int i=0 ; i<active_chartTable.GetCount() ; i++)
1591 if(active_chartTable[i].GetpsFullPath()->IsSameAs(PathToFind))
1597 if (active_chartTable_pathindex.find(PathToFind) !=
1598 active_chartTable_pathindex.end())
1599 return active_chartTable_pathindex[PathToFind];
1609int ChartDatabase::DisableChart(wxString &PathToDisable) {
1610 int index = FinddbIndex(PathToDisable);
1626int ChartDatabase::TraverseDirAndAddCharts(
ChartDirInfo &dir_info,
1627 wxGenericProgressDialog *pprog,
1628 wxString &dir_magic,
bool bForce) {
1630 wxString dir_path = dir_info.fullpath;
1631#ifdef __OCPN__ANDROID__
1632 dir_path = wxString(dir_info.fullpath.mb_str(wxConvUTF8));
1635 wxString old_magic = dir_info.magic_number;
1636 wxString new_magic = old_magic;
1637 dir_magic = old_magic;
1641 bool b_skipDetectDirChange =
false;
1642 bool b_dirchange =
false;
1645 if (!wxDir::Exists(dir_path))
return 0;
1651 bool b_cm93 = Check_CM93_Structure(dir_path);
1653 b_skipDetectDirChange =
true;
1659 if (!b_skipDetectDirChange)
1660 b_dirchange = DetectDirChange(dir_path, dir_info.fullpath, old_magic,
1663 if (!bForce && !b_dirchange) {
1664 wxString msg(_T(
" No change detected on directory "));
1665 msg.Append(dir_path);
1671 wxFileName fn_dir(dir_path, _T(
"stuff"));
1672 unsigned int dir_path_count = fn_dir.GetDirCount();
1674 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Scan...."));
1676 int nEntries = active_chartTable.GetCount();
1678 for (
int ic = 0; ic < nEntries; ic++) {
1679 wxFileName fn(active_chartTable[ic].GetFullSystemPath());
1681 while (fn.GetDirCount() >= dir_path_count) {
1682 if (fn.GetPath() == dir_path) {
1683 active_chartTable[ic].SetValid(
true);
1699 dir_magic = new_magic;
1702 for (
unsigned int i = 0; i < m_ChartClassDescriptorArray.GetCount(); i++) {
1703 nAdd += SearchDirAndAddCharts(dir_info.fullpath,
1704 m_ChartClassDescriptorArray.Item(i), pprog);
1710bool ChartDatabase::DetectDirChange(
const wxString &dir_path,
1711 const wxString &prog_label,
1712 const wxString &magic, wxString &new_magic,
1713 wxGenericProgressDialog *pprog) {
1714 if (pprog) pprog->SetTitle(_(
"OpenCPN Directory Scan...."));
1717 long long unsigned int nmagic;
1718 wxULongLong nacc = 0;
1720 magic.ToULongLong(&nmagic, 10);
1723 wxArrayString FileList;
1724 wxDir dir(dir_path);
1725 int n_files = dir.GetAllFiles(dir_path, &FileList);
1733 for (
int ifile = 0; ifile < n_files; ifile++) {
1734 if (pprog && (ifile % (n_files / 60 + 1)) == 0)
1735 pprog->Update(wxMin((ifile * 100) / n_files, 100), prog_label);
1737 wxFileName file(FileList[ifile]);
1742 wxString fileNameNative = file.GetFullPath();
1743 wxScopedCharBuffer fileNameUTF8 = fileNameNative.ToUTF8();
1744 hash.Update(fileNameUTF8.data(), fileNameUTF8.length());
1747 wxULongLong size = file.GetSize();
1748 wxULongLong fileSize = ((size != wxInvalidSize) ? size : 0);
1749 hash.Update(&fileSize, (
sizeof fileSize));
1752 wxDateTime t = file.GetModificationTime();
1753 wxULongLong fileTime = t.GetTicks();
1754 hash.Update(&fileTime, (
sizeof fileTime));
1758 hash.Receive(&nacc);
1761 new_magic = nacc.ToString();
1764 if (new_magic != magic)
1770bool ChartDatabase::IsChartDirUsed(
const wxString &theDir) {
1771 wxString dir(theDir);
1772 if (dir.Last() ==
'/' || dir.Last() == wxFileName::GetPathSeparator())
1775 dir.Append(wxT(
"*"));
1776 for (UINT32 i = 0; i < active_chartTable.GetCount(); i++) {
1777 if (active_chartTable[i].GetpsFullPath()->Matches(dir))
return true;
1786bool ChartDatabase::Check_CM93_Structure(wxString dir_name) {
1789 wxRegEx test(_T(
"[0-9]+"));
1791 wxDir dirt(dir_name);
1794 if (dirt.IsOpened())
1795 wxLogMessage(_T(
"check_cm93 opened dir OK: ") + dir_name);
1797 wxLogMessage(_T(
"check_cm93 NOT OPENED OK: ") + dir_name);
1798 wxLogMessage(_T(
"check_cm93 returns false.") + dir_name);
1802 bool b_maybe_found_cm93 =
false;
1803 bool b_cont = dirt.GetFirst(&candidate);
1806 if (test.Matches(candidate) && (candidate.Len() == 8)) {
1807 b_maybe_found_cm93 =
true;
1811 b_cont = dirt.GetNext(&candidate);
1814 if (b_maybe_found_cm93) {
1815 wxString dir_next = dir_name;
1816 dir_next += _T(
"/");
1817 dir_next += candidate;
1818 if (wxDir::Exists(dir_next)) {
1819 wxDir dir_n(dir_next);
1820 if (dirt.IsOpened()) {
1821 wxString candidate_n;
1823 wxRegEx test_n(_T(
"^[A-Ga-g]"));
1824 bool b_probably_found_cm93 =
false;
1825 bool b_cont_n = dir_n.IsOpened() && dir_n.GetFirst(&candidate_n);
1827 if (test_n.Matches(candidate_n) && (candidate_n.Len() == 1)) {
1828 b_probably_found_cm93 =
true;
1831 b_cont_n = dir_n.GetNext(&candidate_n);
1834 if (b_probably_found_cm93)
1839 wxString dir_luk = dir_next;
1841 dir_luk += candidate_n;
1842 if (wxDir::Exists(dir_luk))
return true;
1961WX_DECLARE_STRING_HASH_MAP(
int, ChartCollisionsHashMap);
1963int ChartDatabase::SearchDirAndAddCharts(wxString &dir_name_base,
1965 wxGenericProgressDialog *pprog) {
1966 wxString msg(_T(
"Searching directory: "));
1967 msg += dir_name_base;
1969 msg += chart_desc.m_search_mask;
1972 wxString dir_name = dir_name_base;
1974#ifdef __OCPN__ANDROID__
1975 dir_name = wxString(dir_name_base.mb_str(wxConvUTF8));
1978 if (!wxDir::Exists(dir_name))
return 0;
1980 wxString filespec = chart_desc.m_search_mask.Upper();
1981 wxString lowerFileSpec = chart_desc.m_search_mask.Lower();
1982 wxString filespecXZ = filespec + _T(
".xz");
1983 wxString lowerFileSpecXZ = lowerFileSpec + _T(
".xz");
1987 wxArrayString FileList;
1988 int gaf_flags = wxDIR_DEFAULT;
1995 bool b_found_cm93 =
false;
1996 bool b_cm93 = Check_CM93_Structure(dir_name);
1998 if (filespec != _T(
"00300000.A"))
2001 filespec = dir_name;
2002 b_found_cm93 =
true;
2006 if (!b_found_cm93) {
2008 wxDir dir(dir_name);
2009 dir.GetAllFiles(dir_name, &FileList, filespec, gaf_flags);
2011#ifdef __OCPN__ANDROID__
2012 if (!FileList.GetCount()) {
2013 wxArrayString afl = androidTraverseDir(dir_name, filespec);
2014 for (wxArrayString::const_iterator item = afl.begin(); item != afl.end();
2016 FileList.Add(*item);
2022 if (filespec != lowerFileSpec) {
2024 wxArrayString lowerFileList;
2025 dir.GetAllFiles(dir_name, &lowerFileList, lowerFileSpec, gaf_flags);
2028#ifdef __OCPN__ANDROID__
2029 if (!lowerFileList.GetCount()) {
2030 wxArrayString afl = androidTraverseDir(dir_name, lowerFileSpec);
2031 for (wxArrayString::const_iterator item = afl.begin();
2032 item != afl.end(); item++)
2033 lowerFileList.Add(*item);
2037 for (wxArrayString::const_iterator item = lowerFileList.begin();
2038 item != lowerFileList.end(); item++)
2039 FileList.Add(*item);
2045 dir.GetAllFiles(dir_name, &FileList, filespecXZ, gaf_flags);
2046 dir.GetAllFiles(dir_name, &FileList, lowerFileSpecXZ, gaf_flags);
2053 wxString dir_plus = dir_name;
2054 dir_plus += wxFileName::GetPathSeparator();
2055 FileList.Add(dir_plus);
2058 int nFile = FileList.GetCount();
2060 if (!nFile)
return false;
2067 bool bthis_dir_in_dB = IsChartDirUsed(dir_name);
2069 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Add...."));
2073 ChartCollisionsHashMap collision_map;
2074 int nEntry = active_chartTable.GetCount();
2075 for (
int i = 0; i < nEntry; i++) {
2076 wxString table_file_name = active_chartTable[i].GetFullSystemPath();
2077 wxFileName table_file(table_file_name);
2078 collision_map[table_file.GetFullName()] = i;
2081 int nFileProgressQuantum = wxMax(nFile / 100, 2);
2082 double rFileProgressRatio = 100.0 / wxMax(nFile, 1);
2084 for (
int ifile = 0; ifile < nFile; ifile++) {
2085 wxFileName file(FileList[ifile]);
2086 wxString full_name = file.GetFullPath();
2087 wxString file_name = file.GetFullName();
2088 wxString utf8_path = full_name;
2090#ifdef __OCPN__ANDROID__
2096 wxFileName fnbase(dir_name_base);
2097 int nDirs = fnbase.GetDirCount();
2099 wxFileName file_target(FileList[ifile]);
2101 for (
int i = 0; i < nDirs + 1;
2103 file_target.RemoveDir(0);
2105 wxString leftover_path = file_target.GetFullPath();
2107 dir_name_base + leftover_path;
2113 if (!file_name.Matches(lowerFileSpec) && !file_name.Matches(filespec) &&
2114 !file_name.Matches(lowerFileSpecXZ) && !file_name.Matches(filespecXZ) &&
2120 if (pprog && ((ifile % nFileProgressQuantum) == 0))
2121 pprog->Update(
static_cast<int>(ifile * rFileProgressRatio), utf8_path);
2124 bool bAddFinal =
true;
2129 ChartCollisionsHashMap::const_iterator collision_ptr =
2130 collision_map.find(file_name);
2131 bool collision = (collision_ptr != collision_map.end());
2132 bool file_path_is_same =
false;
2133 bool file_time_is_same =
false;
2135 wxString table_file_name;
2138 pEntry = &active_chartTable[collision_ptr->second];
2139 table_file_name = pEntry->GetFullSystemPath();
2141 bthis_dir_in_dB && full_name.IsSameAs(table_file_name);
2145 if (file_path_is_same) {
2149 time_t t_oldFile = pEntry->GetFileTime();
2150 time_t t_newFile = file.GetModificationTime().GetTicks();
2152 if (t_newFile <= t_oldFile) {
2153 file_time_is_same =
true;
2155 pEntry->SetValid(
true);
2158 pEntry->SetValid(
false);
2163 wxString msg_fn(full_name);
2164 msg_fn.Replace(_T(
"%"), _T(
"%%"));
2165 if (file_time_is_same) {
2169 wxString::Format(_T(
"Loading chart data for %s"), msg_fn.c_str()));
2171 pnewChart = CreateChartTableEntry(full_name, utf8_path, chart_desc);
2174 wxLogMessage(wxString::Format(
2175 _T(
" CreateChartTableEntry() failed for file: %s"),
2180 if (!collision || !pnewChart) {
2182 }
else if (file_path_is_same) {
2184 wxString::Format(_T(
" Replacing older chart file of same path: %s"),
2186 }
else if (!file_time_is_same) {
2192 if (pnewChart->IsEarlierThan(*pEntry)) {
2193 wxFileName table_file(table_file_name);
2195 if (table_file.IsFileReadable()) {
2196 pEntry->SetValid(
true);
2198 wxLogMessage(wxString::Format(
2199 _T(
" Retaining newer chart file of same name: %s"),
2202 }
else if (pnewChart->IsEqualTo(*pEntry)) {
2210 pEntry->SetValid(
false);
2212 wxLogMessage(wxString::Format(
2213 _T(
" Replacing older chart file of same name: %s"),
2219 if (0 == b_add_msg) {
2221 wxString::Format(_T(
" Adding chart file: %s"), msg_fn.c_str()));
2223 collision_map[file_name] = active_chartTable.GetCount();
2224 active_chartTable.Add(pnewChart);
2227 if (pnewChart)
delete pnewChart;
2233 m_nentries = active_chartTable.GetCount();
2238bool ChartDatabase::AddChart(wxString &chartfilename,
2240 wxGenericProgressDialog *pprog,
int isearch,
2241 bool bthis_dir_in_dB) {
2243 wxFileName file(chartfilename);
2244 wxString full_name = file.GetFullPath();
2245 wxString file_name = file.GetFullName();
2255 pprog->Update(wxMin((m_pdifile * 100) / m_pdnFile, 100), full_name);
2258 bool bAddFinal =
true;
2260 wxString msg_fn(full_name);
2261 msg_fn.Replace(_T(
"%"), _T(
"%%"));
2263 pnewChart = CreateChartTableEntry(full_name, full_name, chart_desc);
2266 wxLogMessage(wxString::Format(
2267 _T(
" CreateChartTableEntry() failed for file: %s"), msg_fn.c_str()));
2272 int nEntry = active_chartTable.GetCount();
2273 for (
int i = 0; i < nEntry; i++) {
2274 wxString *ptable_file_name = active_chartTable[isearch].GetpsFullPath();
2278 if (bthis_dir_in_dB && full_name.IsSameAs(*ptable_file_name)) {
2282 time_t t_oldFile = active_chartTable[isearch].GetFileTime();
2283 time_t t_newFile = file.GetModificationTime().GetTicks();
2285 if (t_newFile <= t_oldFile) {
2287 active_chartTable[isearch].SetValid(
true);
2290 active_chartTable[isearch].SetValid(
false);
2291 wxLogMessage(wxString::Format(
2292 _T(
" Replacing older chart file of same path: %s"),
2302 wxFileName table_file(*ptable_file_name);
2304 if (table_file.GetFullName() == file_name) {
2307 if (pnewChart->IsEarlierThan(active_chartTable[isearch])) {
2309 if (table_file.IsFileReadable()) {
2310 active_chartTable[isearch].SetValid(
true);
2312 wxLogMessage(wxString::Format(
2313 _T(
" Retaining newer chart file of same name: %s"),
2316 }
else if (pnewChart->IsEqualTo(active_chartTable[isearch])) {
2326 active_chartTable[isearch].SetValid(
false);
2328 wxLogMessage(wxString::Format(
2329 _T(
" Replacing older chart file of same name: %s"),
2339 if (nEntry == isearch) isearch = 0;
2344 if (0 == b_add_msg) {
2346 wxString::Format(_T(
" Adding chart file: %s"), msg_fn.c_str()));
2349 active_chartTable.Add(pnewChart);
2359 m_nentries = active_chartTable.GetCount();
2364bool ChartDatabase::AddSingleChart(wxString &ChartFullPath,
2365 bool b_force_full_search) {
2367 wxFileName fn(ChartFullPath);
2368 wxString ext = fn.GetExt();
2369 ext.Prepend(_T(
"*."));
2370 wxString ext_upper = ext.MakeUpper();
2371 wxString ext_lower = ext.MakeLower();
2372 wxString dir_name = fn.GetPath();
2378 for (
unsigned int i = 0; i < m_ChartClassDescriptorArray.GetCount(); i++) {
2379 if (m_ChartClassDescriptorArray[i].m_descriptor_type == PLUGIN_DESCRIPTOR) {
2380 if (m_ChartClassDescriptorArray[i].m_search_mask == ext_upper) {
2381 desc = m_ChartClassDescriptorArray[i];
2384 if (m_ChartClassDescriptorArray[i].m_search_mask == ext_lower) {
2385 desc = m_ChartClassDescriptorArray[i];
2393 bool b_recurse =
true;
2394 if (!b_force_full_search) b_recurse = IsChartDirUsed(dir_name);
2396 bool rv = AddChart(ChartFullPath, desc, NULL, 0, b_recurse);
2400 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2401 if (!active_chartTable[i].GetbValid()) {
2402 active_chartTable.RemoveAt(i);
2408 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
2409 active_chartTable[i].SetEntryOffset(i);
2413 DetectDirChange(dir_name, _T(
""), _T(
""), new_magic, 0);
2416 bool bcfound =
false;
2417 ArrayOfCDI NewChartDirArray;
2419 ArrayOfCDI ChartDirArray = GetChartDirArray();
2420 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2426 if (newcdi.fullpath == dir_name) {
2427 newcdi.magic_number = new_magic;
2431 NewChartDirArray.Add(newcdi);
2436 cdi.fullpath = dir_name;
2437 cdi.magic_number = new_magic;
2438 NewChartDirArray.Add(cdi);
2442 SetChartDirArray(NewChartDirArray);
2445 m_chartDirs.Clear();
2447 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2449 m_chartDirs.Add(cdi.fullpath);
2452 m_nentries = active_chartTable.GetCount();
2457bool ChartDatabase::RemoveSingleChart(wxString &ChartFullPath) {
2461 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2462 if (ChartFullPath.IsSameAs(GetChartTableEntry(i).GetFullSystemPath())) {
2463 active_chartTable.RemoveAt(i);
2471 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2472 pcte = GetpChartTableEntry(i);
2473 pcte->SetEntryOffset(i);
2477 wxFileName fn(ChartFullPath);
2478 wxString fd = fn.GetPath();
2479 if (!IsChartDirUsed(fd)) {
2481 ArrayOfCDI NewChartDirArray;
2483 ArrayOfCDI ChartDirArray = GetChartDirArray();
2484 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2489 if (newcdi.fullpath != fd) NewChartDirArray.Add(newcdi);
2492 SetChartDirArray(NewChartDirArray);
2496 m_chartDirs.Clear();
2497 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2499 m_chartDirs.Add(cdi.fullpath);
2502 m_nentries = active_chartTable.GetCount();
2511ChartBase *ChartDatabase::GetChart(
const wxChar *theFilePath,
2522 const wxString &filePath, wxString &utf8Path,
2524 wxString msg_fn(filePath);
2525 msg_fn.Replace(_T(
"%"), _T(
"%%"));
2527 wxString::Format(_T(
"Loading chart data for %s"), msg_fn.c_str()));
2529 ChartBase *pch = GetChart(filePath, chart_desc);
2532 wxString::Format(_T(
" ...creation failed for %s"), msg_fn.c_str()));
2536 InitReturn rc = pch->Init(filePath, HEADER_ONLY);
2537 if (rc != INIT_OK) {
2539 wxLogMessage(wxString::Format(_T(
" ...initialization failed for %s"),
2545 ret_val->SetValid(
true);
2552bool ChartDatabase::GetCentroidOfLargestScaleChart(
double *clat,
double *clon,
2553 ChartFamilyEnum family) {
2555 int cur_max_scale = 0;
2557 int nEntry = active_chartTable.GetCount();
2559 for (
int i = 0; i < nEntry; i++) {
2560 if (GetChartFamily(active_chartTable[i].GetChartType()) == family) {
2561 if (active_chartTable[i].GetScale() > cur_max_scale) {
2562 cur_max_scale = active_chartTable[i].GetScale();
2568 if (cur_max_i == -1)
2571 *clat = (active_chartTable[cur_max_i].GetLatMax() +
2572 active_chartTable[cur_max_i].GetLatMin()) /
2574 *clon = (active_chartTable[cur_max_i].GetLonMin() +
2575 active_chartTable[cur_max_i].GetLonMax()) /
2584int ChartDatabase::GetDBChartProj(
int dbIndex) {
2585 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2586 return active_chartTable[dbIndex].GetChartProjectionType();
2588 return PROJECTION_UNKNOWN;
2594int ChartDatabase::GetDBChartFamily(
int dbIndex) {
2595 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2596 return active_chartTable[dbIndex].GetChartFamily();
2598 return CHART_FAMILY_UNKNOWN;
2604wxString ChartDatabase::GetDBChartFileName(
int dbIndex) {
2605 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2606 return wxString(active_chartTable[dbIndex].GetFullSystemPath());
2614int ChartDatabase::GetDBChartType(
int dbIndex) {
2615 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2616 return active_chartTable[dbIndex].GetChartType();
2624float ChartDatabase::GetDBChartSkew(
int dbIndex) {
2625 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2626 return active_chartTable[dbIndex].GetChartSkew();
2634int ChartDatabase::GetDBChartScale(
int dbIndex) {
2635 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2636 return active_chartTable[dbIndex].GetScale();
2644bool ChartDatabase::GetDBBoundingBox(
int dbIndex, LLBBox &box) {
2645 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2647 box.Set(entry.GetLatMin(), entry.GetLonMin(), entry.GetLatMax(),
2654const LLBBox &ChartDatabase::GetDBBoundingBox(
int dbIndex) {
2655 if ((bValid) && (dbIndex >= 0)) {
2657 return entry.GetBBox();
2659 return m_dummy_bbox;
2666int ChartDatabase::GetDBPlyPoint(
int dbIndex,
int plyindex,
float *lat,
2668 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2670 if (entry.GetnPlyEntries()) {
2671 float *fp = entry.GetpPlyTable();
2673 if (lat) *lat = *fp;
2675 if (lon) *lon = *fp;
2677 return entry.GetnPlyEntries();
2685int ChartDatabase::GetDBAuxPlyPoint(
int dbIndex,
int plyindex,
int ply,
2686 float *lat,
float *lon) {
2687 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2689 if (entry.GetnAuxPlyEntries()) {
2690 float *fp = entry.GetpAuxPlyTableEntry(ply);
2693 if (lat) *lat = *fp;
2695 if (lon) *lon = *fp;
2698 return entry.GetAuxCntTableEntry(ply);
2703int ChartDatabase::GetnAuxPlyEntries(
int dbIndex) {
2704 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2706 return entry.GetnAuxPlyEntries();
2714std::vector<float> ChartDatabase::GetReducedPlyPoints(
int dbIndex) {
2715 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2717 if (pentry)
return pentry->GetReducedPlyPoints();
2720 std::vector<float> dummy;
2727std::vector<float> ChartDatabase::GetReducedAuxPlyPoints(
int dbIndex,
2729 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2731 if (pentry)
return pentry->GetReducedAuxPlyPoints(iTable);
2734 std::vector<float> dummy;
2738bool ChartDatabase::IsChartAvailable(
int dbIndex) {
2739 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2743 if (pentry->GetChartType() != CHART_TYPE_PLUGIN)
return true;
2745 wxString *path = pentry->GetpsFullPath();
2746 wxFileName fn(*path);
2747 wxString ext = fn.GetExt();
2748 ext.Prepend(_T(
"*."));
2749 wxString ext_upper = ext.MakeUpper();
2750 wxString ext_lower = ext.MakeLower();
2755 for (
unsigned int i = 0; i < m_ChartClassDescriptorArray.GetCount(); i++) {
2756 if (m_ChartClassDescriptorArray[i].m_descriptor_type ==
2757 PLUGIN_DESCRIPTOR) {
2758 wxString search_mask = m_ChartClassDescriptorArray[i].m_search_mask;
2760 if (search_mask == ext_upper) {
2763 if (search_mask == ext_lower) {
2766 if (path->Matches(search_mask)) {
2776void ChartDatabase::ApplyGroupArray(ChartGroupArray *pGroupArray) {
2777 wxString separator(wxFileName::GetPathSeparator());
2779 for (
unsigned int ic = 0; ic < active_chartTable.GetCount(); ic++) {
2782 pcte->ClearGroupArray();
2784 wxString *chart_full_path = pcte->GetpsFullPath();
2786 for (
unsigned int igroup = 0; igroup < pGroupArray->GetCount(); igroup++) {
2787 ChartGroup *pGroup = pGroupArray->Item(igroup);
2788 for (
const auto &elem : pGroup->m_element_array) {
2789 wxString element_root = elem.m_element_name;
2795 if (!chart_full_path->IsSameAs(element_root))
2796 element_root.Append(
2798 if (chart_full_path->StartsWith(element_root)) {
2800 for (
unsigned int k = 0; k < elem.m_missing_name_array.size(); k++) {
2801 const wxString &missing_item = elem.m_missing_name_array[k];
2802 if (chart_full_path->StartsWith(missing_item)) {
2803 if (chart_full_path->IsSameAs(
2809 if (wxDir::Exists(missing_item))
2818 if (b_add) pcte->AddIntToGroupArray(igroup + 1);