31#include <wx/arrimpl.cpp>
33#include <wx/encconv.h>
34#include <wx/progdlg.h>
36#include <wx/tokenzr.h>
41#include "LOD_reduce.h"
44#include "shapefile_basemap.h"
47#define UINT32 unsigned int
51#include "androidUTIL.h"
56static int s_dbVersion;
62static ChartFamilyEnum GetChartFamily(
int charttype) {
67 cf = CHART_FAMILY_RASTER;
70 cf = CHART_FAMILY_RASTER;
73 cf = CHART_FAMILY_VECTOR;
76 cf = CHART_FAMILY_VECTOR;
78 case CHART_TYPE_CM93COMP:
79 cf = CHART_FAMILY_VECTOR;
81 case CHART_TYPE_DUMMY:
82 cf = CHART_FAMILY_RASTER;
84 case CHART_TYPE_UNKNOWN:
85 cf = CHART_FAMILY_UNKNOWN;
88 cf = CHART_FAMILY_UNKNOWN;
98void ChartTableHeader::Read(wxInputStream &is) {
102void ChartTableHeader::Write(wxOutputStream &os) {
104 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
106 memcpy(dbVersion, vb, 4);
110bool ChartTableHeader::CheckValid() {
112 sprintf(vb,
"V%03d", DB_VERSION_CURRENT);
113 if (strncmp(vb, dbVersion,
sizeof(dbVersion))) {
116 memcpy(vbo, dbVersion, 4);
118 msg.Append(wxString(vbo, wxConvUTF8));
119 msg.Prepend(
" Warning: found incorrect chart db version: ");
125 sprintf(vb,
"V%03d", DB_VERSION_PREVIOUS);
126 if (strncmp(vb, dbVersion,
sizeof(dbVersion)))
130 " Scheduling db upgrade to current db version on "
131 "Options->Charts page visit...");
138 memcpy(vbo, dbVersion, 4);
140 msg.Append(wxString(vbo, wxConvUTF8));
141 msg.Prepend(
"Loading chart db version: ");
152void ChartTableEntry::SetScale(
int scale) {
156 if (Scale >= 1000) rounding = 5 * pow(10, log10(Scale) - 2);
159ChartTableEntry::ChartTableEntry(
ChartBase &theChart, wxString &utf8Path) {
162 char *pt = (
char *)malloc(strlen(utf8Path.mb_str(wxConvUTF8)) + 1);
163 strcpy(pt, utf8Path.mb_str(wxConvUTF8));
166 SetScale(theChart.GetNativeScale());
168 ChartType = theChart.GetChartType();
169 ChartFamily = theChart.GetChartFamily();
171 Skew = theChart.GetChartSkew();
172 ProjectionType = theChart.GetChartProjectionType();
174 wxDateTime ed = theChart.GetEditionDate();
175 if (theChart.GetEditionDate().IsValid())
176 edition_date = theChart.GetEditionDate().GetTicks();
178 wxFileName fn(theChart.GetFullPath());
179 if (fn.GetModificationTime().IsValid())
180 file_date = fn.GetModificationTime().GetTicks();
182 m_pfilename =
new wxString;
183 *m_pfilename = fn.GetFullName();
184 m_psFullPath =
new wxString;
185 *m_psFullPath = utf8Path;
186 m_fullSystemPath = utf8Path;
187 m_FullPath = std::string(pFullPath);
190 m_fullSystemPath = wxString(utf8Path.mb_str(wxConvUTF8));
194 theChart.GetChartExtent(&ext);
200 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
205 double scale_max_zoom = Scale / 4;
207 double display_ppm = 1 / .00025;
208 double meters_per_pixel_max_scale = scale_max_zoom / display_ppm;
209 double LOD_meters = meters_per_pixel_max_scale * LOD_pixels;
214 if (theChart.GetCOVREntries() == 1) {
215 nPlyEntries = theChart.GetCOVRTablePoints(0);
217 if (nPlyEntries > 5 && (LOD_meters > .01)) {
218 std::vector<int> index_keep{0, nPlyEntries - 1, 1, nPlyEntries - 2};
220 double *DPbuffer = (
double *)malloc(2 * nPlyEntries *
sizeof(
double));
222 double *pfed = DPbuffer;
225 for (
int i = 0; i < nPlyEntries; i++) {
231 DouglasPeucker(DPbuffer, 1, nPlyEntries - 2, LOD_meters / (1852 * 60),
237 for (
unsigned int i = 0; i < index_keep.size(); i++) {
238 DPbuffer[2 * index_keep[i]] += 2000.;
241 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
244 for (
int i = 0; i < nPlyEntries; i++) {
245 if (DPbuffer[2 * i] > 1000.) {
246 *pfe++ = DPbuffer[2 * i] - 2000.;
247 *pfe++ = DPbuffer[(2 * i) + 1];
252 nPlyEntries = index_keep.size();
255 float *pf = (
float *)malloc(2 * nPlyEntries *
sizeof(
float));
260 for (
int i = 0; i < nPlyEntries; i++) {
272 float *pf1 = (
float *)malloc(2 * 4 *
sizeof(
float));
276 theChart.GetChartExtent(&fext);
292 nAuxPlyEntries = theChart.GetCOVREntries();
293 wxASSERT(nAuxPlyEntries);
294 float **pfp = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
296 int *pip = (
int *)malloc(nAuxPlyEntries *
sizeof(
int));
298 for (
int j = 0; j < nAuxPlyEntries; j++) {
299 int nPE = theChart.GetCOVRTablePoints(j);
301 if (nPE > 5 && (LOD_meters > .01)) {
302 std::vector<int> index_keep{0, nPE - 1, 1, nPE - 2};
304 double *DPbuffer = (
double *)malloc(2 * nPE *
sizeof(
double));
306 double *pfed = DPbuffer;
309 for (
int i = 0; i < nPE; i++) {
315 DouglasPeucker(DPbuffer, 1, nPE - 2, LOD_meters / (1852 * 60),
321 for (
unsigned int i = 0; i < index_keep.size(); i++) {
322 DPbuffer[2 * index_keep[i]] += 2000.;
325 float *pf = (
float *)malloc(2 * index_keep.size() *
sizeof(float));
328 for (
int i = 0; i < nPE; i++) {
329 if (DPbuffer[2 * i] > 1000.) {
330 *pfe1++ = DPbuffer[2 * i] - 2000.;
331 *pfe1++ = DPbuffer[(2 * i) + 1];
336 pip[j] = index_keep.size();
340 (
float *)malloc(theChart.GetCOVRTablePoints(j) * 2 *
sizeof(float));
341 memcpy(pf_entry, theChart.GetCOVRTableHead(j),
342 theChart.GetCOVRTablePoints(j) * 2 *
sizeof(
float));
344 pip[j] = theChart.GetCOVRTablePoints(j);
354 nNoCovrPlyEntries = theChart.GetNoCOVREntries();
355 if (nNoCovrPlyEntries == 0)
return;
357 float **pfpnc = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
358 float **pft0nc = pfpnc;
359 int *pipnc = (
int *)malloc(nNoCovrPlyEntries *
sizeof(
int));
361 for (
int j = 0; j < nNoCovrPlyEntries; j++) {
363 (
float *)malloc(theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(float));
364 memcpy(pf_entry, theChart.GetNoCOVRTableHead(j),
365 theChart.GetNoCOVRTablePoints(j) * 2 *
sizeof(
float));
366 pft0nc[j] = pf_entry;
367 pipnc[j] = theChart.GetNoCOVRTablePoints(j);
370 pNoCovrPlyTable = pfpnc;
371 pNoCovrCntTable = pipnc;
376ChartTableEntry::~ChartTableEntry() {
380 for (
int i = 0; i < nAuxPlyEntries; i++) free(pAuxPlyTable[i]);
384 if (nNoCovrPlyEntries) {
385 for (
int i = 0; i < nNoCovrPlyEntries; i++) free(pNoCovrPlyTable[i]);
386 free(pNoCovrPlyTable);
387 free(pNoCovrCntTable);
399 wxDateTime mine(edition_date);
400 wxDateTime theirs(cte.edition_date);
402 if (!mine.IsValid() || !theirs.IsValid())
405 return (mine.IsEarlierThan(theirs));
409 wxDateTime mine(edition_date);
410 wxDateTime theirs(cte.edition_date);
412 if (!mine.IsValid() || !theirs.IsValid())
415 return (mine.IsEqualTo(theirs));
420static int convertChartType(
int charttype) {
423 if (s_dbVersion == 14) {
426 return CHART_TYPE_KAP;
428 return CHART_TYPE_GEO;
430 return CHART_TYPE_S57;
432 return CHART_TYPE_CM93;
434 return CHART_TYPE_CM93COMP;
436 return CHART_TYPE_UNKNOWN;
438 return CHART_TYPE_DONTCARE;
440 return CHART_TYPE_DUMMY;
442 return CHART_TYPE_UNKNOWN;
448static int convertChartFamily(
int charttype,
int chartfamily) {
449 if (s_dbVersion < 18) {
453 return CHART_FAMILY_RASTER;
456 case CHART_TYPE_CM93:
457 case CHART_TYPE_CM93COMP:
458 return CHART_FAMILY_VECTOR;
461 return CHART_FAMILY_UNKNOWN;
467bool ChartTableEntry::Read(
const ChartDatabase *pDb, wxInputStream &is) {
468 char path[4096], *cp;
474 int db_version = pD->GetVersion();
476 if (db_version == 18) {
478 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
479 pFullPath = (
char *)malloc(cp - path + 1);
480 strncpy(pFullPath, path, cp - path + 1);
481 wxLogVerbose(
" Chart %s", pFullPath);
484 m_pfilename =
new wxString;
485 wxString fullfilename(pFullPath, wxConvUTF8);
486 wxFileName fn(fullfilename);
487 *m_pfilename = fn.GetFullName();
488 m_psFullPath =
new wxString;
489 *m_psFullPath = fullfilename;
490 m_fullSystemPath = fullfilename;
491 m_FullPath = std::string(pFullPath);
494 m_fullSystemPath = wxString(fullfilename.mb_str(wxConvUTF8));
501 EntryOffset = cte.EntryOffset;
502 ChartType = cte.ChartType;
503 ChartFamily = cte.ChartFamily;
509 m_bbox.Set(LatMin, LonMin, LatMax, LonMax);
512 ProjectionType = cte.ProjectionType;
515 edition_date = cte.edition_date;
516 file_date = cte.file_date;
518 nPlyEntries = cte.nPlyEntries;
519 nAuxPlyEntries = cte.nAuxPlyEntries;
521 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
526 int npeSize = nPlyEntries * 2 *
sizeof(float);
527 pPlyTable = (
float *)malloc(npeSize);
528 is.Read(pPlyTable, npeSize);
531 if (nAuxPlyEntries) {
532 int napeSize = nAuxPlyEntries *
sizeof(int);
533 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
534 pAuxCntTable = (
int *)malloc(napeSize);
535 is.Read(pAuxCntTable, napeSize);
537 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
539 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
540 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
541 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
545 if (nNoCovrPlyEntries) {
546 int napeSize = nNoCovrPlyEntries *
sizeof(int);
547 pNoCovrCntTable = (
int *)malloc(napeSize);
548 is.Read(pNoCovrCntTable, napeSize);
550 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
551 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
552 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
553 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
554 is.Read(pNoCovrPlyTable[i], nfSize);
559 else if (db_version == 17) {
561 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
562 pFullPath = (
char *)malloc(cp - path + 1);
563 strncpy(pFullPath, path, cp - path + 1);
564 wxLogVerbose(
" Chart %s", pFullPath);
567 m_pfilename =
new wxString;
568 wxString fullfilename(pFullPath, wxConvUTF8);
569 wxFileName fn(fullfilename);
570 *m_pfilename = fn.GetFullName();
571 m_psFullPath =
new wxString;
572 *m_psFullPath = fullfilename;
573 m_FullPath = std::string(pFullPath);
580 EntryOffset = cte.EntryOffset;
581 ChartType = cte.ChartType;
587 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
590 ProjectionType = cte.ProjectionType;
593 edition_date = cte.edition_date;
594 file_date = cte.file_date;
596 nPlyEntries = cte.nPlyEntries;
597 nAuxPlyEntries = cte.nAuxPlyEntries;
599 nNoCovrPlyEntries = cte.nNoCovrPlyEntries;
604 int npeSize = nPlyEntries * 2 *
sizeof(float);
605 pPlyTable = (
float *)malloc(npeSize);
606 is.Read(pPlyTable, npeSize);
609 if (nAuxPlyEntries) {
610 int napeSize = nAuxPlyEntries *
sizeof(int);
611 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
612 pAuxCntTable = (
int *)malloc(napeSize);
613 is.Read(pAuxCntTable, napeSize);
615 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
617 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
618 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
619 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
623 if (nNoCovrPlyEntries) {
624 int napeSize = nNoCovrPlyEntries *
sizeof(int);
625 pNoCovrCntTable = (
int *)malloc(napeSize);
626 is.Read(pNoCovrCntTable, napeSize);
628 pNoCovrPlyTable = (
float **)malloc(nNoCovrPlyEntries *
sizeof(
float *));
629 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
630 int nfSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
631 pNoCovrPlyTable[i] = (
float *)malloc(nfSize);
632 is.Read(pNoCovrPlyTable[i], nfSize);
637 else if (db_version == 16) {
639 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
641 pFullPath = (
char *)malloc(cp - path + 1);
642 strncpy(pFullPath, path, cp - path + 1);
643 wxLogVerbose(
" Chart %s", pFullPath);
646 m_pfilename =
new wxString;
647 wxString fullfilename(pFullPath, wxConvUTF8);
648 wxFileName fn(fullfilename);
649 *m_pfilename = fn.GetFullName();
650 m_psFullPath =
new wxString;
651 *m_psFullPath = fullfilename;
652 m_FullPath = std::string(pFullPath);
659 EntryOffset = cte.EntryOffset;
660 ChartType = cte.ChartType;
666 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
669 ProjectionType = cte.ProjectionType;
672 edition_date = cte.edition_date;
673 file_date = cte.file_date;
675 nPlyEntries = cte.nPlyEntries;
676 nAuxPlyEntries = cte.nAuxPlyEntries;
681 int npeSize = nPlyEntries * 2 *
sizeof(float);
682 pPlyTable = (
float *)malloc(npeSize);
683 is.Read(pPlyTable, npeSize);
686 if (nAuxPlyEntries) {
687 int napeSize = nAuxPlyEntries *
sizeof(int);
688 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
689 pAuxCntTable = (
int *)malloc(napeSize);
690 is.Read(pAuxCntTable, napeSize);
692 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
694 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
695 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
696 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
701 else if (db_version == 15) {
703 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
705 pFullPath = (
char *)malloc(cp - path + 1);
706 strncpy(pFullPath, path, cp - path + 1);
707 wxLogVerbose(
" Chart %s", pFullPath);
714 EntryOffset = cte.EntryOffset;
715 ChartType = cte.ChartType;
721 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
724 edition_date = cte.edition_date;
725 file_date = cte.file_date;
727 nPlyEntries = cte.nPlyEntries;
728 nAuxPlyEntries = cte.nAuxPlyEntries;
733 int npeSize = nPlyEntries * 2 *
sizeof(float);
734 pPlyTable = (
float *)malloc(npeSize);
735 is.Read(pPlyTable, npeSize);
738 if (nAuxPlyEntries) {
739 int napeSize = nAuxPlyEntries *
sizeof(int);
740 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
741 pAuxCntTable = (
int *)malloc(napeSize);
742 is.Read(pAuxCntTable, napeSize);
744 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
746 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
747 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
748 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
751 }
else if (db_version == 14) {
753 for (cp = path; (*cp = (char)is.GetC()) != 0; cp++);
754 pFullPath = (
char *)malloc(cp - path + 1);
755 strncpy(pFullPath, path, cp - path + 1);
756 wxLogVerbose(
" Chart %s", pFullPath);
763 EntryOffset = cte.EntryOffset;
764 ChartType = cte.ChartType;
770 m_bbox.Set(LatMin, LatMax, LonMin, LonMax);
773 edition_date = cte.edition_date;
775 nPlyEntries = cte.nPlyEntries;
776 nAuxPlyEntries = cte.nAuxPlyEntries;
780 int npeSize = nPlyEntries * 2 *
sizeof(float);
781 pPlyTable = (
float *)malloc(npeSize);
782 is.Read(pPlyTable, npeSize);
785 if (nAuxPlyEntries) {
786 int napeSize = nAuxPlyEntries *
sizeof(int);
787 pAuxPlyTable = (
float **)malloc(nAuxPlyEntries *
sizeof(
float *));
788 pAuxCntTable = (
int *)malloc(napeSize);
789 is.Read(pAuxCntTable, napeSize);
791 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries;
793 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
794 pAuxPlyTable[nAuxPlyEntry] = (
float *)malloc(nfSize);
795 is.Read(pAuxPlyTable[nAuxPlyEntry], nfSize);
799 ChartFamily = convertChartFamily(ChartType, ChartFamily);
800 ChartType = convertChartType(ChartType);
807bool ChartTableEntry::Write(
const ChartDatabase *pDb, wxOutputStream &os) {
808 os.Write(pFullPath, strlen(pFullPath) + 1);
815 cte.EntryOffset = EntryOffset;
816 cte.ChartType = ChartType;
817 cte.ChartFamily = ChartFamily;
824 cte.edition_date = edition_date;
825 cte.file_date = file_date;
827 cte.nPlyEntries = nPlyEntries;
828 cte.nAuxPlyEntries = nAuxPlyEntries;
831 cte.ProjectionType = ProjectionType;
835 cte.nNoCovrPlyEntries = nNoCovrPlyEntries;
838 wxLogVerbose(
" Wrote Chart %s", pFullPath);
842 int npeSize = nPlyEntries * 2 *
sizeof(float);
843 os.Write(pPlyTable, npeSize);
846 if (nAuxPlyEntries) {
847 int napeSize = nAuxPlyEntries *
sizeof(int);
848 os.Write(pAuxCntTable, napeSize);
850 for (
int nAuxPlyEntry = 0; nAuxPlyEntry < nAuxPlyEntries; nAuxPlyEntry++) {
851 int nfSize = pAuxCntTable[nAuxPlyEntry] * 2 *
sizeof(float);
852 os.Write(pAuxPlyTable[nAuxPlyEntry], nfSize);
856 if (nNoCovrPlyEntries) {
857 int ncSize = nNoCovrPlyEntries *
sizeof(int);
858 os.Write(pNoCovrCntTable, ncSize);
860 for (
int i = 0; i < nNoCovrPlyEntries; i++) {
861 int nctSize = pNoCovrCntTable[i] * 2 *
sizeof(float);
862 os.Write(pNoCovrPlyTable[i], nctSize);
871void ChartTableEntry::Clear() {
880 pNoCovrCntTable = NULL;
881 pNoCovrPlyTable = NULL;
883 nNoCovrPlyEntries = 0;
892void ChartTableEntry::Disable() {
896 LatMax += (float)1000.;
897 LatMin += (float)1000.;
900void ChartTableEntry::ReEnable() {
902 LatMax -= (float)1000.;
903 LatMin -= (float)1000.;
907std::vector<float> ChartTableEntry::GetReducedPlyPoints() {
908 if (m_reducedPlyPoints.size())
return m_reducedPlyPoints;
911 float LOD_meters = 1;
913 float plylat, plylon;
914 const int nPoints = GetnPlyEntries();
916 float *fpo = GetpPlyTable();
918 double *ppd =
new double[nPoints * 2];
919 double *ppsm =
new double[nPoints * 2];
922 for (
int i = 0; i < nPoints; i++) {
924 plylon = fpo[i * 2 + 1];
927 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
935 std::vector<int> index_keep;
937 index_keep.push_back(0);
938 index_keep.push_back(nPoints - 1);
939 index_keep.push_back(1);
940 index_keep.push_back(nPoints - 2);
942 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
945 index_keep.resize(nPoints);
946 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
950 for (
int ip = 0; ip < nPoints; ip++) {
954 for (
unsigned int j = 0; j < index_keep.size(); j++) {
955 if (index_keep[j] == ip) {
956 m_reducedPlyPoints.push_back(x);
957 m_reducedPlyPoints.push_back(y);
966 int nprr = m_reducedPlyPoints.size() / 2;
968 return m_reducedPlyPoints;
971std::vector<float> ChartTableEntry::GetReducedAuxPlyPoints(
int iTable) {
973 if (!m_reducedAuxPlyPointsVector.size()) {
974 std::vector<float> vec;
975 for (
int i = 0; i < GetnAuxPlyEntries(); i++) {
976 m_reducedAuxPlyPointsVector.push_back(vec);
980 std::vector<float> vec;
983 if ((
unsigned int)iTable >= m_reducedAuxPlyPointsVector.size())
return vec;
985 if (m_reducedAuxPlyPointsVector.at(iTable).size())
986 return m_reducedAuxPlyPointsVector.at(iTable);
989 float LOD_meters = 1.0;
991 const int nPoints = GetAuxCntTableEntry(iTable);
992 float *fpo = GetpAuxPlyTableEntry(iTable);
994 double *ppd =
new double[nPoints * 2];
995 double *ppsm =
new double[nPoints * 2];
998 float plylat, plylon;
1000 for (
int i = 0; i < nPoints; i++) {
1001 plylat = fpo[i * 2];
1002 plylon = fpo[i * 2 + 1];
1005 toSM(plylat, plylon, fpo[0], fpo[1], &x, &y);
1013 std::vector<int> index_keep;
1015 index_keep.push_back(0);
1016 index_keep.push_back(nPoints - 1);
1017 index_keep.push_back(1);
1018 index_keep.push_back(nPoints - 2);
1020 DouglasPeuckerM(ppsm, 1, nPoints - 2, LOD_meters, &index_keep);
1023 index_keep.resize(nPoints);
1024 for (
int i = 0; i < nPoints; i++) index_keep[i] = i;
1027 int nnn = index_keep.size();
1030 for (
int ip = 0; ip < nPoints; ip++) {
1034 for (
unsigned int j = 0; j < index_keep.size(); j++) {
1035 if (index_keep[j] == ip) {
1046 m_reducedAuxPlyPointsVector[iTable] = vec;
1048 int nprr = vec.size() / 2;
1057WX_DEFINE_OBJARRAY(ChartTable);
1059ChartDatabase::ChartDatabase() {
1063 m_ChartTableEntryDummy.Clear();
1065 UpdateChartClassDescriptorArray();
1068void ChartDatabase::UpdateChartClassDescriptorArray(
void) {
1069 if (m_ChartClassDescriptorArray.empty()) {
1070 m_ChartClassDescriptorArray.push_back(
1072 m_ChartClassDescriptorArray.push_back(
1074 m_ChartClassDescriptorArray.push_back(
1076 m_ChartClassDescriptorArray.push_back(
1079 "cm93compchart",
"00300000.a", BUILTIN_DESCRIPTOR));
1080 m_ChartClassDescriptorArray.push_back(
1086 m_ChartClassDescriptorArray.erase(
1087 std::remove_if(m_ChartClassDescriptorArray.begin(),
1088 m_ChartClassDescriptorArray.end(),
1090 return cd.m_descriptor_type == PLUGIN_DESCRIPTOR;
1092 m_ChartClassDescriptorArray.end());
1094 wxArrayString array = g_pi_manager->GetPlugInChartClassNameArray();
1095 for (
unsigned int j = 0; j < array.GetCount(); j++) {
1098 wxString class_name = array[j];
1101 wxString mask = cpiw->GetFileSearchMask();
1104 m_ChartClassDescriptorArray.push_back(
1112const ChartTableEntry &ChartDatabase::GetChartTableEntry(
int index)
const {
1113 if (index < GetChartTableEntries())
1114 return active_chartTable[index];
1116 return m_ChartTableEntryDummy;
1120 if (index < GetChartTableEntries())
1121 return &active_chartTable[index];
1126bool ChartDatabase::CompareChartDirArray(ArrayOfCDI &test_array) {
1130 if (test_array.GetCount() != m_dir_array.GetCount())
return false;
1133 unsigned int nfound_outer = 0;
1135 for (
unsigned int i = 0; i < test_array.GetCount(); i++) {
1137 bfound_inner =
false;
1138 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1141 if (p.fullpath.IsSameAs(q.fullpath)) {
1142 bfound_inner =
true;
1146 if (bfound_inner) nfound_outer++;
1149 return (nfound_outer == test_array.GetCount());
1152wxString ChartDatabase::GetMagicNumberCached(wxString dir) {
1153 for (
unsigned int j = 0; j < m_dir_array.GetCount(); j++) {
1155 if (dir.IsSameAs(q.fullpath))
return q.magic_number;
1161bool ChartDatabase::Read(
const wxString &filePath) {
1167 wxFileName file(filePath);
1168 if (!file.FileExists())
return false;
1170 m_DBFileName = filePath;
1172 wxFFileInputStream ifs(filePath);
1173 if (!ifs.Ok())
return false;
1177 if (!cth.CheckValid())
return false;
1181 memcpy(vbo, cth.GetDBVersionString(), 4);
1183 m_dbversion = atoi(&vbo[1]);
1184 s_dbVersion = m_dbversion;
1186 wxLogVerbose(
"Chartdb:Reading %d directory entries, %d table entries",
1187 cth.GetDirEntries(), cth.GetTableEntries());
1188 wxLogMessage(
"Chartdb: Chart directory list follows");
1189 if (0 == cth.GetDirEntries()) wxLogMessage(
" Nil");
1192 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1195 ifs.Read(&dirlen,
sizeof(
int));
1196 while (dirlen > 0) {
1198 int alen = dirlen > 1023 ? 1023 : dirlen;
1199 if (ifs.Read(&dirbuf, alen).Eof())
goto read_error;
1202 dir.Append(wxString(dirbuf, wxConvUTF8));
1205 msg.Printf(
" Chart directory #%d: ", iDir);
1208 m_chartDirs.Add(dir);
1211 entries = cth.GetTableEntries();
1212 active_chartTable.Alloc(entries);
1213 active_chartTable_pathindex.clear();
1214 while (entries-- && entry.Read(
this, ifs)) {
1215 active_chartTable_pathindex[entry.GetFullSystemPath()] = ind++;
1216 active_chartTable.Add(entry);
1221 entry.SetAvailable(
true);
1223 m_nentries = active_chartTable.GetCount();
1228 m_nentries = active_chartTable.GetCount();
1234bool ChartDatabase::Write(
const wxString &filePath) {
1235 wxFileName file(filePath);
1237 file.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME, wxPATH_NATIVE));
1239 if (!dir.DirExists() && !dir.Mkdir())
return false;
1241 wxFFileOutputStream ofs(filePath);
1242 if (!ofs.Ok())
return false;
1244 ChartTableHeader cth(m_chartDirs.GetCount(), active_chartTable.GetCount());
1247 for (
int iDir = 0; iDir < cth.GetDirEntries(); iDir++) {
1248 wxString dir1 = m_chartDirs[iDir];
1249 int dirlen = dir1.length();
1251 strncpy(s, dir1.mb_str(wxConvUTF8), 199);
1254 ofs.Write(&dirlen,
sizeof(
int));
1256 ofs.Write(s, dirlen);
1259 for (UINT32 iTable = 0; iTable < active_chartTable.size(); iTable++)
1260 active_chartTable[iTable].Write(
this, ofs);
1263 m_dbversion = DB_VERSION_CURRENT;
1269wxString SplitPath(wxString s, wxString tkd,
int nchar,
int offset,
1275 wxStringTokenizer tkz(s, tkd);
1276 while (tkz.HasMoreTokens()) {
1277 wxString token = tkz.GetNextToken();
1278 if ((rlen + (
int)token.Len() + 1) < nchar) {
1281 rlen += token.Len() + 1;
1285 for (
int i = 0; i < offset; i++) {
1290 rlen = offset + token.Len() + 1;
1294 if (pn_split) *pn_split = ncr;
1296 return r.Mid(0, r.Len() - 1);
1299wxString ChartDatabase::GetFullChartInfo(
ChartBase *pc,
int dbIndex,
1300 int *char_width,
int *line_count) {
1303 unsigned int max_width = 0;
1305 unsigned int target_width = 60;
1311 line = _(
" Name: ");
1312 wxString longline = pc->GetName();
1315 if (longline.Find(
' ') != wxNOT_FOUND)
1320 if (longline.Len() > target_width) {
1321 line += SplitPath(pc->GetName(), tkz, target_width, 12, &ncr);
1322 max_width = wxMax(max_width, target_width + 4);
1326 max_width = wxMax(max_width, line.Len() + 4);
1335 line.Printf(
" %s: 1:%d", _(
"Scale"), pc->GetNativeScale());
1337 line.Printf(
" %s: 1:%d", _(
"Scale"), cte.GetScale());
1340 max_width = wxMax(max_width, line.Len());
1344 wxDateTime ed = pc->GetEditionDate();
1346 line = _(
" Updated: ") + ed.FormatISODate() +
"\n";
1347 max_width = wxMax(max_width, line.Len());
1352 line = _(
" Source Edition: ") + pc->GetSE() +
"\n";
1353 max_width = wxMax(max_width, line.Len());
1359 line = _(
" Depth Units: ") + pc->GetDepthUnits() +
"\n";
1360 max_width = wxMax(max_width, line.Len());
1364 line = _(
" Soundings: ") + pc->GetSoundingsDatum() +
"\n";
1365 max_width = wxMax(max_width, line.Len());
1369 line = _(
" Datum: ") + pc->GetDatumString() +
"\n";
1370 max_width = wxMax(max_width, line.Len());
1375 line = _(
" Projection: ");
1376 if (PROJECTION_UNKNOWN == cte.GetChartProjectionType())
1377 line += _(
"Unknown");
1378 else if (PROJECTION_MERCATOR == cte.GetChartProjectionType())
1379 line += _(
"Mercator");
1380 else if (PROJECTION_TRANSVERSE_MERCATOR == cte.GetChartProjectionType())
1381 line += _(
"Transverse Mercator");
1382 else if (PROJECTION_POLYCONIC == cte.GetChartProjectionType())
1383 line += _(
"Polyconic");
1384 else if (PROJECTION_WEB_MERCATOR == cte.GetChartProjectionType())
1385 line += _(
"Web Mercator (EPSG:3857)");
1387 max_width = wxMax(max_width, line.Len());
1396 if (pc && pc->GetExtraInfo().Len()) {
1397 line += pc->GetExtraInfo();
1399 max_width = wxMax(max_width, line.Len());
1406 line += pc->GetID();
1408 max_width = wxMax(max_width, line.Len());
1413 line = _(
" ChartFile: ");
1414 wxString longline = *(cte.GetpsFullPath());
1415 if (longline.Len() > target_width) {
1416 line += SplitPath(longline,
"/,\\", target_width, 15, &ncr);
1417 max_width = wxMax(max_width, target_width + 4);
1421 max_width = wxMax(max_width, line.Len() + 4);
1427 if (line_count) *line_count = lc;
1429 if (char_width) *char_width = max_width;
1439 wxGenericProgressDialog *pprog) {
1440 m_dir_array = dir_array;
1444 m_chartDirs.Clear();
1445 active_chartTable.Clear();
1446 active_chartTable_pathindex.clear();
1448 Update(dir_array,
true, pprog);
1453 m_dbversion = DB_VERSION_CURRENT;
1465 virtual wxDirTraverseResult OnFile(
const wxString &filename)
override {
1466 wxFileName fn(filename);
1467 wxFileName dir(fn.GetPath());
1468 if (fn.GetFullName().Matches(
"poly-*-1.dat") &&
1469 dir.GetFullName().IsSameAs(
"GSHHG",
false)) {
1470 parent_dir = fn.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
1473 return wxDIR_CONTINUE;
1475 virtual wxDirTraverseResult OnDir(
const wxString &dirname)
override {
1477 return wxDIR_CONTINUE;
1479 wxString GetGshhsDir()
const {
return parent_dir; }
1482 wxString parent_dir;
1489wxString findGshhgDirectory(
const wxString &directory) {
1490 wxDir dir(directory);
1491 if (!dir.IsOpened()) {
1492 return wxEmptyString;
1495 dir.Traverse(traverser, wxEmptyString, wxDIR_FILES | wxDIR_DIRS);
1496 return traverser.GetGshhsDir();
1504 wxGenericProgressDialog *pprog) {
1505 m_dir_array = dir_array;
1511 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
1512 active_chartTable[i].SetValid(
false);
1514 m_chartDirs.Clear();
1516 if (bForce) active_chartTable.Clear();
1518 bool lbForce = bForce;
1521 if (s_dbVersion != DB_VERSION_CURRENT) {
1522 active_chartTable.Clear();
1524 s_dbVersion = DB_VERSION_CURRENT;
1525 m_dbversion = DB_VERSION_CURRENT;
1530 for (
unsigned int j = 0; j < dir_array.GetCount(); j++) {
1537 if (!androidIsDirWritable(dir_info.fullpath))
continue;
1543 wxString gshhg_dir = findGshhgDirectory(dir_info.fullpath);
1544 if (!gshhg_dir.empty()) {
1549 wxLogMessage(
"Updating GSHHG directory: %s", gshhg_dir.c_str());
1550 gWorldMapLocation = gshhg_dir;
1552 if (dir_info.fullpath.Find(
"OSMSHP") != wxNOT_FOUND) {
1553 if (!wxDir::FindFirst(dir_info.fullpath,
"basemap_*.shp").empty()) {
1554 gWorldShapefileLocation =
1555 dir_info.fullpath + wxFileName::GetPathSeparator();
1556 gShapeBasemap.Reset();
1560 TraverseDirAndAddCharts(dir_info, pprog, dir_magic, lbForce);
1564 dir_info.magic_number = dir_magic;
1565 dir_array.RemoveAt(j);
1566 dir_array.Insert(dir_info, j);
1568 m_chartDirs.Add(dir_info.fullpath);
1571 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1572 if (!active_chartTable[i].GetbValid()) {
1573 active_chartTable.RemoveAt(i);
1579 active_chartTable_pathindex.clear();
1580 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
1581 active_chartTable_pathindex[active_chartTable[i].GetFullSystemPath()] = i;
1582 active_chartTable[i].SetEntryOffset(i);
1585 m_nentries = active_chartTable.GetCount();
1596int ChartDatabase::FinddbIndex(wxString PathToFind) {
1599 for(
unsigned int i=0 ; i<active_chartTable.GetCount() ; i++)
1601 if(active_chartTable[i].GetpsFullPath()->IsSameAs(PathToFind))
1607 if (active_chartTable_pathindex.find(PathToFind) !=
1608 active_chartTable_pathindex.end())
1609 return active_chartTable_pathindex[PathToFind];
1619int ChartDatabase::DisableChart(wxString &PathToDisable) {
1620 int index = FinddbIndex(PathToDisable);
1636int ChartDatabase::TraverseDirAndAddCharts(
ChartDirInfo &dir_info,
1637 wxGenericProgressDialog *pprog,
1638 wxString &dir_magic,
bool bForce) {
1640 wxString dir_path = dir_info.fullpath;
1642 dir_path = wxString(dir_info.fullpath.mb_str(wxConvUTF8));
1645 wxString old_magic = dir_info.magic_number;
1646 wxString new_magic = old_magic;
1647 dir_magic = old_magic;
1651 bool b_skipDetectDirChange =
false;
1652 bool b_dirchange =
false;
1655 if (!wxDir::Exists(dir_path))
return 0;
1661 bool b_cm93 = Check_CM93_Structure(dir_path);
1663 b_skipDetectDirChange =
true;
1669 if (!b_skipDetectDirChange)
1670 b_dirchange = DetectDirChange(dir_path, dir_info.fullpath, old_magic,
1673 if (!bForce && !b_dirchange) {
1674 wxString msg(
" No change detected on directory ");
1675 msg.Append(dir_path);
1681 wxFileName fn_dir(dir_path,
"stuff");
1682 unsigned int dir_path_count = fn_dir.GetDirCount();
1684 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Scan...."));
1686 int nEntries = active_chartTable.GetCount();
1688 for (
int ic = 0; ic < nEntries; ic++) {
1689 wxFileName fn(active_chartTable[ic].GetFullSystemPath());
1691 while (fn.GetDirCount() >= dir_path_count) {
1692 if (fn.GetPath() == dir_path) {
1693 active_chartTable[ic].SetValid(
true);
1709 dir_magic = new_magic;
1712 for (
auto &cd : m_ChartClassDescriptorArray) {
1713 nAdd += SearchDirAndAddCharts(dir_info.fullpath, cd, pprog);
1719bool ChartDatabase::DetectDirChange(
const wxString &dir_path,
1720 const wxString &prog_label,
1721 const wxString &magic, wxString &new_magic,
1722 wxGenericProgressDialog *pprog) {
1723 if (pprog) pprog->SetTitle(_(
"OpenCPN Directory Scan...."));
1726 long long unsigned int nmagic;
1727 wxULongLong nacc = 0;
1729 magic.ToULongLong(&nmagic, 10);
1732 wxArrayString FileList;
1733 wxDir dir(dir_path);
1734 int n_files = dir.GetAllFiles(dir_path, &FileList);
1742 for (
int ifile = 0; ifile < n_files; ifile++) {
1743 if (pprog && (ifile % (n_files / 60 + 1)) == 0)
1744 pprog->Update(wxMin((ifile * 100) / n_files, 100), prog_label);
1746 wxFileName file(FileList[ifile]);
1751 wxString fileNameNative = file.GetFullPath();
1752 wxScopedCharBuffer fileNameUTF8 = fileNameNative.ToUTF8();
1753 hash.Update(fileNameUTF8.data(), fileNameUTF8.length());
1756 wxULongLong size = file.GetSize();
1757 wxULongLong fileSize = ((size != wxInvalidSize) ? size : 0);
1758 hash.Update(&fileSize, (
sizeof fileSize));
1761 wxDateTime t = file.GetModificationTime();
1762 wxULongLong fileTime = t.GetTicks();
1763 hash.Update(&fileTime, (
sizeof fileTime));
1767 hash.Receive(&nacc);
1770 new_magic = nacc.ToString();
1773 if (new_magic != magic)
1779bool ChartDatabase::IsChartDirUsed(
const wxString &theDir) {
1780 wxString dir(theDir);
1781 if (dir.Last() ==
'/' || dir.Last() == wxFileName::GetPathSeparator())
1785 for (UINT32 i = 0; i < active_chartTable.GetCount(); i++) {
1786 if (active_chartTable[i].GetpsFullPath()->Matches(dir))
return true;
1795bool ChartDatabase::Check_CM93_Structure(wxString dir_name) {
1798 wxRegEx test(
"[0-9]+");
1800 wxDir dirt(dir_name);
1803 if (dirt.IsOpened())
1804 wxLogMessage(
"check_cm93 opened dir OK: " + dir_name);
1806 wxLogMessage(
"check_cm93 NOT OPENED OK: " + dir_name);
1807 wxLogMessage(
"check_cm93 returns false." + dir_name);
1811 bool b_maybe_found_cm93 =
false;
1812 bool b_cont = dirt.GetFirst(&candidate);
1815 if (test.Matches(candidate) && (candidate.Len() == 8)) {
1816 b_maybe_found_cm93 =
true;
1820 b_cont = dirt.GetNext(&candidate);
1823 if (b_maybe_found_cm93) {
1824 wxString dir_next = dir_name;
1826 dir_next += candidate;
1827 if (wxDir::Exists(dir_next)) {
1828 wxDir dir_n(dir_next);
1829 if (dirt.IsOpened()) {
1830 wxString candidate_n;
1832 wxRegEx test_n(
"^[A-Ga-g]");
1833 bool b_probably_found_cm93 =
false;
1834 bool b_cont_n = dir_n.IsOpened() && dir_n.GetFirst(&candidate_n);
1836 if (test_n.Matches(candidate_n) && (candidate_n.Len() == 1)) {
1837 b_probably_found_cm93 =
true;
1840 b_cont_n = dir_n.GetNext(&candidate_n);
1843 if (b_probably_found_cm93)
1848 wxString dir_luk = dir_next;
1850 dir_luk += candidate_n;
1851 if (wxDir::Exists(dir_luk))
return true;
1970WX_DECLARE_STRING_HASH_MAP(
int, ChartCollisionsHashMap);
1972int ChartDatabase::SearchDirAndAddCharts(wxString &dir_name_base,
1974 wxGenericProgressDialog *pprog) {
1975 wxString msg(
"Searching directory: ");
1976 msg += dir_name_base;
1978 msg += chart_desc.m_search_mask;
1981 wxString dir_name = dir_name_base;
1984 dir_name = wxString(dir_name_base.mb_str(wxConvUTF8));
1987 if (!wxDir::Exists(dir_name))
return 0;
1989 wxString filespec = chart_desc.m_search_mask.Upper();
1990 wxString lowerFileSpec = chart_desc.m_search_mask.Lower();
1991 wxString filespecXZ = filespec +
".xz";
1992 wxString lowerFileSpecXZ = lowerFileSpec +
".xz";
1996 wxArrayString FileList;
1997 int gaf_flags = wxDIR_DEFAULT;
2004 bool b_found_cm93 =
false;
2005 bool b_cm93 = Check_CM93_Structure(dir_name);
2007 if (filespec !=
"00300000.A")
2010 filespec = dir_name;
2011 b_found_cm93 =
true;
2015 if (!b_found_cm93) {
2016 wxDir dir(dir_name);
2017 dir.GetAllFiles(dir_name, &FileList, filespec, gaf_flags);
2020 if (!FileList.GetCount()) {
2021 wxArrayString afl = androidTraverseDir(dir_name, filespec);
2022 for (wxArrayString::const_iterator item = afl.begin(); item != afl.end();
2024 FileList.Add(*item);
2029 if (filespec != lowerFileSpec) {
2031 wxArrayString lowerFileList;
2032 dir.GetAllFiles(dir_name, &lowerFileList, lowerFileSpec, gaf_flags);
2035 if (!lowerFileList.GetCount()) {
2036 wxArrayString afl = androidTraverseDir(dir_name, lowerFileSpec);
2037 for (wxArrayString::const_iterator item = afl.begin();
2038 item != afl.end(); item++)
2039 lowerFileList.Add(*item);
2043 for (wxArrayString::const_iterator item = lowerFileList.begin();
2044 item != lowerFileList.end(); item++)
2045 FileList.Add(*item);
2051 dir.GetAllFiles(dir_name, &FileList, filespecXZ, gaf_flags);
2052 dir.GetAllFiles(dir_name, &FileList, lowerFileSpecXZ, gaf_flags);
2058 wxString dir_plus = dir_name;
2059 dir_plus += wxFileName::GetPathSeparator();
2060 FileList.Add(dir_plus);
2063 int nFile = FileList.GetCount();
2065 if (!nFile)
return false;
2072 bool bthis_dir_in_dB = IsChartDirUsed(dir_name);
2074 if (pprog) pprog->SetTitle(_(
"OpenCPN Chart Add...."));
2078 ChartCollisionsHashMap collision_map;
2079 int nEntry = active_chartTable.GetCount();
2080 for (
int i = 0; i < nEntry; i++) {
2081 wxString table_file_name = active_chartTable[i].GetFullSystemPath();
2082 wxFileName table_file(table_file_name);
2083 collision_map[table_file.GetFullName()] = i;
2086 int nFileProgressQuantum = wxMax(nFile / 100, 2);
2087 double rFileProgressRatio = 100.0 / wxMax(nFile, 1);
2089 for (
int ifile = 0; ifile < nFile; ifile++) {
2090 wxFileName file(FileList[ifile]);
2091 wxString full_name = file.GetFullPath();
2092 wxString file_name = file.GetFullName();
2093 wxString utf8_path = full_name;
2101 wxFileName fnbase(dir_name_base);
2102 int nDirs = fnbase.GetDirCount();
2104 wxFileName file_target(FileList[ifile]);
2106 for (
int i = 0; i < nDirs + 1;
2108 file_target.RemoveDir(0);
2110 wxString leftover_path = file_target.GetFullPath();
2112 dir_name_base + leftover_path;
2118 if (!file_name.Matches(lowerFileSpec) && !file_name.Matches(filespec) &&
2119 !file_name.Matches(lowerFileSpecXZ) && !file_name.Matches(filespecXZ) &&
2125 if (pprog && ((ifile % nFileProgressQuantum) == 0))
2126 pprog->Update(
static_cast<int>(ifile * rFileProgressRatio), utf8_path);
2129 bool bAddFinal =
true;
2134 ChartCollisionsHashMap::const_iterator collision_ptr =
2135 collision_map.find(file_name);
2136 bool collision = (collision_ptr != collision_map.end());
2137 bool file_path_is_same =
false;
2138 bool file_time_is_same =
false;
2140 wxString table_file_name;
2143 if (b_found_cm93) collision =
false;
2146 pEntry = &active_chartTable[collision_ptr->second];
2147 table_file_name = pEntry->GetFullSystemPath();
2149 bthis_dir_in_dB && full_name.IsSameAs(table_file_name);
2153 if (file_path_is_same) {
2157 time_t t_oldFile = pEntry->GetFileTime();
2158 time_t t_newFile = file.GetModificationTime().GetTicks();
2160 if (t_newFile <= t_oldFile) {
2161 file_time_is_same =
true;
2163 pEntry->SetValid(
true);
2166 pEntry->SetValid(
false);
2171 wxString msg_fn(full_name);
2172 msg_fn.Replace(
"%",
"%%");
2173 if (file_time_is_same) {
2177 wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
2179 pnewChart = CreateChartTableEntry(full_name, utf8_path, chart_desc);
2182 wxLogMessage(wxString::Format(
2183 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2187 if (!collision || !pnewChart) {
2189 }
else if (file_path_is_same) {
2190 wxLogMessage(wxString::Format(
2191 " Replacing older chart file of same path: %s", msg_fn.c_str()));
2192 }
else if (!file_time_is_same) {
2198 if (pnewChart->IsEarlierThan(*pEntry)) {
2199 wxFileName table_file(table_file_name);
2201 if (table_file.IsFileReadable()) {
2202 pEntry->SetValid(
true);
2205 wxString::Format(
" Retaining newer chart file of same name: %s",
2208 }
else if (pnewChart->IsEqualTo(*pEntry)) {
2216 pEntry->SetValid(
false);
2218 wxLogMessage(wxString::Format(
2219 " Replacing older chart file of same name: %s", msg_fn.c_str()));
2224 if (0 == b_add_msg) {
2226 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2228 collision_map[file_name] = active_chartTable.GetCount();
2229 active_chartTable.Add(pnewChart);
2232 if (pnewChart)
delete pnewChart;
2238 m_nentries = active_chartTable.GetCount();
2243bool ChartDatabase::AddChart(wxString &chartfilename,
2245 wxGenericProgressDialog *pprog,
int isearch,
2246 bool bthis_dir_in_dB) {
2248 wxFileName file(chartfilename);
2249 wxString full_name = file.GetFullPath();
2250 wxString file_name = file.GetFullName();
2260 pprog->Update(wxMin((m_pdifile * 100) / m_pdnFile, 100), full_name);
2263 bool bAddFinal =
true;
2265 wxString msg_fn(full_name);
2266 msg_fn.Replace(
"%",
"%%");
2268 pnewChart = CreateChartTableEntry(full_name, full_name, chart_desc);
2271 wxLogMessage(wxString::Format(
2272 " CreateChartTableEntry() failed for file: %s", msg_fn.c_str()));
2277 int nEntry = active_chartTable.GetCount();
2278 for (
int i = 0; i < nEntry; i++) {
2279 wxString *ptable_file_name = active_chartTable[isearch].GetpsFullPath();
2283 if (bthis_dir_in_dB && full_name.IsSameAs(*ptable_file_name)) {
2287 time_t t_oldFile = active_chartTable[isearch].GetFileTime();
2288 time_t t_newFile = file.GetModificationTime().GetTicks();
2290 if (t_newFile <= t_oldFile) {
2292 active_chartTable[isearch].SetValid(
true);
2295 active_chartTable[isearch].SetValid(
false);
2297 wxString::Format(
" Replacing older chart file of same path: %s",
2307 wxFileName table_file(*ptable_file_name);
2309 if (table_file.GetFullName() == file_name) {
2312 if (pnewChart->IsEarlierThan(active_chartTable[isearch])) {
2314 if (table_file.IsFileReadable()) {
2315 active_chartTable[isearch].SetValid(
true);
2317 wxLogMessage(wxString::Format(
2318 " Retaining newer chart file of same name: %s",
2321 }
else if (pnewChart->IsEqualTo(active_chartTable[isearch])) {
2331 active_chartTable[isearch].SetValid(
false);
2334 wxString::Format(
" Replacing older chart file of same name: %s",
2344 if (nEntry == isearch) isearch = 0;
2349 if (0 == b_add_msg) {
2351 wxString::Format(
" Adding chart file: %s", msg_fn.c_str()));
2354 active_chartTable.Add(pnewChart);
2364 m_nentries = active_chartTable.GetCount();
2369bool ChartDatabase::AddSingleChart(wxString &ChartFullPath,
2370 bool b_force_full_search) {
2372 wxFileName fn(ChartFullPath);
2373 wxString ext = fn.GetExt();
2375 wxString ext_upper = ext.MakeUpper();
2376 wxString ext_lower = ext.MakeLower();
2377 wxString dir_name = fn.GetPath();
2383 for (
auto &cd : m_ChartClassDescriptorArray) {
2384 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2385 if (cd.m_search_mask == ext_upper) {
2389 if (cd.m_search_mask == ext_lower) {
2398 bool b_recurse =
true;
2399 if (!b_force_full_search) b_recurse = IsChartDirUsed(dir_name);
2401 bool rv = AddChart(ChartFullPath, desc, NULL, 0, b_recurse);
2405 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2406 if (!active_chartTable[i].GetbValid()) {
2407 active_chartTable.RemoveAt(i);
2413 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++)
2414 active_chartTable[i].SetEntryOffset(i);
2418 DetectDirChange(dir_name,
"",
"", new_magic, 0);
2421 bool bcfound =
false;
2422 ArrayOfCDI NewChartDirArray;
2424 ArrayOfCDI ChartDirArray = GetChartDirArray();
2425 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2431 if (newcdi.fullpath == dir_name) {
2432 newcdi.magic_number = new_magic;
2436 NewChartDirArray.Add(newcdi);
2441 cdi.fullpath = dir_name;
2442 cdi.magic_number = new_magic;
2443 NewChartDirArray.Add(cdi);
2447 SetChartDirArray(NewChartDirArray);
2450 m_chartDirs.Clear();
2452 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2454 m_chartDirs.Add(cdi.fullpath);
2457 m_nentries = active_chartTable.GetCount();
2462bool ChartDatabase::RemoveSingleChart(wxString &ChartFullPath) {
2466 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2467 if (ChartFullPath.IsSameAs(GetChartTableEntry(i).GetFullSystemPath())) {
2468 active_chartTable.RemoveAt(i);
2476 for (
unsigned int i = 0; i < active_chartTable.GetCount(); i++) {
2477 pcte = GetpChartTableEntry(i);
2478 pcte->SetEntryOffset(i);
2482 wxFileName fn(ChartFullPath);
2483 wxString fd = fn.GetPath();
2484 if (!IsChartDirUsed(fd)) {
2486 ArrayOfCDI NewChartDirArray;
2488 ArrayOfCDI ChartDirArray = GetChartDirArray();
2489 for (
unsigned int i = 0; i < ChartDirArray.GetCount(); i++) {
2494 if (newcdi.fullpath != fd) NewChartDirArray.Add(newcdi);
2497 SetChartDirArray(NewChartDirArray);
2501 m_chartDirs.Clear();
2502 for (
unsigned int i = 0; i < GetChartDirArray().GetCount(); i++) {
2504 m_chartDirs.Add(cdi.fullpath);
2507 m_nentries = active_chartTable.GetCount();
2516ChartBase *ChartDatabase::GetChart(
const wxChar *theFilePath,
2527 const wxString &filePath, wxString &utf8Path,
2529 wxString msg_fn(filePath);
2530 msg_fn.Replace(
"%",
"%%");
2531 wxLogMessage(wxString::Format(
"Loading chart data for %s", msg_fn.c_str()));
2533 ChartBase *pch = GetChart(filePath, chart_desc);
2536 wxString::Format(
" ...creation failed for %s", msg_fn.c_str()));
2540 InitReturn rc = pch->Init(filePath, HEADER_ONLY);
2541 if (rc != INIT_OK) {
2544 wxString::Format(
" ...initialization failed for %s", msg_fn.c_str()));
2549 ret_val->SetValid(
true);
2556bool ChartDatabase::GetCentroidOfLargestScaleChart(
double *clat,
double *clon,
2557 ChartFamilyEnum family) {
2559 int cur_max_scale = 0;
2561 int nEntry = active_chartTable.GetCount();
2563 for (
int i = 0; i < nEntry; i++) {
2564 if (GetChartFamily(active_chartTable[i].GetChartType()) == family) {
2565 if (active_chartTable[i].GetScale() > cur_max_scale) {
2566 cur_max_scale = active_chartTable[i].GetScale();
2572 if (cur_max_i == -1)
2575 *clat = (active_chartTable[cur_max_i].GetLatMax() +
2576 active_chartTable[cur_max_i].GetLatMin()) /
2578 *clon = (active_chartTable[cur_max_i].GetLonMin() +
2579 active_chartTable[cur_max_i].GetLonMax()) /
2588int ChartDatabase::GetDBChartProj(
int dbIndex) {
2589 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2590 return active_chartTable[dbIndex].GetChartProjectionType();
2592 return PROJECTION_UNKNOWN;
2598int ChartDatabase::GetDBChartFamily(
int dbIndex) {
2599 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2600 return active_chartTable[dbIndex].GetChartFamily();
2602 return CHART_FAMILY_UNKNOWN;
2608wxString ChartDatabase::GetDBChartFileName(
int dbIndex) {
2609 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2610 return wxString(active_chartTable[dbIndex].GetFullSystemPath());
2618int ChartDatabase::GetDBChartType(
int dbIndex) {
2619 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2620 return active_chartTable[dbIndex].GetChartType();
2628float ChartDatabase::GetDBChartSkew(
int dbIndex) {
2629 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2630 return active_chartTable[dbIndex].GetChartSkew();
2638int ChartDatabase::GetDBChartScale(
int dbIndex) {
2639 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size()))
2640 return active_chartTable[dbIndex].GetScale();
2648bool ChartDatabase::GetDBBoundingBox(
int dbIndex, LLBBox &box) {
2649 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2651 box.Set(entry.GetLatMin(), entry.GetLonMin(), entry.GetLatMax(),
2658const LLBBox &ChartDatabase::GetDBBoundingBox(
int dbIndex) {
2659 if ((bValid) && (dbIndex >= 0)) {
2661 return entry.GetBBox();
2663 return m_dummy_bbox;
2670int ChartDatabase::GetDBPlyPoint(
int dbIndex,
int plyindex,
float *lat,
2672 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2674 if (entry.GetnPlyEntries()) {
2675 float *fp = entry.GetpPlyTable();
2677 if (lat) *lat = *fp;
2679 if (lon) *lon = *fp;
2681 return entry.GetnPlyEntries();
2689int ChartDatabase::GetDBAuxPlyPoint(
int dbIndex,
int plyindex,
int ply,
2690 float *lat,
float *lon) {
2691 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2693 if (entry.GetnAuxPlyEntries()) {
2694 float *fp = entry.GetpAuxPlyTableEntry(ply);
2697 if (lat) *lat = *fp;
2699 if (lon) *lon = *fp;
2702 return entry.GetAuxCntTableEntry(ply);
2707int ChartDatabase::GetnAuxPlyEntries(
int dbIndex) {
2708 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2710 return entry.GetnAuxPlyEntries();
2718std::vector<float> ChartDatabase::GetReducedPlyPoints(
int dbIndex) {
2719 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2721 if (pentry)
return pentry->GetReducedPlyPoints();
2724 std::vector<float> dummy;
2731std::vector<float> ChartDatabase::GetReducedAuxPlyPoints(
int dbIndex,
2733 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2735 if (pentry)
return pentry->GetReducedAuxPlyPoints(iTable);
2738 std::vector<float> dummy;
2742bool ChartDatabase::IsChartAvailable(
int dbIndex) {
2743 if ((bValid) && (dbIndex >= 0) && (dbIndex < (
int)active_chartTable.size())) {
2747 if (pentry->GetChartType() != CHART_TYPE_PLUGIN)
return true;
2749 wxString *path = pentry->GetpsFullPath();
2750 wxFileName fn(*path);
2751 wxString ext = fn.GetExt();
2753 wxString ext_upper = ext.MakeUpper();
2754 wxString ext_lower = ext.MakeLower();
2759 for (
auto &cd : m_ChartClassDescriptorArray) {
2760 if (cd.m_descriptor_type == PLUGIN_DESCRIPTOR) {
2761 wxString search_mask = cd.m_search_mask;
2763 if (search_mask == ext_upper) {
2766 if (search_mask == ext_lower) {
2769 if (path->Matches(search_mask)) {
2779void ChartDatabase::ApplyGroupArray(ChartGroupArray *pGroupArray) {
2780 wxString separator(wxFileName::GetPathSeparator());
2782 for (
unsigned int ic = 0; ic < active_chartTable.GetCount(); ic++) {
2785 pcte->ClearGroupArray();
2787 wxString *chart_full_path = pcte->GetpsFullPath();
2789 for (
unsigned int igroup = 0; igroup < pGroupArray->GetCount(); igroup++) {
2790 ChartGroup *pGroup = pGroupArray->Item(igroup);
2791 for (
const auto &elem : pGroup->m_element_array) {
2792 wxString element_root = elem.m_element_name;
2798 if (!chart_full_path->IsSameAs(element_root))
2799 element_root.Append(
2801 if (chart_full_path->StartsWith(element_root)) {
2803 for (
unsigned int k = 0; k < elem.m_missing_name_array.size(); k++) {
2804 const wxString &missing_item = elem.m_missing_name_array[k];
2805 if (chart_full_path->StartsWith(missing_item)) {
2806 if (chart_full_path->IsSameAs(
2812 if (wxDir::Exists(missing_item))
2821 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.
A class for computing hash of arbitrary length.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents an entry in the chart table, containing information about a single chart.