33#include <wx/arrimpl.cpp>
35#include <wx/encconv.h>
36#include <wx/progdlg.h>
38#include <wx/tokenzr.h>
43#include "LOD_reduce.h"
49#define UINT32 unsigned int
53#include "androidUTIL.h"
58static int s_dbVersion;
64static ChartFamilyEnum GetChartFamily(
int charttype) {
69 cf = CHART_FAMILY_RASTER;
72 cf = CHART_FAMILY_RASTER;
75 cf = CHART_FAMILY_VECTOR;
78 cf = CHART_FAMILY_VECTOR;
80 case CHART_TYPE_CM93COMP:
81 cf = CHART_FAMILY_VECTOR;
83 case CHART_TYPE_DUMMY:
84 cf = CHART_FAMILY_RASTER;
86 case CHART_TYPE_UNKNOWN:
87 cf = CHART_FAMILY_UNKNOWN;
90 cf = CHART_FAMILY_UNKNOWN;
100void ChartTableHeader::Read(wxInputStream &is) {
104void ChartTableHeader::Write(wxOutputStream &os) {
106 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
108 memcpy(dbVersion, vb, 4);
112bool ChartTableHeader::CheckValid() {
114 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
115 if (strncmp(vb, dbVersion,
sizeof(dbVersion))) {
118 memcpy(vbo, dbVersion, 4);
120 msg.Append(wxString(vbo, wxConvUTF8));
121 msg.Prepend(
" Warning: found incorrect chart db version: ");
127 sprintf(vb,
"V%03d", DB_VERSION_PREVIOUS);
128 if (strncmp(vb, dbVersion,
sizeof(dbVersion)))
132 " Scheduling db upgrade to current db version on "
133 "Options->Charts page visit...");
140 memcpy(vbo, dbVersion, 4);
142 msg.Append(wxString(vbo, wxConvUTF8));
143 msg.Prepend(
"Loading chart db version: ");
154void ChartTableEntry::SetScale(
int scale) {
158 if (Scale >= 1000) rounding = 5 * pow(10, log10(Scale) - 2);
161ChartTableEntry::ChartTableEntry(
ChartBase &theChart, wxString &utf8Path) {
164 char *pt = (
char *)malloc(strlen(utf8Path.mb_str(wxConvUTF8)) + 1);
165 strcpy(pt, utf8Path.mb_str(wxConvUTF8));
168 SetScale(theChart.GetNativeScale());
170 ChartType = theChart.GetChartType();
171 ChartFamily = theChart.GetChartFamily();
173 Skew = theChart.GetChartSkew();
174 ProjectionType = theChart.GetChartProjectionType();
176 wxDateTime ed = theChart.GetEditionDate();
177 if (theChart.GetEditionDate().IsValid())
178 edition_date = theChart.GetEditionDate().GetTicks();
180 wxFileName fn(theChart.GetFullPath());
181 if (fn.GetModificationTime().IsValid())
182 file_date = fn.GetModificationTime().GetTicks();
184 m_pfilename =
new wxString;
185 *m_pfilename = fn.GetFullName();
186 m_psFullPath =
new wxString;
187 *m_psFullPath = utf8Path;
188 m_fullSystemPath = utf8Path;
189 m_FullPath = std::string(pFullPath);
192 m_fullSystemPath = wxString(utf8Path.mb_str(wxConvUTF8));
196 theChart.GetChartExtent(&ext);
202 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
207 double scale_max_zoom = Scale / 4;
209 double display_ppm = 1 / .00025;
210 double meters_per_pixel_max_scale = scale_max_zoom / display_ppm;
211 double LOD_meters = meters_per_pixel_max_scale * LOD_pixels;
216 if (theChart.GetCOVREntries() == 1) {
217 nPlyEntries = theChart.GetCOVRTablePoints(0);
219 if (nPlyEntries > 5 && (LOD_meters > .01)) {
220 std::vector<int> index_keep{0, nPlyEntries - 1, 1, nPlyEntries - 2};
222 double *DPbuffer = (
double *)malloc(2 * nPlyEntries *
sizeof(
double));
224 double *pfed = DPbuffer;
227 for (
int i = 0; i < nPlyEntries; i++) {
233 DouglasPeucker(DPbuffer, 1, nPlyEntries - 2, LOD_meters / (1852 * 60),
239 for (
unsigned int i = 0; i < index_keep.size(); i++) {
240 DPbuffer[2 * index_keep[i]] += 2000.;
243 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
246 for (
int i = 0; i < nPlyEntries; i++) {
247 if (DPbuffer[2 * i] > 1000.) {
248 *pfe++ = DPbuffer[2 * i] - 2000.;
249 *pfe++ = DPbuffer[(2 * i) + 1];
254 nPlyEntries = index_keep.size();
257 float *pf = (
float *)malloc(2 * nPlyEntries *
sizeof(
float));
262 for (
int i = 0; i < nPlyEntries; i++) {
274 float *pf1 = (
float *)malloc(2 * 4 *
sizeof(
float));
278 theChart.GetChartExtent(&fext);
294 nAuxPlyEntries = theChart.GetCOVREntries();
295 wxASSERT(nAuxPlyEntries);
296 float **pfp = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
298 int *pip = (
int *)malloc(nAuxPlyEntries *
sizeof(
int));
300 for (
int j = 0; j < nAuxPlyEntries; j++) {
301 int nPE = theChart.GetCOVRTablePoints(j);
303 if (nPE > 5 && (LOD_meters > .01)) {
304 std::vector<int> index_keep{0, nPE - 1, 1, nPE - 2};
306 double *DPbuffer = (
double *)malloc(2 * nPE *
sizeof(
double));
308 double *pfed = DPbuffer;
311 for (
int i = 0; i < nPE; i++) {
317 DouglasPeucker(DPbuffer, 1, nPE - 2, LOD_meters / (1852 * 60),
323 for (
unsigned int i = 0; i < index_keep.size(); i++) {
324 DPbuffer[2 * index_keep[i]] += 2000.;
327 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
330 for (
int i = 0; i < nPE; i++) {
331 if (DPbuffer[2 * i] > 1000.) {
332 *pfe1++ = DPbuffer[2 * i] - 2000.;
333 *pfe1++ = DPbuffer[(2 * i) + 1];
338 pip[j] = index_keep.size();
342 (
float *)malloc(theChart.GetCOVRTablePoints(j) * 2 *
sizeof(float));
343 memcpy(pf_entry, theChart.GetCOVRTableHead(j),
344 theChart.GetCOVRTablePoints(j) * 2 *
sizeof(
float));
346 pip[j] = theChart.GetCOVRTablePoints(j);
356 nNoCovrPlyEntries = theChart.GetNoCOVREntries();
357 if (nNoCovrPlyEntries == 0)
return;
359 float **pfpnc = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
360 float **pft0nc = pfpnc;
361 int *pipnc = (
int *)malloc(nNoCovrPlyEntries *
sizeof(
int));
363 for (
int j = 0; j < nNoCovrPlyEntries; j++) {
365 (
float *)malloc(theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(float));
366 memcpy(pf_entry, theChart.GetNoCOVRTableHead(j),
367 theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(
float));
368 pft0nc[j] = pf_entry;
369 pipnc[j] = theChart.GetNoCOVRTablePoints(j);
372 pNoCovrPlyTable = pfpnc;
373 pNoCovrCntTable = pipnc;
378ChartTableEntry::~ChartTableEntry() {
382 for (
int i = 0; i < nAuxPlyEntries; i++) free(pAuxPlyTable[i]);
386 if (nNoCovrPlyEntries) {
387 for (
int i = 0; i < nNoCovrPlyEntries; i++) free(pNoCovrPlyTable[i]);
388 free(pNoCovrPlyTable);
389 free(pNoCovrCntTable);
401 wxDateTime mine(edition_date);
402 wxDateTime theirs(cte.edition_date);
404 if (!mine.IsValid() || !theirs.IsValid())
407 return (mine.IsEarlierThan(theirs));
411 wxDateTime mine(edition_date);
412 wxDateTime theirs(cte.edition_date);
414 if (!mine.IsValid() || !theirs.IsValid())
417 return (mine.IsEqualTo(theirs));
422static int convertChartType(
int charttype) {
425 if (s_dbVersion == 14) {
428 return CHART_TYPE_KAP;
430 return CHART_TYPE_GEO;
432 return CHART_TYPE_S57;
434 return CHART_TYPE_CM93;
436 return CHART_TYPE_CM93COMP;
438 return CHART_TYPE_UNKNOWN;
440 return CHART_TYPE_DONTCARE;
442 return CHART_TYPE_DUMMY;
444 return CHART_TYPE_UNKNOWN;
450static int convertChartFamily(
int charttype,
int chartfamily) {
451 if (s_dbVersion < 18) {
455 return CHART_FAMILY_RASTER;
458 case CHART_TYPE_CM93:
459 case CHART_TYPE_CM93COMP:
460 return CHART_FAMILY_VECTOR;
463 return CHART_FAMILY_UNKNOWN;
469bool ChartTableEntry::Read(
const ChartDatabase *pDb, wxInputStream &is) {
470 char path[4096], *cp;
476 int db_version = pD->GetVersion();
478 if (db_version == 18) {
480 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
481 pFullPath = (
char *)malloc(cp - path + 1);
482 strncpy(pFullPath, path, cp - path + 1);
483 wxLogVerbose(
" Chart %s", pFullPath);
486 m_pfilename =
new wxString;
487 wxString fullfilename(pFullPath, wxConvUTF8);
488 wxFileName fn(fullfilename);
489 *m_pfilename = fn.GetFullName();
490 m_psFullPath =
new wxString;
491 *m_psFullPath = fullfilename;
492 m_fullSystemPath = fullfilename;
493 m_FullPath = std::string(pFullPath);
496 m_fullSystemPath = wxString(fullfilename.mb_str(wxConvUTF8));
503 EntryOffset = cte.EntryOffset;
504 ChartType = cte.ChartType;
505 ChartFamily = cte.ChartFamily;
511 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
514 ProjectionType = cte.ProjectionType;
517 edition_date = cte.edition_date;
518 file_date = cte.file_date;
520 nPlyEntries = cte.nPlyEntries;
521 nAuxPlyEntries = cte.nAuxPlyEntries;
523 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
528 int npeSize = nPlyEntries * 2 *
sizeof(float);
529 pPlyTable = (
float *)malloc(npeSize);
530 is.Read(pPlyTable, npeSize);
533 if (nAuxPlyEntries) {
534 int napeSize = nAuxPlyEntries *
sizeof(int);
535 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
536 pAuxCntTable = (
int *)malloc(napeSize);
537 is.Read(pAuxCntTable, napeSize);
539 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
541 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
542 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
543 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
547 if (nNoCovrPlyEntries) {
548 int napeSize = nNoCovrPlyEntries *
sizeof(int);
549 pNoCovrCntTable = (
int *)malloc(napeSize);
550 is.Read(pNoCovrCntTable, napeSize);
552 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
553 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
554 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
555 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
556 is.Read(pNoCovrPlyTable[i], nfSize);
561 else if (db_version == 17) {
563 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
564 pFullPath = (
char *)malloc(cp - path + 1);
565 strncpy(pFullPath, path, cp - path + 1);
566 wxLogVerbose(
" Chart %s", pFullPath);
569 m_pfilename =
new wxString;
570 wxString fullfilename(pFullPath, wxConvUTF8);
571 wxFileName fn(fullfilename);
572 *m_pfilename = fn.GetFullName();
573 m_psFullPath =
new wxString;
574 *m_psFullPath = fullfilename;
575 m_FullPath = std::string(pFullPath);
582 EntryOffset = cte.EntryOffset;
583 ChartType = cte.ChartType;
589 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
592 ProjectionType = cte.ProjectionType;
595 edition_date = cte.edition_date;
596 file_date = cte.file_date;
598 nPlyEntries = cte.nPlyEntries;
599 nAuxPlyEntries = cte.nAuxPlyEntries;
601 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
606 int npeSize = nPlyEntries * 2 *
sizeof(float);
607 pPlyTable = (
float *)malloc(npeSize);
608 is.Read(pPlyTable, npeSize);
611 if (nAuxPlyEntries) {
612 int napeSize = nAuxPlyEntries *
sizeof(int);
613 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
614 pAuxCntTable = (
int *)malloc(napeSize);
615 is.Read(pAuxCntTable, napeSize);
617 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
619 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
620 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
621 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
625 if (nNoCovrPlyEntries) {
626 int napeSize = nNoCovrPlyEntries *
sizeof(int);
627 pNoCovrCntTable = (
int *)malloc(napeSize);
628 is.Read(pNoCovrCntTable, napeSize);
630 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
631 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
632 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
633 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
634 is.Read(pNoCovrPlyTable[i], nfSize);
639 else if (db_version == 16) {
641 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
643 pFullPath = (
char *)malloc(cp - path + 1);
644 strncpy(pFullPath, path, cp - path + 1);
645 wxLogVerbose(
" Chart %s", pFullPath);
648 m_pfilename =
new wxString;
649 wxString fullfilename(pFullPath, wxConvUTF8);
650 wxFileName fn(fullfilename);
651 *m_pfilename = fn.GetFullName();
652 m_psFullPath =
new wxString;
653 *m_psFullPath = fullfilename;
654 m_FullPath = std::string(pFullPath);
661 EntryOffset = cte.EntryOffset;
662 ChartType = cte.ChartType;
668 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
671 ProjectionType = cte.ProjectionType;
674 edition_date = cte.edition_date;
675 file_date = cte.file_date;
677 nPlyEntries = cte.nPlyEntries;
678 nAuxPlyEntries = cte.nAuxPlyEntries;
683 int npeSize = nPlyEntries * 2 *
sizeof(float);
684 pPlyTable = (
float *)malloc(npeSize);
685 is.Read(pPlyTable, npeSize);
688 if (nAuxPlyEntries) {
689 int napeSize = nAuxPlyEntries *
sizeof(int);
690 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
691 pAuxCntTable = (
int *)malloc(napeSize);
692 is.Read(pAuxCntTable, napeSize);
694 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
696 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
697 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
698 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
703 else if (db_version == 15) {
705 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
707 pFullPath = (
char *)malloc(cp - path + 1);
708 strncpy(pFullPath, path, cp - path + 1);
709 wxLogVerbose(
" Chart %s", pFullPath);
716 EntryOffset = cte.EntryOffset;
717 ChartType = cte.ChartType;
723 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
726 edition_date = cte.edition_date;
727 file_date = cte.file_date;
729 nPlyEntries = cte.nPlyEntries;
730 nAuxPlyEntries = cte.nAuxPlyEntries;
735 int npeSize = nPlyEntries * 2 *
sizeof(float);
736 pPlyTable = (
float *)malloc(npeSize);
737 is.Read(pPlyTable, npeSize);
740 if (nAuxPlyEntries) {
741 int napeSize = nAuxPlyEntries *
sizeof(int);
742 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
743 pAuxCntTable = (
int *)malloc(napeSize);
744 is.Read(pAuxCntTable, napeSize);
746 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
748 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
749 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
750 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
753 }
else if (db_version == 14) {
755 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
756 pFullPath = (
char *)malloc(cp - path + 1);
757 strncpy(pFullPath, path, cp - path + 1);
758 wxLogVerbose(
" Chart %s", pFullPath);
765 EntryOffset = cte.EntryOffset;
766 ChartType = cte.ChartType;
772 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
775 edition_date = cte.edition_date;
777 nPlyEntries = cte.nPlyEntries;
778 nAuxPlyEntries = cte.nAuxPlyEntries;
782 int npeSize = nPlyEntries * 2 *
sizeof(float);
783 pPlyTable = (
float *)malloc(npeSize);
784 is.Read(pPlyTable, npeSize);
787 if (nAuxPlyEntries) {
788 int napeSize = nAuxPlyEntries *
sizeof(int);
789 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
790 pAuxCntTable = (
int *)malloc(napeSize);
791 is.Read(pAuxCntTable, napeSize);
793 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
795 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
796 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
797 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
801 ChartFamily = convertChartFamily(ChartType, ChartFamily);
802 ChartType = convertChartType(ChartType);
809bool ChartTableEntry::Write(
const ChartDatabase *pDb, wxOutputStream &os) {
810 os.Write(pFullPath, strlen(pFullPath) + 1);
817 cte.EntryOffset = EntryOffset;
818 cte.ChartType = ChartType;
819 cte.ChartFamily = ChartFamily;
826 cte.edition_date = edition_date;
827 cte.file_date = file_date;
829 cte.nPlyEntries = nPlyEntries;
830 cte.nAuxPlyEntries = nAuxPlyEntries;
833 cte.ProjectionType = ProjectionType;
837 cte.nNoCovrPlyEntries = nNoCovrPlyEntries;
840 wxLogVerbose(
" Wrote Chart %s", pFullPath);
844 int npeSize = nPlyEntries * 2 *
sizeof(float);
845 os.Write(pPlyTable, npeSize);
848 if (nAuxPlyEntries) {
849 int napeSize = nAuxPlyEntries *
sizeof(int);
850 os.Write(pAuxCntTable, napeSize);
852 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries; nAuxPlyEntry++) {
853 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
854 os.Write(pAuxPlyTable[nAuxPlyEntry], nfSize);
858 if (nNoCovrPlyEntries) {
859 int ncSize = nNoCovrPlyEntries *
sizeof(int);
860 os.Write(pNoCovrCntTable, ncSize);
862 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
863 int nctSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
864 os.Write(pNoCovrPlyTable[i], nctSize);
873void ChartTableEntry::Clear() {
882 pNoCovrCntTable = NULL;
883 pNoCovrPlyTable = NULL;
885 nNoCovrPlyEntries = 0;
894void ChartTableEntry::Disable() {
898 LatMax += (float)1000.;
899 LatMin += (float)1000.;
902void ChartTableEntry::ReEnable() {
904 LatMax -= (float)1000.;
905 LatMin -= (float)1000.;
909std::vector<float> ChartTableEntry::GetReducedPlyPoints() {
910 if (m_reducedPlyPoints.size())
return m_reducedPlyPoints;
913 float LOD_meters = 1;
915 float plylat, plylon;
916 const int nPoints = GetnPlyEntries();
918 float *fpo = GetpPlyTable();
920 double *ppd =
new double[nPoints * 2];
921 double *ppsm =
new double[nPoints * 2];
924 for (
int i = 0; i < nPoints; i++) {
926 plylon = fpo[i * 2 + 1];
929 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
937 std::vector<int> index_keep;
939 index_keep.push_back(0);
940 index_keep.push_back(nPoints - 1);
941 index_keep.push_back(1);
942 index_keep.push_back(nPoints - 2);
944 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
947 index_keep.resize(nPoints);
948 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
952 for (
int ip = 0; ip < nPoints; ip++) {
956 for (
unsigned int j = 0; j < index_keep.size(); j++) {
957 if (index_keep[j] == ip) {
958 m_reducedPlyPoints.push_back(x);
959 m_reducedPlyPoints.push_back(y);
968 int nprr = m_reducedPlyPoints.size() / 2;
970 return m_reducedPlyPoints;
973std::vector<float> ChartTableEntry::GetReducedAuxPlyPoints(
int iTable) {
975 if (!m_reducedAuxPlyPointsVector.size()) {
976 std::vector<float> vec;
977 for (
int i = 0; i < GetnAuxPlyEntries(); i++) {
978 m_reducedAuxPlyPointsVector.push_back(vec);
982 std::vector<float> vec;
985 if ((
unsigned int)iTable >= m_reducedAuxPlyPointsVector.size())
return vec;
987 if (m_reducedAuxPlyPointsVector.at(iTable).size())
988 return m_reducedAuxPlyPointsVector.at(iTable);
991 float LOD_meters = 1.0;
993 const int nPoints = GetAuxCntTableEntry(iTable);
994 float *fpo = GetpAuxPlyTableEntry(iTable);
996 double *ppd =
new double[nPoints * 2];
997 double *ppsm =
new double[nPoints * 2];
1000 float plylat, plylon;
1002 for (
int i = 0; i < nPoints; i++) {
1003 plylat = fpo[i * 2];
1004 plylon = fpo[i * 2 + 1];
1007 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
1015 std::vector<int> index_keep;
1017 index_keep.push_back(0);
1018 index_keep.push_back(nPoints - 1);
1019 index_keep.push_back(1);
1020 index_keep.push_back(nPoints - 2);
1022 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
1025 index_keep.resize(nPoints);
1026 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
1029 int nnn = index_keep.size();
1032 for (
int ip = 0; ip < nPoints; ip++) {
1036 for (
unsigned int j = 0; j < index_keep.size(); j++) {
1037 if (index_keep[j] == ip) {
1048 m_reducedAuxPlyPointsVector[iTable] = vec;
1050 int nprr = vec.size() / 2;
1059WX_DEFINE_OBJARRAY(ChartTable);
1061ChartDatabase::ChartDatabase() {
1065 m_ChartTableEntryDummy.Clear();
1067 UpdateChartClassDescriptorArray();
1070void ChartDatabase::UpdateChartClassDescriptorArray() {
1071 if (m_ChartClassDescriptorArray.empty()) {
1072 m_ChartClassDescriptorArray.push_back(
1074 m_ChartClassDescriptorArray.push_back(
1076 m_ChartClassDescriptorArray.push_back(
1078 m_ChartClassDescriptorArray.push_back(
1081 "cm93compchart",
"00300000.a", BUILTIN_DESCRIPTOR));
1082 m_ChartClassDescriptorArray.push_back(
1088 m_ChartClassDescriptorArray.erase(
1089 std::remove_if(m_ChartClassDescriptorArray.begin(),
1090 m_ChartClassDescriptorArray.end(),
1092 return cd.m_descriptor_type == PLUGIN_DESCRIPTOR;
1094 m_ChartClassDescriptorArray.end());
1096 wxArrayString array =
g_pi_manager->GetPlugInChartClassNameArray();
1097 for (
unsigned int j = 0; j < array.GetCount(); j++) {
1100 wxString class_name = array[j];
1103 wxString mask = cpiw->GetFileSearchMask();
1106 m_ChartClassDescriptorArray.push_back(
1114const ChartTableEntry &ChartDatabase::GetChartTableEntry(
int index)
const {
1115 if (index < GetChartTableEntries())
1116 return active_chartTable[index];
1118 return m_ChartTableEntryDummy;
1122 if (index < GetChartTableEntries())
1123 return &active_chartTable[index];
1128bool ChartDatabase::CompareChartDirArray(ArrayOfCDI &test_array) {
1132 if (test_array.GetCount() != m_dir_array.GetCount())
return false;
1135 unsigned int nfound_outer = 0;
1137 for (
unsigned int i = 0; i < test_array.GetCount(); i++) {
1139 bfound_inner =
false;
1140 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1143 if (p.fullpath.IsSameAs(q.fullpath)) {
1144 bfound_inner =
true;
1148 if (bfound_inner) nfound_outer++;
1151 return (nfound_outer == test_array.GetCount());
1154wxString ChartDatabase::GetMagicNumberCached(wxString dir) {
1155 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1157 if (dir.IsSameAs(q.fullpath))
return q.magic_number;
1163bool ChartDatabase::Read(
const wxString &filePath) {
1169 wxFileName file(filePath);
1170 if (!file.FileExists())
return false;
1172 m_DBFileName = filePath;
1174 wxFFileInputStream ifs(filePath);
1175 if (!ifs.Ok())
return false;
1179 if (!cth.CheckValid())
return false;
1183 memcpy(vbo, cth.GetDBVersionString(), 4);
1185 m_dbversion = atoi(&vbo[1]);
1186 s_dbVersion = m_dbversion;
1188 wxLogVerbose(
"Chartdb:Reading %d directory entries, %d table entries",
1189 cth.GetDirEntries(), cth.GetTableEntries());
1190 wxLogMessage(
"Chartdb: Chart directory list follows");
1191 if (0 == cth.GetDirEntries()) wxLogMessage(
" Nil");
1194 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1197 ifs.Read(&dirlen,
sizeof(
int));
1198 while (dirlen > 0) {
1200 int alen = dirlen > 1023 ? 1023 : dirlen;
1201 if (ifs.Read(&dirbuf, alen).Eof())
goto read_error;
1204 dir.Append(wxString(dirbuf, wxConvUTF8));
1207 msg.Printf(
" Chart directory #%d: ", iDir);
1210 m_chartDirs.Add(dir);
1213 entries = cth.GetTableEntries();
1214 active_chartTable.Alloc(entries);
1215 active_chartTable_pathindex.clear();
1216 while (entries-- && entry.Read(
this, ifs)) {
1217 active_chartTable_pathindex[entry.GetFullSystemPath()] = ind++;
1218 active_chartTable.Add(entry);
1223 entry.SetAvailable(
true);
1225 m_nentries = active_chartTable.GetCount();
1230 m_nentries = active_chartTable.GetCount();
1236bool ChartDatabase::Write(
const wxString &filePath) {
1237 wxFileName file(filePath);
1239 file.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME, wxPATH_NATIVE));
1241 if (!dir.DirExists() && !dir.Mkdir())
return false;
1243 wxFFileOutputStream ofs(filePath);
1244 if (!ofs.Ok())
return false;
1246 ChartTableHeader cth(m_chartDirs.GetCount(), active_chartTable.GetCount());
1249 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1250 wxString dir1 = m_chartDirs[iDir];
1251 int dirlen = dir1.length();
1253 strncpy(s, dir1.mb_str(wxConvUTF8), 199);
1256 ofs.Write(&dirlen,
sizeof(
int));
1258 ofs.Write(s, dirlen);
1261 for (UINT32 iTable = 0; iTable < active_chartTable.size(); iTable++)
1262 active_chartTable[iTable].Write(
this, ofs);
1265 m_dbversion = DB_VERSION_CURRENT;
1271wxString SplitPath(wxString s, wxString tkd,
int nchar,
int offset,
1277 wxStringTokenizer tkz(s, tkd);
1278 while (tkz.HasMoreTokens()) {
1279 wxString token = tkz.GetNextToken();
1280 if ((rlen + (
int)token.Len() + 1) < nchar) {
1283 rlen += token.Len() + 1;
1287 for (
int i = 0; i < offset; i++) {
1292 rlen = offset + token.Len() + 1;
1296 if (pn_split) *pn_split = ncr;
1298 return r.Mid(0, r.Len() - 1);
1301wxString ChartDatabase::GetFullChartInfo(
ChartBase *pc,
int dbIndex,
1302 int *char_width,
int *line_count) {
1305 unsigned int max_width = 0;
1307 unsigned int target_width = 60;
1313 line = _(
" Name: ");
1314 wxString longline = pc->GetName();
1317 if (longline.Find(
' ') != wxNOT_FOUND)
1322 if (longline.Len() > target_width) {
1323 line += SplitPath(pc->GetName(), tkz, target_width, 12, &ncr);
1324 max_width = wxMax(max_width, target_width + 4);
1328 max_width = wxMax(max_width, line.Len() + 4);
1337 line.Printf(
" %s: 1:%d", _(
"Scale"), pc->GetNativeScale());
1339 line.Printf(
" %s: 1:%d", _(
"Scale"), cte.GetScale());
1342 max_width = wxMax(max_width, line.Len());
1346 wxDateTime ed = pc->GetEditionDate();
1348 line = _(
" Updated: ") + ed.FormatISODate() +
"\n";
1349 max_width = wxMax(max_width, line.Len());
1354 line = _(
" Source Edition: ") + pc->GetSE() +
"\n";
1355 max_width = wxMax(max_width, line.Len());
1361 line = _(
" Depth Units: ") + pc->GetDepthUnits() +
"\n";
1362 max_width = wxMax(max_width, line.Len());
1366 line = _(
" Soundings: ") + pc->GetSoundingsDatum() +
"\n";
1367 max_width = wxMax(max_width, line.Len());
1371 line = _(
" Datum: ") + pc->GetDatumString() +
"\n";
1372 max_width = wxMax(max_width, line.Len());
1377 line = _(
" Projection: ");
1378 if (PROJECTION_UNKNOWN == cte.GetChartProjectionType())
1379 line += _(
"Unknown");
1380 else if (PROJECTION_MERCATOR == cte.GetChartProjectionType())
1381 line += _(
"Mercator");
1382 else if (PROJECTION_TRANSVERSE_MERCATOR == cte.GetChartProjectionType())
1383 line += _(
"Transverse Mercator");
1384 else if (PROJECTION_POLYCONIC == cte.GetChartProjectionType())
1385 line += _(
"Polyconic");
1386 else if (PROJECTION_WEB_MERCATOR == cte.GetChartProjectionType())
1387 line += _(
"Web Mercator (EPSG:3857)");
1389 max_width = wxMax(max_width, line.Len());
1398 if (pc && pc->GetExtraInfo().Len()) {
1399 line += pc->GetExtraInfo();
1401 max_width = wxMax(max_width, line.Len());
1408 line += pc->GetID();
1410 max_width = wxMax(max_width, line.Len());
1415 line = _(
" ChartFile: ");
1416 wxString longline = *(cte.GetpsFullPath());
1417 if (longline.Len() > target_width) {
1418 line += SplitPath(longline,
"/,\\", target_width, 15, &ncr);
1419 max_width = wxMax(max_width, target_width + 4);
1423 max_width = wxMax(max_width, line.Len() + 4);
1429 if (line_count) *line_count = lc;
1431 if (char_width) *char_width = max_width;
1441 wxGenericProgressDialog *pprog) {
1442 m_dir_array = dir_array;
1446 m_chartDirs.Clear();
1447 active_chartTable.Clear();
1448 active_chartTable_pathindex.clear();
1450 Update(dir_array,
true, pprog);
1455 m_dbversion = DB_VERSION_CURRENT;
1467 virtual wxDirTraverseResult OnFile(
const wxString &filename)
override {
1468 wxFileName fn(filename);
1469 wxFileName dir(fn.GetPath());
1470 if (fn.GetFullName().Matches(
"poly-*-1.dat") &&
1471 dir.GetFullName().IsSameAs(
"GSHHG",
false)) {
1472 parent_dir = fn.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
1475 return wxDIR_CONTINUE;
1477 virtual wxDirTraverseResult OnDir(
const wxString &dirname)
override {
1479 return wxDIR_CONTINUE;
1481 wxString GetGshhsDir()
const {
return parent_dir; }
1484 wxString parent_dir;
1491wxString findGshhgDirectory(
const wxString &directory) {
1492 wxDir dir(directory);
1493 if (!dir.IsOpened()) {
1494 return wxEmptyString;
1497 dir.Traverse(traverser, wxEmptyString, wxDIR_FILES | wxDIR_DIRS);
1498 return traverser.GetGshhsDir();
1506 wxGenericProgressDialog *pprog) {
1507 m_dir_array = dir_array;
1513 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
1514 active_chartTable[i].SetValid(
false);
1516 m_chartDirs.Clear();
1518 if (bForce) active_chartTable.Clear();
1520 bool lbForce = bForce;
1523 if (s_dbVersion != DB_VERSION_CURRENT) {
1524 active_chartTable.Clear();
1526 s_dbVersion = DB_VERSION_CURRENT;
1527 m_dbversion = DB_VERSION_CURRENT;
1532 for (
unsigned int j = 0; j < dir_array.GetCount(); j++) {
1539 if (!androidIsDirWritable(dir_info.fullpath))
continue;
1545 wxString gshhg_dir = findGshhgDirectory(dir_info.fullpath);
1546 if (!gshhg_dir.empty()) {
1551 wxLogMessage(
"Updating GSHHG directory: %s", gshhg_dir.c_str());
1552 gWorldMapLocation = gshhg_dir;
1554 if (dir_info.fullpath.Find(
"OSMSHP") != wxNOT_FOUND) {
1555 if (!wxDir::FindFirst(dir_info.fullpath,
"basemap_*.shp").empty()) {
1556 gWorldShapefileLocation =
1557 dir_info.fullpath + wxFileName::GetPathSeparator();
1562 TraverseDirAndAddCharts(dir_info, pprog, dir_magic, lbForce);
1566 dir_info.magic_number = dir_magic;
1567 dir_array.RemoveAt(j);
1568 dir_array.Insert(dir_info, j);
1570 m_chartDirs.Add(dir_info.fullpath);
1573 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1574 if (!active_chartTable[i].GetbValid()) {
1575 active_chartTable.RemoveAt(i);
1581 active_chartTable_pathindex.clear();
1582 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1583 active_chartTable_pathindex[active_chartTable[i].GetFullSystemPath()] = i;
1584 active_chartTable[i].SetEntryOffset(i);
1587 m_nentries = active_chartTable.GetCount();
1598int ChartDatabase::FinddbIndex(wxString PathToFind) {
1601 for(
unsigned int i=0 ; i<active_chartTable.GetCount() ; i++)
1603 if(active_chartTable[i].GetpsFullPath()->IsSameAs(PathToFind))
1609 if (active_chartTable_pathindex.find(PathToFind) !=
1610 active_chartTable_pathindex.end())
1611 return active_chartTable_pathindex[PathToFind];
1621int ChartDatabase::DisableChart(wxString &PathToDisable) {
1622 int index = FinddbIndex(PathToDisable);
1638int ChartDatabase::TraverseDirAndAddCharts(
ChartDirInfo &dir_info,
1639 wxGenericProgressDialog *pprog,
1640 wxString &dir_magic,
bool bForce) {
1642 wxString dir_path = dir_info.fullpath;
1644 dir_path = wxString(dir_info.fullpath.mb_str(wxConvUTF8));
1647 wxString old_magic = dir_info.magic_number;
1648 wxString new_magic = old_magic;
1649 dir_magic = old_magic;
1653 bool b_skipDetectDirChange =
false;
1654 bool b_dirchange =
false;
1657 if (!wxDir::Exists(dir_path))
return 0;
1663 bool b_cm93 = Check_CM93_Structure(dir_path);
1665 b_skipDetectDirChange =
true;
1671 if (!b_skipDetectDirChange)
1672 b_dirchange = DetectDirChange(dir_path, dir_info.fullpath, old_magic,
1675 if (!bForce && !b_dirchange) {
1676 wxString msg(
" No change detected on directory ");
1677 msg.Append(dir_path);
1683 wxFileName fn_dir(dir_path,
"stuff");
1684 unsigned int dir_path_count = fn_dir.GetDirCount();
1686 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Scan...."));
1688 int nEntries = active_chartTable.GetCount();
1690 for (
int ic = 0; ic < nEntries; ic++) {
1691 wxFileName fn(active_chartTable[ic].GetFullSystemPath());
1693 while (fn.GetDirCount() >= dir_path_count) {
1694 if (fn.GetPath() == dir_path) {
1695 active_chartTable[ic].SetValid(
true);
1711 dir_magic = new_magic;
1714 for (
auto &cd : m_ChartClassDescriptorArray) {
1715 nAdd += SearchDirAndAddCharts(dir_info.fullpath, cd, pprog);
1721bool ChartDatabase::DetectDirChange(
const wxString &dir_path,
1722 const wxString &prog_label,
1723 const wxString &magic, wxString &new_magic,
1724 wxGenericProgressDialog *pprog) {
1725 if (pprog) pprog->SetTitle(_(
"OpenCPN Directory Scan...."));
1728 long long unsigned int nmagic;
1729 wxULongLong nacc = 0;
1731 magic.ToULongLong(&nmagic, 10);
1734 wxArrayString FileList;
1735 wxDir dir(dir_path);
1736 int n_files = dir.GetAllFiles(dir_path, &FileList);
1744 for (
int ifile = 0; ifile < n_files; ifile++) {
1745 if (pprog && (ifile % (n_files / 60 + 1)) == 0)
1746 pprog->Update(wxMin((ifile * 100) / n_files, 100), prog_label);
1748 wxFileName file(FileList[ifile]);
1753 wxString fileNameNative = file.GetFullPath();
1754 wxScopedCharBuffer fileNameUTF8 = fileNameNative.ToUTF8();
1755 hash.Update(fileNameUTF8.data(), fileNameUTF8.length());
1758 wxULongLong size = file.GetSize();
1759 wxULongLong fileSize = ((size != wxInvalidSize) ? size : 0);
1760 hash.Update(&fileSize, (
sizeof fileSize));
1763 wxDateTime t = file.GetModificationTime();
1764 wxULongLong fileTime = t.GetTicks();
1765 hash.Update(&fileTime, (
sizeof fileTime));
1769 hash.Receive(&nacc);
1772 new_magic = nacc.ToString();
1775 if (new_magic != magic)
1781bool ChartDatabase::IsChartDirUsed(
const wxString &theDir) {
1782 wxString dir(theDir);
1783 if (dir.Last() ==
'/' || dir.Last() == wxFileName::GetPathSeparator())
1787 for (UINT32 i = 0; i < active_chartTable.GetCount(); i++) {
1788 if (active_chartTable[i].GetpsFullPath()->Matches(dir))
return true;
1797bool ChartDatabase::Check_CM93_Structure(wxString dir_name) {
1800 wxRegEx test(
"[0-9]+");
1802 wxDir dirt(dir_name);
1805 if (dirt.IsOpened())
1806 wxLogMessage(
"check_cm93 opened dir OK: " + dir_name);
1808 wxLogMessage(
"check_cm93 NOT OPENED OK: " + dir_name);
1809 wxLogMessage(
"check_cm93 returns false." + dir_name);
1813 bool b_maybe_found_cm93 =
false;
1814 bool b_cont = dirt.GetFirst(&candidate);
1817 if (test.Matches(candidate) && (candidate.Len() == 8)) {
1818 b_maybe_found_cm93 =
true;
1822 b_cont = dirt.GetNext(&candidate);
1825 if (b_maybe_found_cm93) {
1826 wxString dir_next = dir_name;
1828 dir_next += candidate;
1829 if (wxDir::Exists(dir_next)) {
1830 wxDir dir_n(dir_next);
1831 if (dirt.IsOpened()) {
1832 wxString candidate_n;
1834 wxRegEx test_n(
"^[A-Ga-g]");
1835 bool b_probably_found_cm93 =
false;
1836 bool b_cont_n = dir_n.IsOpened() && dir_n.GetFirst(&candidate_n);
1838 if (test_n.Matches(candidate_n) && (candidate_n.Len() == 1)) {
1839 b_probably_found_cm93 =
true;
1842 b_cont_n = dir_n.GetNext(&candidate_n);
1845 if (b_probably_found_cm93)
1850 wxString dir_luk = dir_next;
1852 dir_luk += candidate_n;
1853 if (wxDir::Exists(dir_luk))
return true;
1972WX_DECLARE_STRING_HASH_MAP(
int, ChartCollisionsHashMap);
1974int ChartDatabase::SearchDirAndAddCharts(wxString &dir_name_base,
1976 wxGenericProgressDialog *pprog) {
1977 wxString msg(
"Searching directory: ");
1978 msg += dir_name_base;
1980 msg += chart_desc.m_search_mask;
1983 wxString dir_name = dir_name_base;
1986 dir_name = wxString(dir_name_base.mb_str(wxConvUTF8));
1989 if (!wxDir::Exists(dir_name))
return 0;
1991 wxString filespec = chart_desc.m_search_mask.Upper();
1992 wxString lowerFileSpec = chart_desc.m_search_mask.Lower();
1993 wxString filespecXZ = filespec +
".xz";
1994 wxString lowerFileSpecXZ = lowerFileSpec +
".xz";
1998 wxArrayString FileList;
1999 int gaf_flags = wxDIR_DEFAULT;
2006 bool b_found_cm93 =
false;
2007 bool b_cm93 = Check_CM93_Structure(dir_name);
2009 if (filespec !=
"00300000.A")
2012 filespec = dir_name;
2013 b_found_cm93 =
true;
2017 if (!b_found_cm93) {
2018 wxDir dir(dir_name);
2019 dir.GetAllFiles(dir_name, &FileList, filespec, gaf_flags);
2022 if (!FileList.GetCount()) {
2023 wxArrayString afl = androidTraverseDir(dir_name, filespec);
2024 for (wxArrayString::const_iterator item = afl.begin(); item != afl.end();
2026 FileList.Add(*item);
2031 if (filespec != lowerFileSpec) {
2033 wxArrayString lowerFileList;
2034 dir.GetAllFiles(dir_name, &lowerFileList, lowerFileSpec, gaf_flags);
2037 if (!lowerFileList.GetCount()) {
2038 wxArrayString afl = androidTraverseDir(dir_name, lowerFileSpec);
2039 for (wxArrayString::const_iterator item = afl.begin();
2040 item != afl.end(); item++)
2041 lowerFileList.Add(*item);
2045 for (wxArrayString::const_iterator item = lowerFileList.begin();
2046 item != lowerFileList.end(); item++)
2047 FileList.Add(*item);
2053 dir.GetAllFiles(dir_name, &FileList, filespecXZ, gaf_flags);
2054 dir.GetAllFiles(dir_name, &FileList, lowerFileSpecXZ, gaf_flags);
2060 wxString dir_plus = dir_name;
2061 dir_plus += wxFileName::GetPathSeparator();
2062 FileList.Add(dir_plus);
2065 int nFile = FileList.GetCount();
2067 if (!nFile)
return false;
2074 bool bthis_dir_in_dB = IsChartDirUsed(dir_name);
2076 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Add...."));
2080 ChartCollisionsHashMap collision_map;
2081 int nEntry = active_chartTable.GetCount();
2082 for (
int i = 0; i < nEntry; i++) {
2083 wxString table_file_name = active_chartTable[i].GetFullSystemPath();
2084 wxFileName table_file(table_file_name);
2085 collision_map[table_file.GetFullName()] = i;
2088 int nFileProgressQuantum = wxMax(nFile / 100, 2);
2089 double rFileProgressRatio = 100.0 / wxMax(nFile, 1);
2091 for (
int ifile = 0; ifile < nFile; ifile++) {
2092 wxFileName file(FileList[ifile]);
2093 wxString full_name = file.GetFullPath();
2094 wxString file_name = file.GetFullName();
2095 wxString utf8_path = full_name;
2103 wxFileName fnbase(dir_name_base);
2104 int nDirs = fnbase.GetDirCount();
2106 wxFileName file_target(FileList[ifile]);
2108 for (
int i = 0; i < nDirs + 1;
2110 file_target.RemoveDir(0);
2112 wxString leftover_path = file_target.GetFullPath();
2114 dir_name_base + leftover_path;
2120 if (!file_name.Matches(lowerFileSpec) && !file_name.Matches(filespec) &&
2121 !file_name.Matches(lowerFileSpecXZ) && !file_name.Matches(filespecXZ) &&
2127 if (pprog && ((ifile % nFileProgressQuantum) == 0))
2128 pprog->Update(
static_cast<int>(ifile * rFileProgressRatio), utf8_path);
2131 bool bAddFinal =
true;
2136 ChartCollisionsHashMap::const_iterator collision_ptr =
2137 collision_map.find(file_name);
2138 bool collision = (collision_ptr != collision_map.end());
2139 bool file_path_is_same =
false;
2140 bool file_time_is_same =
false;
2142 wxString table_file_name;
2145 if (b_found_cm93) collision =
false;
2148 pEntry = &active_chartTable[collision_ptr->second];
2149 table_file_name = pEntry->GetFullSystemPath();
2151 bthis_dir_in_dB && full_name.IsSameAs(table_file_name);
2155 if (file_path_is_same) {
2159 time_t t_oldFile = pEntry->GetFileTime();
2160 time_t t_newFile = file.GetModificationTime().GetTicks();
2162 if (t_newFile <= t_oldFile) {
2163 file_time_is_same =
true;
2165 pEntry->SetValid(
true);
2168 pEntry->SetValid(
false);
2173 wxString msg_fn(full_name);
2174 msg_fn.Replace(
"%",
"%%");
2175 if (file_time_is_same) {
2179 wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
2181 pnewChart = CreateChartTableEntry(full_name, utf8_path, chart_desc);
2184 wxLogMessage(wxString::Format(
2185 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2189 if (!collision || !pnewChart) {
2191 }
else if (file_path_is_same) {
2192 wxLogMessage(wxString::Format(
2193 " Replacing older chart file of same path: %s", msg_fn.c_str()));
2194 }
else if (!file_time_is_same) {
2200 if (pnewChart->IsEarlierThan(*pEntry)) {
2201 wxFileName table_file(table_file_name);
2203 if (table_file.IsFileReadable()) {
2204 pEntry->SetValid(
true);
2207 wxString::Format(
" Retaining newer chart file of same name: %s",
2210 }
else if (pnewChart->IsEqualTo(*pEntry)) {
2218 pEntry->SetValid(
false);
2220 wxLogMessage(wxString::Format(
2221 " Replacing older chart file of same name: %s", msg_fn.c_str()));
2226 if (0 == b_add_msg) {
2228 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2230 collision_map[file_name] = active_chartTable.GetCount();
2231 active_chartTable.Add(pnewChart);
2234 if (pnewChart)
delete pnewChart;
2240 m_nentries = active_chartTable.GetCount();
2245bool ChartDatabase::AddChart(wxString &chartfilename,
2247 wxGenericProgressDialog *pprog,
int isearch,
2248 bool bthis_dir_in_dB) {
2250 wxFileName file(chartfilename);
2251 wxString full_name = file.GetFullPath();
2252 wxString file_name = file.GetFullName();
2262 pprog->Update(wxMin((m_pdifile * 100) / m_pdnFile, 100), full_name);
2265 bool bAddFinal =
true;
2267 wxString msg_fn(full_name);
2268 msg_fn.Replace(
"%",
"%%");
2270 pnewChart = CreateChartTableEntry(full_name, full_name, chart_desc);
2273 wxLogMessage(wxString::Format(
2274 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2279 int nEntry = active_chartTable.GetCount();
2280 for (
int i = 0; i < nEntry; i++) {
2281 wxString *ptable_file_name = active_chartTable[isearch].GetpsFullPath();
2285 if (bthis_dir_in_dB && full_name.IsSameAs(*ptable_file_name)) {
2289 time_t t_oldFile = active_chartTable[isearch].GetFileTime();
2290 time_t t_newFile = file.GetModificationTime().GetTicks();
2292 if (t_newFile <= t_oldFile) {
2294 active_chartTable[isearch].SetValid(
true);
2297 active_chartTable[isearch].SetValid(
false);
2299 wxString::Format(
" Replacing older chart file of same path: %s",
2309 wxFileName table_file(*ptable_file_name);
2311 if (table_file.GetFullName() == file_name) {
2314 if (pnewChart->IsEarlierThan(active_chartTable[isearch])) {
2316 if (table_file.IsFileReadable()) {
2317 active_chartTable[isearch].SetValid(
true);
2319 wxLogMessage(wxString::Format(
2320 " Retaining newer chart file of same name: %s",
2323 }
else if (pnewChart->IsEqualTo(active_chartTable[isearch])) {
2333 active_chartTable[isearch].SetValid(
false);
2336 wxString::Format(
" Replacing older chart file of same name: %s",
2346 if (nEntry == isearch) isearch = 0;
2351 if (0 == b_add_msg) {
2353 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2356 active_chartTable.Add(pnewChart);
2366 m_nentries = active_chartTable.GetCount();
2371bool ChartDatabase::AddSingleChart(wxString &ChartFullPath,
2372 bool b_force_full_search) {
2374 wxFileName fn(ChartFullPath);
2375 wxString ext = fn.GetExt();
2377 wxString ext_upper = ext.MakeUpper();
2378 wxString ext_lower = ext.MakeLower();
2379 wxString dir_name = fn.GetPath();
2385 for (
auto &cd : m_ChartClassDescriptorArray) {
2386 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2387 if (cd.m_search_mask == ext_upper) {
2391 if (cd.m_search_mask == ext_lower) {
2400 bool b_recurse =
true;
2401 if (!b_force_full_search) b_recurse = IsChartDirUsed(dir_name);
2403 bool rv = AddChart(ChartFullPath, desc, NULL, 0, b_recurse);
2407 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2408 if (!active_chartTable[i].GetbValid()) {
2409 active_chartTable.RemoveAt(i);
2415 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
2416 active_chartTable[i].SetEntryOffset(i);
2420 DetectDirChange(dir_name,
"",
"", new_magic, 0);
2423 bool bcfound =
false;
2424 ArrayOfCDI NewChartDirArray;
2426 ArrayOfCDI ChartDirArray = GetChartDirArray();
2427 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2433 if (newcdi.fullpath == dir_name) {
2434 newcdi.magic_number = new_magic;
2438 NewChartDirArray.Add(newcdi);
2443 cdi.fullpath = dir_name;
2444 cdi.magic_number = new_magic;
2445 NewChartDirArray.Add(cdi);
2449 SetChartDirArray(NewChartDirArray);
2452 m_chartDirs.Clear();
2454 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2456 m_chartDirs.Add(cdi.fullpath);
2459 m_nentries = active_chartTable.GetCount();
2464bool ChartDatabase::RemoveSingleChart(wxString &ChartFullPath) {
2468 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2469 if (ChartFullPath.IsSameAs(GetChartTableEntry(i).GetFullSystemPath())) {
2470 active_chartTable.RemoveAt(i);
2478 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2479 pcte = GetpChartTableEntry(i);
2480 pcte->SetEntryOffset(i);
2484 wxFileName fn(ChartFullPath);
2485 wxString fd = fn.GetPath();
2486 if (!IsChartDirUsed(fd)) {
2488 ArrayOfCDI NewChartDirArray;
2490 ArrayOfCDI ChartDirArray = GetChartDirArray();
2491 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2496 if (newcdi.fullpath != fd) NewChartDirArray.Add(newcdi);
2499 SetChartDirArray(NewChartDirArray);
2503 m_chartDirs.Clear();
2504 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2506 m_chartDirs.Add(cdi.fullpath);
2509 m_nentries = active_chartTable.GetCount();
2518ChartBase *ChartDatabase::GetChart(
const wxChar *theFilePath,
2529 const wxString &filePath, wxString &utf8Path,
2531 wxString msg_fn(filePath);
2532 msg_fn.Replace(
"%",
"%%");
2533 wxLogMessage(wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
2535 ChartBase *pch = GetChart(filePath, chart_desc);
2538 wxString::Format(
" ...creation failed for %s", msg_fn.c_str()));
2542 InitReturn rc = pch->Init(filePath, HEADER_ONLY);
2543 if (rc != INIT_OK) {
2546 wxString::Format(
" ...initialization failed for %s", msg_fn.c_str()));
2551 ret_val->SetValid(
true);
2558bool ChartDatabase::GetCentroidOfLargestScaleChart(
double *clat,
double *clon,
2559 ChartFamilyEnum family) {
2561 int cur_max_scale = 0;
2563 int nEntry = active_chartTable.GetCount();
2565 for (
int i = 0; i < nEntry; i++) {
2566 if (GetChartFamily(active_chartTable[i].GetChartType()) == family) {
2567 if (active_chartTable[i].GetScale() > cur_max_scale) {
2568 cur_max_scale = active_chartTable[i].GetScale();
2574 if (cur_max_i == -1)
2577 *clat = (active_chartTable[cur_max_i].GetLatMax() +
2578 active_chartTable[cur_max_i].GetLatMin()) /
2580 *clon = (active_chartTable[cur_max_i].GetLonMin() +
2581 active_chartTable[cur_max_i].GetLonMax()) /
2590int ChartDatabase::GetDBChartProj(
int dbIndex) {
2591 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2592 return active_chartTable[dbIndex].GetChartProjectionType();
2594 return PROJECTION_UNKNOWN;
2600int ChartDatabase::GetDBChartFamily(
int dbIndex) {
2601 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2602 return active_chartTable[dbIndex].GetChartFamily();
2604 return CHART_FAMILY_UNKNOWN;
2610wxString ChartDatabase::GetDBChartFileName(
int dbIndex) {
2611 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2612 return wxString(active_chartTable[dbIndex].GetFullSystemPath());
2620int ChartDatabase::GetDBChartType(
int dbIndex) {
2621 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2622 return active_chartTable[dbIndex].GetChartType();
2630float ChartDatabase::GetDBChartSkew(
int dbIndex) {
2631 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2632 return active_chartTable[dbIndex].GetChartSkew();
2640int ChartDatabase::GetDBChartScale(
int dbIndex) {
2641 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2642 return active_chartTable[dbIndex].GetScale();
2650bool ChartDatabase::GetDBBoundingBox(
int dbIndex, LLBBox &box) {
2651 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2653 box.Set(entry.GetLatMin(), entry.GetLonMin(), entry.GetLatMax(),
2660const LLBBox &ChartDatabase::GetDBBoundingBox(
int dbIndex) {
2661 if ((bValid) && (dbIndex >= 0)) {
2663 return entry.GetBBox();
2665 return m_dummy_bbox;
2672int ChartDatabase::GetDBPlyPoint(
int dbIndex,
int plyindex,
float *lat,
2674 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2676 if (entry.GetnPlyEntries()) {
2677 float *fp = entry.GetpPlyTable();
2679 if (lat) *lat = *fp;
2681 if (lon) *lon = *fp;
2683 return entry.GetnPlyEntries();
2691int ChartDatabase::GetDBAuxPlyPoint(
int dbIndex,
int plyindex,
int ply,
2692 float *lat,
float *lon) {
2693 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2695 if (entry.GetnAuxPlyEntries()) {
2696 float *fp = entry.GetpAuxPlyTableEntry(ply);
2699 if (lat) *lat = *fp;
2701 if (lon) *lon = *fp;
2704 return entry.GetAuxCntTableEntry(ply);
2709int ChartDatabase::GetnAuxPlyEntries(
int dbIndex) {
2710 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2712 return entry.GetnAuxPlyEntries();
2720std::vector<float> ChartDatabase::GetReducedPlyPoints(
int dbIndex) {
2721 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2723 if (pentry)
return pentry->GetReducedPlyPoints();
2726 std::vector<float> dummy;
2733std::vector<float> ChartDatabase::GetReducedAuxPlyPoints(
int dbIndex,
2735 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2737 if (pentry)
return pentry->GetReducedAuxPlyPoints(iTable);
2740 std::vector<float> dummy;
2744bool ChartDatabase::IsChartAvailable(
int dbIndex) {
2745 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2749 if (pentry->GetChartType() != CHART_TYPE_PLUGIN)
return true;
2751 wxString *path = pentry->GetpsFullPath();
2752 wxFileName fn(*path);
2753 wxString ext = fn.GetExt();
2755 wxString ext_upper = ext.MakeUpper();
2756 wxString ext_lower = ext.MakeLower();
2761 for (
auto &cd : m_ChartClassDescriptorArray) {
2762 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2763 wxString search_mask = cd.m_search_mask;
2765 if (search_mask == ext_upper) {
2768 if (search_mask == ext_lower) {
2771 if (path->Matches(search_mask)) {
2781void ChartDatabase::ApplyGroupArray(ChartGroupArray *pGroupArray) {
2782 wxString separator(wxFileName::GetPathSeparator());
2784 for (
unsigned int ic = 0; ic < active_chartTable.GetCount(); ic++) {
2787 pcte->ClearGroupArray();
2789 wxString *chart_full_path = pcte->GetpsFullPath();
2791 for (
unsigned int igroup = 0; igroup < pGroupArray->GetCount(); igroup++) {
2792 ChartGroup *pGroup = pGroupArray->Item(igroup);
2793 for (
const auto &elem : pGroup->m_element_array) {
2794 wxString element_root = elem.m_element_name;
2800 if (!chart_full_path->IsSameAs(element_root))
2801 element_root.Append(
2803 if (chart_full_path->StartsWith(element_root)) {
2805 for (
unsigned int k = 0; k < elem.m_missing_name_array.size(); k++) {
2806 const wxString &missing_item = elem.m_missing_name_array[k];
2807 if (chart_full_path->StartsWith(missing_item)) {
2808 if (chart_full_path->IsSameAs(
2814 if (wxDir::Exists(missing_item))
2823 if (b_add) pcte->AddIntToGroupArray(igroup + 1);
General chart base definitions.
ChartGroupArray * g_pGroupArray
Global instance.
Basic chart info storage.
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.
Class for computing hash of arbitrary length.
Hash of arbitrary length.
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.